Security scanners (Checkov, tfsec, Trivy) are deterministic and authoritative — and their output is a wall of finding IDs that teams learn to scroll past. The right division of labor: the scanner decides WHAT is wrong; AI explains WHY it matters in your context, ranks what to fix first, and drafts the fix PRs.
Tier: Foundation · Workflow area: Infrastructure as Code
Commercial tools now open fix PRs automatically; this playbook builds the same loop with OSS parts, keeping the trust boundary explicit — AI never decides whether something is a finding.
Skip AI for a repo with three findings — just fix them.
checkov -d . -o json or trivy config --format json .Run the scanner; export JSON. The scanner output is the source of truth for the entire workflow — AI adds no findings and removes none:
checkov -d infra/ -o json > findings.json
jq '.results.failed_checks | length' findings.json
Ask for contextual triage, not re-scanning.
Attached: Checkov findings JSON for our Terraform repo, plus a map of
which stacks are production.
For each distinct check ID:
1. Explain the actual risk in one paragraph — in terms of what an attacker
or an outage does with it, not compliance language.
2. Classify urgency: NOW (internet-exposed or prod data risk),
SPRINT (prod, not exposed), BACKLOG (sandbox/dev only).
3. Note which findings are likely false positives given the context
(e.g., intentionally public static-site bucket) — flag, do not dismiss.
Do not add findings the scanner did not report. Do not mark anything
resolved.
Verify the triage sample-wise. Spot-check: every NOW item — confirm the resource really is prod/exposed (the model only knows what you attached); every "likely false positive" — confirm against the actual code before anyone skips it.
Draft fixes in small, owner-aligned batches.
Draft the Terraform changes to fix these 6 CKV_AWS_16 findings (RDS
encryption) in modules/database. Constraints: use the existing kms_key_id
variable pattern from modules/storage; do not change instance sizes or
any attribute unrelated to the finding; note that enabling encryption on
an existing unencrypted RDS instance requires snapshot-restore — produce
the runbook steps for that, not just the HCL.
That last constraint is the difference between a useful fix PR and a landmine: some security fixes (RDS encryption, some S3 settings) force replacement of stateful resources. The AI must be made to surface migration impact, and you must read the plan.
Route each batch through the standard chain (validate → plan → policy → cost, pb-08). The plan gate is where "this fix replaces the production database" becomes visible. Policy gate confirms the finding count actually dropped.
Institutionalize skips. Where a finding is accepted risk, encode it as an inline skip with justification — AI drafts these too, humans approve:
#checkov:skip=CKV_AWS_18:Access logging handled centrally via org CloudTrail; ticket SEC-482
The scanner is the source of truth in both directions — AI may neither invent findings nor wave them away. "Likely false positive" is a flag for human review, never a dismissal.
terraform validate + TFLint.Findings JSON contains resource names, ARNs, account IDs. For client estates: run scanners inside the client boundary (all OSS), and either use the client's in-tenancy AI endpoint for triage, or strip identifiers (jq transform replacing resource addresses with stable hashes) before external triage and re-map locally. The explanation step needs check IDs and resource types, not real names — redaction costs little here.