Planning & Validation in CI
Review the diff, gate the danger
The plan is the review artifact: 'what will this change?' becomes a PR artifact instead of a leap. Validation (terraform validate, fmt, lint, checkov/tfsec) plus policy-as-code gates make apply a safe, human-verifiable step.
What you will learn
- Run fmt/validate/lint and integrate plan review into PRs
- Apply compose/comment plan bot patterns
- Add static security checks (checkov, tfsec, provider policies)
Automation produces a plan on each PR, posts it to the PR, then gates apply on approval. fmt/validate catch syntax; scan tools catch security/structure smells; policy-as-code (OPA/Sentinel/provider policies) enforces org invariants.
What is this?
Local hygiene: terraform fmt -recursive -check, terraform validate (in init'd dir), terraform console, .tflint, crossplane kubesec-esque. CI: init → validate → fmt check → plan (with -out and dir isolation) → comment plan via Terraform Cloud / Atlantis / GitHub Action plan-comment; apply gated in approvals. Providers' plan renderers (yellow/red diffs). Security scanning: checkov, tfsec (outdated), Trivy config scans, Snyk IaC, provider policies (AWS SCP) as backstop. Policy-as-code: OPA rego on plan files, Sentinel, Caspian Policies, Semgrep rules for HCL. Plan workspace / plan comment diff size guard.
Why do you need it?
- A reviewed plan is the single highest-leverage infra practice.
- fmt/validate catches 90% of 'what even is this' mistakes before review.
- Scanners find public-internet SG rules, plaintext secrets, missing encryption.
- Policy-as-code enforces org invariants no human review reliably checks.
Mental model
An architect submitting plans for a building permit, with an inspector on-site
Plan review + policy gates
The permit office (PR/CI) reads the plans (plan diff); the inspector (scanner/policy) also checks the materials against the code (security/standard) before the build (apply) proceeds.
How it works
- Push → CI init/integrate validate + fmt check → branch plan.
- A plan bot (Atlantis/Cloud) comments a formatted diff on the PR.
- Reviewers read ACTION/NOKEY lines; policy-as-code rules also evaluated at plan time.
- Approval triggers apply (rarely auto; used for greenlighted stacks).
- Wanttev: plan output stored, apply re-runs plan to confirm none drifted mid-flight.
Plan-gated apply.
Examples
CI plan stage (GitHub Action sketch)
- name: Terraform plan run: | terraform init -backend-config=env/${ENV}.backend terraform fmt -recursive -check terraform validate terraform plan -out=tfplan -var-file=env/${ENV}.tfvars- name: Security scan run: checkov -d . --download-external-modules false# apply job: requires review + holds until plan matchesInit→format→validate→plan→scan pipeline; apply is a separate, approved job that reuses the plan.
In production
- Atlantis/Terraform Cloud with plan PR comments across 50+ repos.
- Checkov enforces no world-open SG and encrypted S3 globally.
- Sentinel/OPA rule: prod plans must not exceed an env size delta or touch prod locks.
Best practices
- Make plan output an artifact of every PR — readable, config'd for your env's non-output respects.
- Gate applies with branch protection + required review; auto-apply only for ephemeral stacks.
- Run scanners at PR, not only weekly; block on high/medium config findings.
- Add policy-as-code where humans repeat the same 'this is bad' review comment.
- Re-run plan at apply time and ensure it matches the approved one.
Common mistakes
- Applying from memory without a plan (the 'prod turn' that eats itself).
- fmt/validate skipped; reviewers drown in whitespace diffs.
- Policy-as-code in a repo nobody reads → rules never enforced.
- Assuming scanners replace human review (they catch patterns, not intent).
Debugging tips
- Plan contains noise/resources not yours → module unpin or stale state branch; verify backend key.
- Policy rule flapping → read the rego and adapt the file/annotation rather than disabling.
- Plan bot posts nothing → init creds/privaterepo reach; check CI logs.
- fmt -check failing on CI but not locally → line endings/editor config; add a template rule.
Interview checkpoint
Quick quiz
Which step technically guarantees syntax correctness?
A policy-as-code rule evaluates: