Repository navigation
feat: terraform-plan-review standalone skill - #23
Open
Akshat0694 wants to merge 1 commit into
Open
Akshat0694 wants to merge 1 commit into
Akshat0694 wants to merge 1 commit into
Conversation
Reviews a Terraform or OpenTofu plan before apply: three bundled Tirith policies (no-deletes, no-replacements, no-stateful-deletes), a report template with replacements and deletes first, and no sensitive values. Synthetic plan fixtures with a CI job that checks each policy verdict, and manual evals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 2 of 4: the
terraform-plan-reviewstandalone skill. Stacked on #22: review and merge #22 first, then this PR's base changes tomain.What changes
standalone/terraform-plan-review/:SKILL.md: get the plan as JSON, asking before runningplan; run the bundled Tirith policies; groupresource_changes; write the report. It never applies and never prints sensitive values.assets/policies/: three Tirith policies,no-deletes,no-replacementsandno-stateful-deletes(23 data-holding types across AWS, Google Cloud and Azure, listed inreferences/plan-json.md).references/report-template.mdandreferences/plan-json.md.tests/fixtures/plans/: eight syntheticterraform show -jsondocuments with fake account IDs and names, plusgenerate.pyto rebuild them. Shapes follow a real Terraform 1.14 plan. The two beyond the plan's six:no-stateful-types.jsoncovers the stateful policy's "nothing to check" case, andreplace-create-first.jsoncovers the second replacement order.plan-review-policies: Python 3.11, Tirith pinned to 1.2.1.tests/policies/check_plan_review_policies.pyrunstirith lint, then every policy against every fixture, and asserts each exit code (24 cases). It also fails if a policy or fixture has no expectation. It runs outside the bun test runner, as the plan asks.tests/evals/terraform-plan-review.md: the manual eval rows.skills.sh.jsongrouping and README table row for the new skill.Things found in Tirith along the way (to report upstream)
The documented "detect a destroy" pattern never fires on a real plan.
reference/terraform-plan.md(synced from Tirith 1.2.1) uses"condition": {"type": "ContainedIn", "value": ["destroy"]}witheval_expression: "!check". That fails in two ways:delete, notdestroy.!, a singleno-oporcreateelsewhere in the plan hides the delete.I tested it against these fixtures: it passed
delete-bucket.json. The bundled policies useNotContainedIn ["delete"]without negation, which catches both deletes and replacements.-policy-pathtakes one file in Tirith 1.2.1. The syncedreference/verdicts.mdsays it takes "a file or a directory", but 1.2.1 opens the path as a file and prints onlyERRORfor a directory. The skill loops over the policy files.tirith lintdoes accept a directory.The synced
tirith-policiesskill pins its install line to@1.2.0. This skill pins@1.2.1.Verified installs (this branch)
npx skills add …/tree/terraform-plan-review/standalone --list: finds 2 skills (terraform-plan-review,tirith-policies).claude plugin install terraform --marketplace StackGuardian/stackguardian-mcp#terraform-plan-review: 2 skills, 0 MCP servers.Eval results
Claude Code, run with
claude -p. Each run used a fresh directory holding onlyplan.json, no MCP servers (--strict-mcp-config) and Tirith 1.2.1 on thePATH.terraformandtofuwere blocked; every attempted command was logged. "Without" ran with--disable-slash-commands, so no skill loaded. Prompt: "Review the Terraform plan in plan.json before I apply it."create-onlyupdate-in-placereplace-db: namesaws_db_instance.main, destroy first,storage_encrypteddelete-bucket: names both deleted addressessensitive: noFAKE-SENSITIVE-PASSWORD-…value printedno-stateful-typesreplace-create-firstmalformed: says the file is invalid and lists no changesThe plan's required passes with the skill all hold. Reading the transcripts:
no-replacements. The policy was correct, because Tirith sorts lists before comparing, but it now lists both orders explicitly so nobody misreads it.Checks
bun run fmt,build,typecheck: clean.bun run test: 23/23.node scripts/sync-tirith-skills.mjs --check: passes.python tests/policies/check_plan_review_policies.py: 24/24, lint clean.claude plugin validate . --strict: passes.bun run fallow -- --summary: unchanged from feat: standalone skills layout, Tirith sync, marketplace and catalog #22 (48). The new files are Python and JSON.🤖 Generated with Claude Code