Skip to content

QA plan: Infracost PR comment (#32)

Story: Infracost PR comment — per-env breakdown (#32)
Capability: Cost guardrails and observability (#31)

TypeCoverage
Pipeline behaviorInfracost CI step runs on every PR that touches *.tf files (or unconditionally) and posts a cost-diff comment
Pipeline behaviorCost breakdown shows QA and Prod as separate line items
Pipeline behaviorThe comment steps do not block merge, and a missing or failed comment does not fail the PR
AccuracyAdding a new AWS resource in a PR shows a non-zero delta in the Infracost comment
Regression guardA step in the Terraform PR job asserts each environment’s monthly total against a $5 ceiling and fails the PR when a total exceeds it. The ceiling bounds fixed-price provisioned resources, not the bill: Infracost prices the Terraform plan, so Bedrock appears in no plan at all, and Aurora Serverless v2 prices to zero because ACU consumption is usage-based. What the ceiling guards against is adding fixed-price infrastructure, a NAT Gateway or a PrivateLink endpoint being the cases that matter here
  • Infracost installed in CI (Story #29 pipeline)
  • infracost.yml configuration file exists with per-env workspace paths
  • CI step runs on a test PR with a Terraform change and posts a comment containing a cost breakdown
  • Comment shows QA and Prod line items separately
  • Infracost comment updated (not duplicated) on subsequent pushes to the same PR
  • The Terraform PR job asserts each environment’s monthly total against the $5 ceiling and fails the PR when a total exceeds it
  • A Terraform change that adds a fixed-price resource above the ceiling (a NAT Gateway, a PrivateLink endpoint) makes that assertion fail; reverting it makes the assertion pass
  • A failed or missing cost comment does not fail the PR; the ceiling assertion is the only step that does
  • No Infracost job runs in the deploy workflow

CI only. Infracost uses Terraform plan JSON; no live AWS resource calls.

Infracost CLI, GitHub Actions.

The comment half is observational: a PR with a known Terraform change (adding a CloudWatch alarm, say) is pushed to CI, and the reviewer confirms the Infracost comment appears and the delta is non-zero.

Terminal window
# Given a PR adding a new CloudWatch alarm resource
# When Infracost runs in CI
infracost diff --path infra/roots/qa --format json | python3 -c "
import sys, json; r=json.load(sys.stdin)
delta=float(r['projects'][0]['diff']['totalMonthlyCost'])
assert delta != 0, 'Expected non-zero cost delta for new alarm'
print(f'Cost delta: ${delta:.4f}/mo')
"
# Then the delta is non-zero and printed to the CI log

The ceiling half is checked by hand this way, and the PR job makes the same comparison, failing the PR when a total exceeds the ceiling:

Terminal window
# When the monthly total is priced per environment
infracost breakdown --config-file infracost.yml --format json \
| jq -r '.projects[] | "\(.name): \(.breakdown.totalMonthlyCost)"'
# Then each total is at or below the $5 ceiling
  • Infracost API key must be stored as a GitHub Actions secret; if the key expires or is absent, the step fails silently. Add an explicit check for the env var before the Infracost invocation.
  • Infracost prices only the fixed-price subset of this stack. Aurora Serverless v2 is usage-based and prices to zero, so most of what the environment costs is invisible to the tool. Document the limitation in the Infracost configuration comment, and read the ceiling as a bound on provisioned infrastructure rather than on spend. This is also why the accuracy criterion is a one-sided ceiling: a two-sided band would assert a bill figure the tool never produces.
  • The comment steps are best-effort so an Infracost outage cannot block a merge, but the ceiling step is not, so an outage that takes down the assertion fails the PR. That is the intended trade: a check that cannot fail is not a gate. Distinguish the two failure modes in the step’s output so a tool outage is not mistaken for a cost regression.
  • A ceiling set too far above the stack’s fixed-price total never fires. $5 sits clear of that total while falling below the cheapest thing worth catching, a PrivateLink endpoint at roughly $7.30 per AZ per month. Re-derive it from an infracost breakdown run against main whenever the stack gains a fixed-price component.
  • Two PRs that each price under the ceiling can merge to a main that does not, since each is priced against its own base. Requiring branches to be up to date before merge closes this; a post-merge cost job does not, because failing it reports a regression already on main.

Cost guardrails: PRs that increase AWS spend are visible before merge. This plan’s exit criteria cover visibility (comment posted) and the ceiling assertion, both pre-merge. Under RAG016 the comment stays informational and a cost-delta budget gate stays rejected; the ceiling is a conformance check on fixed-price provisioned resources, and it does block the merge.