fix: apply the verified managed plan snapshot - #6849
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
It changes core apply-time integrity checks and planfile execution behavior, so it warrants careful human validation of error handling and operational edge cases.
Pull request overview
This PR hardens Atlantis’s built-in Terraform apply execution by requiring an ExpectedPlanHash and ensuring apply consumes an immutable, verified snapshot of the plan bytes (instead of reading from a mutable plan file path during execution), including for remote apply flows.
Changes:
- Enforce
ExpectedPlanHashpresence and verify SHA-256 of the loaded plan bytes before any apply execution. - For local apply, write the verified bytes to a read-only temp snapshot (
0400) and pass that snapshot path to Terraform; for remote apply, reuse the verified bytes without re-reading the plan file. - Update/apply tests to set
ExpectedPlanHashand assert the snapshot behavior, permissions, integrity, and cleanup.
File summaries
| File | Description |
|---|---|
| server/core/runtime/apply_step_runner.go | Adds plan-hash enforcement and validated snapshot creation; updates remote apply to use verified bytes. |
| server/core/runtime/apply_step_runner_test.go | Extends unit coverage to require hashes and validate snapshot integrity/cleanup and file permissions. |
Review details
Suppressed comments (1)
server/core/runtime/apply_step_runner.go:64
- The new plan-hash mismatch error message is generic; including dir/workspace/project makes it easier to identify which project in a multi-project apply needs a re-plan.
digest := sha256.Sum256(contents)
if hex.EncodeToString(digest[:]) != ctx.ExpectedPlanHash {
return "", fmt.Errorf("plan file changed; run `atlantis plan` before apply")
}
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if ctx.ExpectedPlanHash == "" { | ||
| return "", fmt.Errorf("expected plan hash is missing; run `atlantis plan` before apply") | ||
| } |
| // Keep execution copies outside the checkout so custom steps still see the | ||
| // convention PLANFILE. A private directory also prevents accidental discovery | ||
| // by repository globs. Terraform consumes only these verified bytes. |
Code Coverage OverviewLanguages: Go Go / code-coverage/goThe overall line coverage in commit 88412e0 in the Show a line coverage summary of the most covered files.
Updated |
Bind built-in apply execution and remote plan comparison to the exact bytes checked against ExpectedPlanHash. Preserve custom workflow PLANFILE behavior and successful apply cleanup. Assisted-by: OpenAI GPT-6 <noreply@openai.com> Signed-off-by: Rui Chen <rui@chenrui.dev>
Clarify that operators can override the system temporary directory. Assisted-by: OpenAI GPT-6 <noreply@openai.com> Signed-off-by: Rui Chen <rui@chenrui.dev>
70794ca to
88412e0
Compare
Summary
Make built-in apply consume a read-only
.tfplansnapshot of the exact bytes verified againstExpectedPlanHash. Missing or mismatched hashes fail before Terraform starts. Remote apply compares against the same verified bytes without rereading the mutable source.Notes
Independent snapshot slice from #6657, based on main including #6781. No plan generations, publication claims, S3 key changes, or custom-run
PLANFILEredirection. Successful apply still removes the convention plan through PlanStore.The snapshot lives in a private system temporary directory and is removed when apply returns. Operators can override the temporary-directory location through TMPDIR. Process crashes may leave temporary copies for the host's temporary-file cleanup. The binding applies to built-in apply consumption; custom scripts retain their existing behavior and are not advertised as cryptographically bound.
Tests cover missing hashes, mutations before/after snapshot creation, permissions, cleanup, and existing direct-context/custom-workflow regressions. Local lint reports three unchanged findings (two modernize suggestions and one deprecated GitLab test field); hosted checks are still required.