fix(docker-release): export GH_TOKEN so stevedore can cut the GitHub Release - #64
Merged
Merged
Conversation
…Release The stevedore step passed REGISTRY, STEVEDORE_CACHE_* and GH_PRIVATE_TOKEN but no GH_TOKEN. stevedore's publish path shells out to `gh release create` (internal/publish/publish.go) and takes no token flag, so gh found no credentials and exited 4 — after the image had already been built, pushed and marker-ref'd. The failure mode is worse than a red check, because it straddles a completed publish: on understudy v0.0.140 the run reports failure while understudy:0.0.140 and :31434f0 are both live in ECR, the generated dist/CHANGELOG.md is discarded with the job, and the tag ends up with no Release for a consumer to read. Every v* tag since v0.0.135 has had its Release created by hand. `contents: write` was already declared on the job for the marker refs, so github.token can create the release as-is; no new permission or secret. Env set on a `uses:` step reaches a composite action's own steps — REGISTRY and GH_PRIVATE_TOKEN travel that same path today and demonstrably arrive. Not fixed here: docker-release-split.yml has the same missing env on its `Stevedore merge` step, and additionally its per-platform legs run plain `release` (no --skip-publish), which reaches publishRelease too — so each leg would race to create the same tag's Release. Handing the legs a token without first skipping publish there would turn one clear failure into a flaky one, so split mode is left alone and tracked separately. Refs #63, understudy#225
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.
Symptom
docker-release.yml@mainbuilds and pushes the image, then fails the job on the last thing it does:Failing run: understudy v0.0.140.
Why it's worse than a red check
The failure straddles a completed publish, so the two halves disagree:
understudy:0.0.140and:31434f0, pushed2026-08-22T04:17:19Z, verified viaecr describe-images;dist/CHANGELOG.mdis generated and then thrown away with the job;understudy#225created the tag flow to produce.Consumers resolving the highest semver tag pick the image up regardless, so "red release run" does not mean "nothing shipped" — the natural reading is wrong. Every
v*tag from v0.0.135 through v0.0.140 has had its Release created by hand.Cause
internal/publish/publish.goshellsgh release createand passes no token flag —ghauthenticates purely from the environment:The stevedore action sets
GH_TOKENonly on itsInstall stevedorestep (to download its own binary). ItsRun stevedorestep declares justSD_COMMAND/SD_ARGS/SD_CONFIG, so nothing carries a token into the process that runsgh.exit status 4is gh's "no credentials", not a permissions denial.GH_PRIVATE_TOKENis a different thing and cannot stand in: it's a minted App token withcontents: read, wired to a BuildKit--secretfor fetching private modules inside the build.Fix
One env line on the stevedore step. No new permission and no new secret — the job already declares
contents: writefor the marker refs, which is exactly what creating a release needs:Env set on a
uses:step reaches a composite action's own steps. That path isn't assumed —REGISTRYandGH_PRIVATE_TOKENare set the same way and demonstrably arrive in the same run that failed (the image went to the right ECR host, and the privateppkitfetch succeeded).Deliberately not fixed here
docker-release-split.ymlhas the same missing env onStevedore merge, and a second problem underneath it:Merge()just callsRelease(), and the publish guard isif !o.NoPush && !o.Snapshot && !o.SkipPublish— nothing excludes a split leg. The per-platform legs run plainrelease --split <platform>with no--skip-publish, so each leg reachespublishReleaseand would race to create the same tag's Release (gh release createis not idempotent).Handing the legs a token before fixing that would convert one deterministic failure into a flaky one, so split mode is untouched. It needs
--skip-publishon the legs first, then the same env line onmerge.Verification
actionlintclean over the whole repo (local 1.7.x; the pinned CI version is 1.7.7).validate-reusable-inputsjobs cover the change; the input contract is unchanged (nowith:/inputs:edit), so no caller can break at parse time.v*tag on a caller. Note the first run after merge may hit an already-existing Release for a hand-created tag; that's the non-idempotentgh release create, not a regression from this change.Refs #63, pinpredict/understudy#225