fix(gcp): reject destroy trust tuples off protected dev/main - #2376
Merged
Merged
Conversation
gcp-dev-destroy.yml rejects every dispatch ref except refs/heads/dev and refs/heads/main before auth, but the cicd-oidc input contract accepted a destroy purpose tuple on any branch. A tenant bootstrapped with its destroy tuple on the tenant branch could never be torn down. Validate destroy tuples in both the cicd-oidc root and the identity module, and in gcp_foundation bootstrap before any command runs. A test pins the workflow guard, both Terraform validations, and the example inputs to one Python constant so they cannot drift. Correct the bootstrap README, which said destroy uses the tenant branch.
|
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.



Problem
On 2026-09-23, dispatching
gcp-dev-destroy.ymlfromdevwithenvironment=balrogfailed with:Branch "dev" is not allowed to deploy to balrog-destroy due to environment protection rules.The workflow's pre-auth guard
Reject non-protected dispatch refsallows onlyrefs/heads/dev|refs/heads/main. That guard is a security control and this PR does not change it. The balrog foundation (cicd-oidc) was applied with its destroy purpose tuple bound torefs/heads/balrog, andbalrog-destroyallowed only branchbalrog. No dispatch could satisfy both the guard and that binding. The foundation input contract accepted the tuple anyway.scripts/bootstrap/README.mdalso said "Deploy and destroy use the selected tenant branch", which contradicts the guard.Fix
platform/terraform/gcp/global/cicd-oidc/inventory.tfandmodules/cicd-oidc-identity/inventory.tf: newpurpose_contextsvalidation. Everydestroytuple must haverefinrefs/heads/dev/refs/heads/main, and itsworkflow_refmust end with@<ref>.scripts/bootstrap/gcp_foundation.py: adds aDESTROY_PROTECTED_REFSconstant and checks it right after the required-keys check, before anygcloud/gh/terraformcall. Without this check, API enablement and state-bucket creation would run before Terraform variable validation.test_destroy_refs_match_workflow_guard_and_terraform_contractchecks the workflow guard'scasepattern, both Terraform validations, and the example inputs againstDESTROY_PROTECTED_REFS.<environment>-destroyEnvironment branch policy must allow that ref.docs/dev/deploy-secrets.mdalready said this; it now also says bootstrap rejects other refs.Tests
terraform testinplatform/terraform/gcp/global/cicd-oidc(mock provider): 7 passed. New runs: destroy onrefs/heads/devwith a tenant-branch deploy is accepted; destroy on the tenant branch is rejected.pytest scripts/bootstrap/tests: all passed. New cases: dev and main are accepted; a tenant-branch ref and a mismatchedworkflow_refare rejected before any command runs; plus the drift test.pytest scripts/check_tf_gcp_wif_trust: 29 passed. Thecheck_tf_gcp_wif_trusthook is clean.pytest shifter/packer/tests/test_packer_gcp.py -k destroy: 2 passed.Operator follow-up (not in this PR)
The live balrog foundation still has the
refs/heads/balrogdestroy tuple, andbalrog-destroystill allows onlybalrog. Fixing it takes a re-apply of the balrogcicd-oidcroot with arefs/heads/devdestroy tuple, plus a change to thebalrog-destroyEnvironment branch policy to allowdev. Re-applying with the current inputs will now fail validation until the tuple is corrected.