Use JSON plan output for deterministic plan hashing#429
Open
toast-gear wants to merge 1 commit into
Open
Conversation
Fixes dflook#196. Plan comparison was hashing the human-readable text output of terraform plan, which is non-deterministic across runs even when the actual intended changes are identical. This caused spurious "plan changed" failures during apply. Switch to hashing the JSON plan output (terraform show -json) instead, which is stable for the same set of changes. The only excluded field is `timestamp`, which is regenerated on every plan run and carries no information about what will change. Backward compatibility is preserved: PR comments created before this change carry a `plan_hash` (text-based) but no `plan_json_hash`. The approval logic falls back through plan_json_hash → plan_hash → text comparison, so existing in-flight PRs continue to work without requiring a re-plan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
Author
|
This is entirely AI made FYI, I was just curious at how good it is at this sort of thing so decided to see if it could fix and issue I raised many many years ago when I was using this action |
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.
Fixes #196.
What changed
Switch plan comparison hashing from the human-readable
terraform plantext output to the machine-readableterraform show -jsonoutput.image/src/github_pr_comment/hash.pyplan_json_hash(json_plan_path, salt): reads the full JSON plan, removes only thetimestampfield (the single volatile field that changes on every run but carries no information about what will change), canonicalises withcanonicaljsonfor key-order determinism, and hashes.plan_hash()(text-based) is retained unchanged as a backward-compatibility fallback.image/src/github_pr_comment/comment.pyplan_json_hashPR comment header field alongside the existingplan_hash.image/src/github_pr_comment/__main__.py_json_plan_path(): constructs the path toplan.jsonfrom theGITHUB_WORKSPACEandWORKSPACE_TMP_DIRenv vars already exported byactions.sh, returningNoneif the file doesn't exist.plan_json_hashwhenplan.jsonis available, and always writes the legacyplan_hashalongside it so older versions of the apply action can still verify.is_approved()prefersplan_json_hash→ falls back toplan_hash→ falls back to direct text comparison.Why
Terraform's text output is non-deterministic across runs even when the planned changes are identical. Cosmetic differences (ordering, whitespace, provider-injected warnings) were causing spurious "plan changed" failures at apply time and blocking deployments. The JSON output is stable for the same intended changes.
Backward compatibility
Fully preserved. PR comments created before this change carry
plan_hashbut noplan_json_hash. The three-level fallback inis_approved()handles them transparently — no re-plan required for in-flight PRs.When JSON is unavailable
JSON plan output is not produced when using remote/cloud backends that do not support saving plan files (
PLAN_OUT=""). In that case_json_plan_path()returnsNone,plan_json_hashis not stored, and the existing text-based path is used unchanged.