72 / 75 · 08 Infrastructure as Code Testing · AI Agents Reviewing Infrastructure Code← prev⊞ allnext →☰ Read as one page
13.4Integrating AI Review into CI
GitHub Actions Workflow
# .github/workflows/iac-review.yml
name: AI Infrastructure Review
on:
pull_request:
paths:
- 'terraform/**'
- 'k8s/**'
- 'Dockerfile*'
jobs:
ai-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate Terraform plan
run: |
cd terraform/
terraform init
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
- name: Static analysis
run: |
checkov -d ./terraform/ -o json > checkov-results.json
trivy config ./terraform/ --format json > trivy-results.json
- name: AI review of changes
run: |
# Combine plan + static analysis for AI review
python scripts/ai_iac_review.py \
--plan terraform/tfplan.json \
--checkov checkov-results.json \
--trivy trivy-results.json \
--output review-comment.md
- name: Post review to PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('review-comment.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
The AI Review Script
# scripts/ai_iac_review.py
import json
import argparse
import os
from anthropic import Anthropic
def load_json(path):
with open(path) as f:
return json.load(f)
def build_review_prompt(plan, checkov_results, trivy_results):
"""Build a structured prompt for AI review."""
# Summarize the plan
changes = plan.get("resource_changes", [])
creates = [c["address"] for c in changes if "create" in c["change"]["actions"]]
updates = [c["address"] for c in changes if "update" in c["change"]["actions"]]
destroys = [c["address"] for c in changes if "delete" in c["change"]["actions"]]
# Summarize static analysis findings
checkov_failures = [
r for r in checkov_results.get("results", {}).get("failed_checks", [])
]
trivy_findings = trivy_results.get("Results", [])
prompt = f"""Review this Terraform infrastructure change:
## Plan Summary
- Resources to create: {len(creates)} ({', '.join(creates[:10])})
- Resources to update: {len(updates)} ({', '.join(updates[:10])})
- Resources to destroy: {len(destroys)} ({', '.join(destroys[:10])})
## Full Plan
```json
{json.dumps(plan, indent=2)[:10000]}
Checkov Findings ({len(checkov_failures)} failures)
{json.dumps(checkov_failures[:20], indent=2)}
Trivy Findings
{json.dumps(trivy_findings[:20], indent=2)}
Provide a structured review with severity ratings."""
return prompt
def main(): parser = argparse.ArgumentParser() parser.add_argument("--plan", required=True) parser.add_argument("--checkov", required=True) parser.add_argument("--trivy", required=True) parser.add_argument("--output", required=True) args = parser.parse_args()
plan = load_json(args.plan)
checkov = load_json(args.checkov)
trivy = load_json(args.trivy)
prompt = build_review_prompt(plan, checkov, trivy)
client = Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
system="You are a senior infrastructure security engineer. Review the Terraform plan and static analysis results. Provide actionable findings with severity ratings.",
)
review = response.content[0].text
with open(args.output, "w") as f:
f.write("## AI Infrastructure Review\n\n")
f.write(review)
f.write("\n\n---\n*Generated by AI review pipeline*")
if name == "main": main() ```