decommission: resolve the workspace Terraform version and fail clearly without a token - #73
Merged
Merged
Conversation
…y without a token The workflow could not run at all. Two independent defects, both in the path before any state is touched. The discover job declares no environment, so it cannot read an environment-scoped secret - which is where the installation guide puts the HCP token. The caller reference resolves to empty and terraform init fails with a bare authentication error pointing nowhere near the cause. The workflow already carried this reasoning for WORKSPACE; it was not carried across to the token. Both jobs also installed the latest Terraform. Plan and apply are unaffected because they execute remotely, but state rm runs locally against remote state and is refused unless the CLI satisfies the workspace constraint. That made the workflow time-dependent: it worked when written and broke on its own once a newer Terraform shipped, with no change in either repository. A single composite action covers both. It refuses to continue without a token, naming the repository-level requirement, then reads the version the workspace requires and hands it to setup-terraform. It never falls back to the latest release, since installing a version the workspace rejects is the failure it exists to prevent. A workspace may report an exact version or a pessimistic constraint. Exact versions pass through, ~>X.Y.Z becomes the <X.(Y+1).0 form setup-terraform understands, and anything else fails loudly rather than being guessed at. docs/workflows.md gains the Decommission section it never had. The setup requirements are load-bearing here, and it settles the operating order: the config must still be present when the workflow runs, and is deleted afterwards.
Terraform constraints are conventionally written with a space, as in "~> 1.14.0". The patterns required the digit immediately after the operator, so a workspace using the usual spelling was rejected as untranslatable rather than resolved. Stripping spaces before matching also means the remaining operator shapes only need a case arm to support, not a second spelling each.
dev-milos
marked this pull request as ready for review
August 14, 2026 09:19
mladjan-gadzic
approved these changes
Aug 14, 2026
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.
Closes G-Research/gr-oss#1436
Closes G-Research/gr-oss#1437
The
decommissionworkflow could not run at all. Two independent defects, both in the pathbefore any state is touched, and the feature is unusable until both land — hence one pull
request.
The token
discoverdeclares noenvironment:, so it cannot read an environment-scoped secret, whichis where the installation guide puts the HCP token. The caller's
secrets.TFC_TOKENis alsoevaluated outside any environment, so it resolves to an empty string and
terraform initfails with:
— which points nowhere near the cause.
The workflow already carried exactly this reasoning for a different input:
The same constraint applies to the token and was not carried across.
The CLI version
Both jobs installed the latest Terraform.
planandapplyare unaffected because theyexecute remotely, but
state rmruns locally against remote state and is refused unlessthe CLI satisfies the workspace constraint:
This one is time-dependent. It worked when the feature was written and broke on its own once a
newer Terraform shipped — no change in either repository was needed. Every consumer inherits
it as soon as their workspace constraint falls behind, and it surfaces only when someone
actually needs to decommission, which is when an orphaned repository is already breaking plans
for everything else.
Approach
One composite action,
resolve-tf-version, covers both. It needs the same three values eitherway, and both defects want to fail early and clearly:
setup-terraformIt never falls back to the latest release — installing a version the workspace rejects is
the failure it exists to prevent.
This mirrors
link-backend, the existing precedent for extracting the few lines both jobsneed.
Version shapes
A workspace may report an exact version or a pessimistic constraint, and
setup-terraformaccepts exact versions and
<-style constraints but not~>. Verified across the shapes:Constraints are conventionally written with a space, so spacing is normalised before
matching rather than one spelling being privileged.
1.14.31.14.3~> 1.14.0or~>1.14.0<1.15.0~> 1.9.0<1.10.0~> 1.14,>= 1.14.0,latest, emptyRejecting the two-component
~>1.14is deliberate: it means>=1.14, <2.0, not the samething, and guessing there would install a version the workspace might refuse.
Applied to both jobs
The version failure was observed only in the mutating job — with a mismatched CLI,
discovercompleted fine, since
terraform show -jsonandterraform state listtolerate it, and onlystate rmrefused.Both jobs still resolve it.
discoverreads state, a future version could break that too, andtwo jobs installing different CLIs is a trap for the next reader.
graformeris deliberately untouched, and the action's description says why: plan and applyrun remotely, so the local CLI is only a client there.
Documentation
docs/workflows.mdcoversImportandDrift Checkand never coveredDecommission. Thesetup requirements are load-bearing — they are half of the token fix — so the new section
states them explicitly, including that the token and
WORKSPACEmust both berepository-level, unlike every other workflow here.
It also settles the operating order. The original description of the feature says to delete the
config first and then run the workflow; the code refuses to run without it, and testing
confirmed the code:
Verification
Both defects were reproduced against a real organisation during release testing, and the same
path re-verifies the fix. Still to run once this is on a testable ref:
discoverfails on the new guard with an actionablemessage rather than on
terraform initaddresses enumerated including composite-keyed environment resources, approval gate holding,
state rmsucceeding, the repository on GitHub untouched, and deleting the config afterwardsplanning no changes
The last group was confirmed manually during testing with both workarounds in place; this run
is what shows the workarounds are no longer needed.