fix(actions): pin github-actions runtime image to the release version#353
Closed
Cre-eD wants to merge 1 commit into
Closed
fix(actions): pin github-actions runtime image to the release version#353Cre-eD wants to merge 1 commit into
Cre-eD wants to merge 1 commit into
Conversation
The four composite actions (deploy-client-stack, provision-parent-stack, cancel-stack, destroy) hardcoded image docker://simplecontainer/github-actions:latest. A Docker-based action's image field is a parse-time literal with no expression interpolation, so pinning the action git ref (e.g. @2026.6.14) only pinned the thin action.yml wrapper. The runtime image still floated to whatever :latest pointed at. Any release that re-tags :latest therefore silently changed the runtime for every downstream consumer that believed it was pinned. This already bit a PAY-SPACE deploy on 2026-06-30 when 2026.6.17 moved :latest mid-day. Fix unifies on the :staging placeholder that branch-preview.yaml already expects: - action.yml x4: :latest -> :staging, so @main resolves to the maintained staging image and branch-preview.yaml's existing :staging -> version substitution actually applies (previously a no-op, so previews shipped :latest too). - welder.yaml tag-release: substitute :staging -> :${project:version} and commit before tagging, mirroring branch-preview.yaml. Prod release tags now ship action.yml pinned to their own version's image, which is the image push.yaml already builds and signs. The :latest and :staging Docker tags are still published, so any consumer referencing them directly is unaffected. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Semgrep Scan ResultsRepository:
Scanned at 2026-06-30 09:49 UTC |
📊 Statement coverageMeasured on the documented included set (see
Baseline: |
Security Scan ResultsRepository:
Scanned at 2026-06-30 09:50 UTC |
Contributor
Author
|
Closing — handling this on the PAY-SPACE consumer side instead of changing the upstream release mechanism. |
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
The four composite actions —
deploy-client-stack,provision-parent-stack,cancel-stack,destroy— hardcode their runtime image asdocker://simplecontainer/github-actions:latest.A Docker-based action's
image:field is a parse-time literal (GitHub Actions does not allow${{ }}interpolation there). So when a consumer carefully pins the action git ref — e.g.uses: simple-container-com/api/.github/actions/deploy-client-stack@2026.6.14— the pin only fixes the thinaction.ymlwrapper. The code that actually runs is whateversimplecontainer/github-actions:latestpoints to at job time.Result: any release that re-tags
:latestsilently changes the runtime for every downstream consumer that believes it is pinned, defeating the entire purpose of version pinning.This already bit production on 2026-06-30:
2026.6.17was published and moved:latestat 07:48 UTC, and a downstream deploy that was pinned to an older action tag immediately started running the new image with no change on its side.There's a second, latent bug:
branch-preview.yamlalready substitutes:staging→:${VERSION}, butmainnever contained:staging(it was:latest), so that substitution was a no-op — preview builds shipped:latesttoo.Fix
Unify on the
:stagingplaceholder thatbranch-preview.yamlalready expects:action.yml×4::latest→:staging.@main/ dev now resolves to the maintained staging image (built and pushed bybuild-staging.yml), andbranch-preview.yaml's existing:staging→ version substitution finally applies.welder.yamltag-release: substitute:staging→:${project:version}and commit before tagging, mirroringbranch-preview.yaml. Prod release tags now shipaction.ymlpinned to their own version's image — the same imagepush.yamlalready builds, signs, and attests.After this,
@2026.6.X⇒simplecontainer/github-actions:2026.6.X(reproducible),@main⇒:staging, preview tags ⇒ their preview version.Compatibility
The
:latestand:stagingDocker tags are still published bywelder.yaml/push.yaml/build-staging.yml, so anyone referencing them directly is unaffected. Only future release tags change behaviour; already-published tags (2026.6.17and earlier) keep their:latestreference and are not rewritten.Test plan
tag-releasesed withVERSION=2026.6.18→image: 'docker://simplecontainer/github-actions:2026.6.18'.2026.6.xtag'saction.ymlreferences:2026.6.x(not:latest), and that the tagged commit's image is signed/attested.Follow-up (not in this PR)
Add a release-gate check that fails if a pushed release tag's
action.ymlstill references:staging/:latest, so this can't silently regress.