fix(stacks): mark promote approval executed AFTER preflight, not before (#11)#242
Merged
mastermanas805 merged 2 commits intoJun 4, 2026
Conversation
…re (#11) The Promote handler called MarkPromoteApprovalExecuted inside consumeApprovedPromote BEFORE the promote preflight (source-services fetch, image_ref check, target create/update, vault copy, env load) ran. Any preflight failure (412 missing_image_ref / no_services, 503 lookup/create/ env_load, 400 vault, 402 cap) therefore burned the single-use approval to 'executed' while the promote never launched — stranding the operator with a consumed, non-retryable approval and forcing a fresh email round-trip. Split consumeApprovedPromote into: - validateApprovedPromote — read-only checks (uuid, lookup, ownership, status, from/to/kind match, expiry), runs at the original position so an invalid approval still 4xxs early. Returns the row, no mutation. - markApprovedPromoteExecuted — the 'executed' CAS flip + audit, called ONLY after preflight fully succeeds, immediately before the runStackDeploy launch. A preflight failure now leaves the approval 'approved' and retryable. The single-use guarantee is preserved: MarkPromoteApprovalExecuted's CAS still returns 0 rows (409 approval_already_executed) on a concurrent double-consume. Twin promote (consumeApprovedTwin in twin.go) has its own consume path and is out of scope for this fix. Coverage: Symptom: preflight 412/503 strands a consumed (status='executed') approval Enumeration: rg MarkPromoteApprovalExecuted + consumeApprovedPromote call sites in stack.go Sites found: 1 (stack.go Promote; twin.go has a separate consumeApprovedTwin) Sites touched: 1 Coverage test: TestStackPromote_ApprovalID_PreflightFails_StaysApproved (missing_image_ref), TestStackPromote_ApprovalID_NoServices_StaysApproved, TestStackPromote_ApprovalID_HappyPath_ExecutesOnce (executed once + single-use), TestMarkApprovedPromoteExecuted_AlreadyExecuted_409 (CAS-miss arm), TestStackFinal_ConsumeApproved_ExecuteError_503 (updated for new call order) Live verified: awaiting post-merge auto-deploy (rule 14 build-SHA gate in CI) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What
Closes sweep finding #11 (P2): a promote approval was burned to
status='executed'BEFORE the promote preflight ran. Any preflight failure stranded the single-use approval as consumed and non-retryable.PromotecalledMarkPromoteApprovalExecuted(insideconsumeApprovedPromote) immediately after validating theapproval_id— but BEFORE the preflight (source-services fetch,image_refcheck, target create/update, vault copy, env load). A preflight failure (412missing_image_ref/no_services, 503lookup/create/env_load, 400vault, 402 cap) therefore consumed the approval while the promote never launched, forcing the operator to request a fresh email approval.Fix
Split
consumeApprovedPromoteinto two halves:validateApprovedPromote— read-only checks (uuid, lookup, ownership, status,from/to/kindmatch, expiry). Runs at the original position so an invalid approval still4xxs early. Returns the row; no mutation.markApprovedPromoteExecuted— theexecutedCAS flip + audit. Called ONLY after preflight fully succeeds, immediately before therunStackDeploylaunch.A preflight failure now leaves the approval
approvedand retryable. Single-use is preserved:MarkPromoteApprovalExecuted's CAS still returns 0 rows →409 approval_already_executedon a concurrent double-consume.twin.go'sconsumeApprovedTwinis a separate consume path and out of scope for this fix.Coverage block
100% patch coverage (both split functions + the new call sites).
go vetclean;gofmtclean.🤖 Generated with Claude Code