Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

Terraform PR Gates — GitHub Actions

A production-grade Continuous Integration (CI) pull-request quality gate for Terraform monorepos. Every PR must pass 6 blocking gates before merge, and the results are posted back to the PR as a single sticky comment (updated in place, never spammed):

PR comment posted by the pipeline: 6/6 gates green with per-module test breakdown.

The gates

Gate Tool What it blocks
🎨 Format terraform fmt -check unformatted code
🧱 Validate terraform init -backend=false + validate per workspace broken config, schema errors
🧪 Unit tests terraform test per module (mock providers, offline) behavioural regressions
🔍 Lint TFLint (curated root .tflint.hcl) provider misuse, dead code
🛡️ Security Checkov (curated .checkov.yaml) insecure resources
🔑 Secret scanning Gitleaks (separate workflow) leaked credentials

Design decisions

  • No cloud credentials. Everything runs offline (-backend=false, mock_provider in tests) — a malicious PR can't exfiltrate secrets that aren't there. GITHUB_TOKEN is read-only except for the comment step.
  • Minutes-frugal, but never blind. The Terraform gates are path-filtered; Gitleaks deliberately is not — a secret can land in any file, so it runs on every PR and every push to main as its own workflow.
  • One sticky comment. The report finds its previous comment by a hidden marker and PATCHes it, so the PR timeline stays clean. Fork PRs (read-only token) skip the comment instead of failing.
  • Reproducible runs. Terraform version from .terraform-version, TFLint and Checkov pinned, provider plugins cached by .terraform.lock.hcl hash.
  • Failure-friendly reporting. Per-module test counts survive a red job (single-line output), and init failures surface with logs instead of masquerading as test failures.

Using it in your repo

Copy .github/workflows/ into a Terraform repo laid out as:

modules/<name>/tests/*.tftest.hcl   # unit tests (mock providers)
environments/<env>/                 # deployable workspaces
.terraform-version  .tflint.hcl  .checkov.yaml

Open a PR that touches any .tf file — the gates run, and the bot comment above appears on the PR.

Plan & apply — Atlantis + Infracost

These gates are deliberately credential-free: they prove the code is correct without ever talking to a cloud account. The stateful half of the pipeline — terraform plan and apply — runs in a separate lane on Atlantis, with Infracost attached:

  1. The same PR triggers atlantis plan — a real plan against real state, posted to the PR, with per-workspace state locking so two PRs can't race the same environment.
  2. Infracost posts a cost diff alongside it — a price tag on every PR before anyone approves ("this change adds ~$140/month").
  3. Only after the gates above are green and the plan is reviewed does a maintainer comment atlantis apply — apply happens from the PR, before merge, so what lands on main is exactly what was applied.

Cloud credentials live only in the Atlantis runner (Workload Identity — no long-lived keys in GitHub), which is why this repo's gates can stay read-only.

About

Continuous Integration (CI): Blocking PR quality gates for Terraform — fmt, validate, terraform test (offline mock providers), TFLint, Checkov, Gitleaks — with a sticky results comment on every PR

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors