Cursor AI Guardrails Checklist for Terraform and Ansible Repos

devops-linux

Why this checklist

Cursor AI infrastructure code review illustration

Last month, one Cursor autocomplete suggestion added Action = "*" to a production IAM policy during a “simplify this” refactor request. Nobody typed that wildcard on purpose — the model just decided it was a cleaner way to express the policy, and it slipped past a tired reviewer who was skimming a 200-line diff at 6pm. That’s the moment we started treating Cursor AI infrastructure code review as its own discipline, not an afterthought bolted onto normal PR review.

App code has a natural blast radius limiter: bad logic fails a test, throws a 500, gets caught in staging. Infra-as-code doesn’t have that luxury. A hallucinated resource attribute in Terraform can delete a production subnet on apply, not just fail a unit test. Ansible playbooks with inconsistent privilege escalation can half-execute against real hosts. Kubernetes manifests with no resource limits can starve a shared cluster silently for weeks before anyone notices the node pressure alerts.

Cursor’s autocomplete and Composer/Agent mode pull context from open files, .cursorrules (or the newer .cursor/rules/*.mdc format), and whatever it’s indexed across your repo. If that context includes a terraform.tfstate file or a .tfvars with real secrets, the model sees them — and depending on your plan, that context may leave your network and hit a third-party API. This isn’t an “AI is bad” post. It’s the opposite: I think Cursor is genuinely useful for infra work. But it needs the same review discipline you’d apply to a junior engineer who was just handed root access and a keyboard. The checklist below is what we now run before merging any AI-assisted change to Terraform, Ansible, or Kubernetes manifests.

The checklist

This is the actual list we paste into our infra repo README. It’s grouped by when you run it — repo setup, per-PR review, and process — because different people own different stages.

Repo setup (do this once, before anyone opens Cursor Agent mode):

  1. Add .cursor/rules/infra.mdc — Cursor 0.45+ replaced the single .cursorrules file with a rules directory. If your repo is still on the old format, the new syntax is silently ignored, which means your “rules” are doing nothing while you think they’re enforced.
  2. Define provider version discipline in the rules file — explicitly forbid the model from touching required_providers without a human ask.
  3. Ban wildcard IAM actions in the rules — spell out “no Action = "*" or Resource = "*"” so the model has an explicit constraint, not just good intentions.
  4. Add a .cursorignore excluding state and secrets*.tfstate, *.tfvars, secrets/**, kubeconfig*, *.pem, *.key.
  5. Pin naming conventions in the rules file — e.g. <env>-<service>-<resource> — so AI-generated resources match existing module patterns instead of inventing new ones.
  6. Run tflint --init once per repo — it pulls the AWS ruleset plugin. Skip this and tflint runs with zero warnings every time, giving false confidence that everything’s clean.

Per-PR review (every AI-assisted infra change, no exceptions):

  1. Run terraform plan -out=tfplan and inspect the plan file directly — never accept the AI’s prose summary of “what this will do” as the source of truth.
  2. Diff the plan against the AI’s stated intent. If the request was “add tags,” the plan should not show new IAM resources or provider version bumps.
  3. Grep the diff for new wildcard actions or resources with "*" anywhere in a policy statement.
  4. Check whether provider constraints changed. Agent mode has a habit of “helpfully” bumping hashicorp/aws from ~> 5.0 to 6.x mid-refactor, which breaks for_each syntax on resources like aws_instance.
  5. Confirm checkov and tflint both pass in CI, not just locally.
  6. Manually review any count or for_each expression the AI touched — this is the single most common hallucination spot in AI-generated Terraform.

Process (org-level policy, enforced regardless of who’s reviewing):

  1. Tag AI-assisted commits (Co-authored-by: Cursor or a trailer like AI-assisted: cursor-0.47, claude-3.5-sonnet).
  2. Never allow Agent mode’s “run in terminal” feature to auto-execute terraform apply or kubectl apply. It’s opt-in, but it’s easy to enable accidentally and forget it’s on.
  3. Gate every apply behind a human approval step in CI, separate from the code review approval.
  4. Log which model and Cursor version generated each change in a CHANGELOG-ai.md or commit trailer, so audit and rollback triage aren’t guesswork later.

Here’s the rules file and pre-commit config we actually run. The .mdc format uses YAML frontmatter plus markdown, and it’s scoped by glob so it only applies to infra file types:


# .cursor/rules/infra.mdc
# Cursor rules file for infrastructure repos (Cursor 0.45+)
# Place at .cursor/rules/infra.mdc — replaces legacy .cursorrules

---
description: Rules for Terraform/Ansible/K8s changes in this repo
globs: ["**/*.tf", "**/*.yaml", "**/*.yml"]
alwaysApply: true
---

# Provider & version discipline
- Never change `required_providers` version constraints without explicit human request.
- Do not add or modify `lifecycle { prevent_destroy }` blocks silently.
- Flag any `count` or `for_each` expression that could evaluate to zero-length list.

# Security
- Never suggest hardcoding secrets, API keys, or ARNs with wildcard "*" actions.
- If a `.tfvars` or `secrets/` file is opened, do not read or summarize its contents.

# Style
- Follow existing module naming: `<env>-<service>-<resource>` (e.g. `prod-billing-vpc`).
- Prefer `for_each` over `count` for resources keyed by name, not index.

---
# .cursorignore
# Prevent indexing of sensitive/large state artifacts
*.tfstate
*.tfstate.backup
*.tfvars
secrets/**
.terraform/**
kubeconfig*
*.pem
*.key

---
# .pre-commit-config.yaml (partial)
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.96.1
    hooks:
      - id: terraform_fmt
      - id: terraform_tflint
      - id: terraform_checkov
        args:
          - --args=--quiet
          - --args=--compact

Commonly missed items

The checklist above looks straightforward on paper, but in practice a few items get skipped constantly — usually because they’re invisible until something already broke.

First, people assume Cursor only indexes tracked source files. It doesn’t. By default it indexes the entire repo tree, including .git/ history and stray .tfstate.backup files that got committed years ago and never cleaned up. Those get fed silently into context. If you’ve ever run git filter-branch or BFG to strip a leaked secret from history, you need to manually rebuild the index afterward (Cmd+Shift+P → "Cursor: Rebuild Index") — otherwise stale embeddings can still surface the old secret value in a completion months later.

Second — and this one trips up almost every new team — .cursorignore does not behave like .gitignore for the model’s memory. It blocks indexing for autocomplete and chat context going forward, but it doesn’t retroactively purge cached embeddings from a prior index, and it doesn’t stop the AI from reading a file that’s simply open in your editor tab. An open terraform.tfstate tab is still fully readable by Agent mode, ignore file or not.

Third, nobody tracks token cost until the bill shows up. Large mono-infra-repos with 50+ Terraform modules can push a single Composer session past 100k tokens on indexing alone. On Cursor Pro ($20/user/mo), large-file indexing throttles on repos over roughly 50k files; Business ($40/user/mo) raises the ceiling but doesn’t remove the cost if you’ve got a BYO Anthropic or OpenAI key configured.

Finally — and this is the one I’ve personally been burned by — reviewers eyeball a diff and skip checking whether the AI quietly removed a lifecycle { prevent_destroy } block while “cleaning up formatting.” It reads as whitespace noise until the next apply destroys something you meant to protect.

Automation ideas

A checklist that lives only in reviewers’ heads decays fast. Bake as much of it into CI as you can, so the enforcement doesn’t depend on who’s on call that week.

Start with a pre-commit hook that runs security scanning before any AI-assisted commit lands. We pin checkov>=3.2.0 — older 2.x releases miss several IAM policy checks that matter specifically for the wildcard-action problem described above. Here’s the diff pattern that pre-commit and CI should catch automatically, taken from an actual “simplify this policy” request that went sideways:


  # Before AI edit
  resource "aws_iam_policy" "deploy" {
    name   = "prod-deploy-policy"
    policy = jsonencode({
      Statement = [{
        Effect   = "Allow"
        Action   = ["s3:GetObject", "s3:PutObject"]
        Resource = "arn:aws:s3:::prod-artifacts/*"
      }]
    })
  }

  # After Cursor Agent "simplify this policy" request — WRONG, caught in review
+ resource "aws_iam_policy" "deploy" {
+   name   = "prod-deploy-policy"
+   policy = jsonencode({
+     Statement = [{
+       Effect   = "Allow"
+       Action   = "*"                 # <-- hallucinated wildcard, silently added
+       Resource = "*"                 # <-- checkov CKV_AWS_1 would flag this
+     }]
+   })
+ }

# checkov output that should block the merge:
# Check: CKV_AWS_1: "Ensure IAM policies do not allow full administrative privileges"
# FAILED for resource: aws_iam_policy.deploy
# File: /iam.tf:1-9

Next, add a GitHub Action that fails any PR touching iam.tf or network.tf unless a human — not a bot account — has left an approving review. Combine CODEOWNERS with branch protection rules requiring that named team’s sign-off specifically for those paths. Finally, a small script grepping commit messages for the AI-assisted: trailer and cross-referencing it against a required checkbox in your PR template (“I ran the Cursor AI infrastructure code review checklist”) closes the loop — it won’t stop a determined reviewer from lying, but it stops the checklist from being forgotten by accident, which is the far more common failure mode.

Read the Terraform docs on plan/apply workflows if you’re building the CI gate from scratch, and check our Terraform automation posts for related pipeline patterns we’ve written up separately. None of this replaces judgment — it just makes sure judgment gets applied every single time, not just when someone remembers to be careful.

Related

Leave a Reply

Your email address will not be published. Required fields are marked *

Support us · 💳 Monobank