ci: move every first-party action off the Node 20 runtime - #328
Open
FrameAutomata wants to merge 3 commits into
Open
ci: move every first-party action off the Node 20 runtime#328FrameAutomata wants to merge 3 commits into
FrameAutomata wants to merge 3 commits into
Conversation
GitHub is force-migrating node20 actions onto Node 24, which currently surfaces as a run annotation. The failure mode when the shim is removed is that every workflow breaks at once, release-traceway.yml and release-cli.yml included, so this moves ahead of it rather than discovering it at release time. All 63 actions/* pins across the 16 workflows: checkout v4 -> v7 (25 uses) setup-go v5 -> v7 (15 uses) upload-artifact v4 -> v7 (10 uses) download-artifact v4 -> v8 ( 5 uses) setup-node v4 -> v7 ( 4 uses) cache v4 -> v6 ( 4 uses) runs.using was read at each source and target ref: every one of these was node20 and is now node24. The six remaining node20 actions are all third-party and all on release workflows (docker/*, wrangler-action, setup-helm); they are a separate change because no PR label can exercise them. The three multi-major jumps with real behaviour changes, and why each is inert here: setup-go v6 stops relying on Go's toolchain download. It installs the `toolchain` directive's version rather than the `go` line's, and sets GOTOOLCHAIN=local so no download happens. Every module built in CI already pins toolchain go1.26.6, so the same compiler runs, one download sooner. The one job that installs an older Go than the repo floor (benchmark-hardware, go-version 1.25) only builds benchmarks/loadgen, which declares go 1.25 -- it does not build the backend, whose image is built by docker on the SUT. backend-vulncheck.yml documented the v5 mechanism in a comment, so that comment is rewritten here. setup-node v5 auto-enables caching when package.json carries a `packageManager` field. No package.json in the repo has one, and three of the four call sites already set `cache: npm` explicitly. download-artifact v5 changed the output path for single downloads by ID. Nothing here downloads by ID -- every call site uses `name:`, or `pattern:` with `merge-multiple: true`, or downloads all artifacts. v8 additionally errors rather than warns on a digest mismatch, which is the behaviour we would want anyway. All runners are GitHub-hosted (ubuntu-latest / ubuntu-24.04), so the 2.327.1 minimum runner version these releases require is already met. Refs #326. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The snippet is a copy-paste CI recipe, so a reader who follows it lands on the same deprecation annotation this branch just cleared out of our own workflows. Only the two action pins are touched. The `node-version: 20` on the next line is stale too, but that is a question about what Node the JS SDK supports rather than about the action runtime, so it wants its own change. Refs #326. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two follow-ups from reviewing the action bumps. The vulncheck comment named GOTOOLCHAIN=local for both setup-go and the golang Docker bases while asserting the two behave differently, which destroyed the contrast the comment exists to draw. The real difference is which Go gets installed first, so the setup-go half no longer mentions the variable and the Docker half says explicitly that it ignores the `toolchain` line. The parenthetical recording what v5 used to do is gone too -- no file pins setup-go@v5 any more, and git blame is the right home for a version delta. backend.yml pins `cache: false` on setup-go and hand-rolls actions/cache over ~/.cache/go-build and ~/go/pkg/mod, keyed on go.sum with a run_id suffix so each run saves a fresh entry and the restore-keys carry the previous tree forward. Neither cached tree is valid across a Go version change: go-build entries are compiler-keyed, and until this branch GOTOOLCHAIN=auto materialised a ~250MB toolchain module inside GOMODCACHE. setup-go v7 installs the toolchain directly and never writes that module again, but nothing deletes it either -- the module cache has no trimming, so the run_id rotation would have copied a dead toolchain forward on every run indefinitely. Adding the version to the key fixes that without a cleanup step, and fixes it for every future Go bump rather than this one: the cache generation now rotates whenever the compiler does. Costs one cold run per job, most of which was dead weight anyway. Refs #326. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 27, 2026
FrameAutomata
added a commit
that referenced
this pull request
Aug 28, 2026
Nothing in this repo watched action versions: no dependabot.yml, no renovate.json, and the strings appear nowhere. That is how the Node 20 runtime migration (#326) was found twice in one day, both times because a human read a run annotation. #328/#329 bought distance from that deadline but no detection, so the next major lands exactly as silently. Adopt Dependabot for the github-actions ecosystem only. npm and Go modules are left unwatched on purpose -- backend/ and cli/ already run govulncheck daily, and those ecosystems would bury the signal this file exists for. Two groups, split the same way #328/#329 split by hand, on what a major means rather than on who ships it: actions/* majors are normally runtime bumps, wide and mechanical and reviewable as one sweep, while a third-party major can change behaviour -- wrangler-action v4 silently moved its default Wrangler CLI from 3 to 4, which is the whole of #331. The PRs are deliberately not auto-labelled `ci`. That label is the collaborator trust gate that makes PR CI opt-in, and an unattended bot PR proposing an action version nobody has read should not trip it; a reviewer applies it after looking, as for any human PR. Worth being clear-eyed that this is mostly detection and not validation: `ci` reaches only backend*.yml and cli*.yml, while most pins sit on release-*.yml, benchmark-*.yml and traceway-autofix.yml, where validating a bump still means a workflow_dispatch dry run. Detection is the half that was missing. Settle the two Node questions in the same pass, since they are the same discipline. release-docs.yml and release-website.yml pinned `node-version: "latest"`, which floats two production deploys onto whatever Node shipped that morning, up to and including a non-LTS Current release -- and neither docs/package.json nor website/package.json declares an engines floor to catch it. Both now pin 22, the major already used by release-traceway.yml, benchmark-processor.yml and the node:22-alpine Dockerfiles, matching frontend/package.json's >=22. Whether Traceway moves to Node 24 is now one decision made once rather than one made silently on two deploy paths. The source-map upload recipe was the last surviving `node-version: 20` in the repo, recommending to readers a major this repo uses nowhere while #328 had just bumped the action pins around it to the Node 24 majors. It recommends 22 now, the same version the shipped Dockerfiles run. Closes #330 Co-Authored-By: Claude Opus 5 (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.
Part 1 of #326. Bumps the 63
actions/*pins across all 16 workflows. Part 2 (ci/326-node24-third-party) handles the six third-party actions on the release workflows and is stacked on this branch.GitHub currently reports this as a run annotation:
The forcing is the step before removal, and when that lands every workflow breaks at once —
release-traceway.ymlandrelease-cli.ymlincluded. Losing the ability to cut a release is a bad way to find out.actions/checkoutactions/setup-goactions/upload-artifactactions/download-artifactactions/setup-nodeactions/cacheruns.usingwas read at each source and target ref: all six werenode20, all six are nownode24.The three jumps with real behaviour changes
Not a
sed 's/@v4/@v7/'— these skip 2–3 majors. Each was checked against how this repo actually calls it.setup-gov6 changed toolchain handling (#460), and this repo cares: CLAUDE.md documents keepinggoandtoolchainingo.moddistinct. v6 installs thetoolchainversion rather than thegoline's, and setsGOTOOLCHAIN=localso Go does not download one itself.Both modules pin
go 1.26.2/toolchain go1.26.6, so the same compiler runs either way — v5 got there by downloading 1.26.6 on first use, v7 installs it directly. Same version, one less download.GOTOOLCHAIN=localdoes mean a job that installs an older Go than a module's floor now errors instead of silently upgrading. One job installs an older Go:benchmark-hardware.yml(go-version: '1.25'). It only buildsbenchmarks/loadgen, which declaresgo 1.25; the backend there is built bydocker compose --buildon the Hetzner SUT, not by the runner's Go. So nothing regresses.backend-vulncheck.ymldocumented the v5 mechanism in a comment — rewritten in this PR, since it would otherwise now be false.setup-nodev5 auto-enables caching whenpackage.jsonhas apackageManagerfield. Nopackage.jsonin this repo has one, and three of the four call sites already setcache: "npm"explicitly.download-artifactv5 changed output paths for single downloads by ID. Nothing here downloads by ID — every call site usesname:, orpattern:+merge-multiple: true, or downloads everything. v8 additionally errors rather than warns on a digest mismatch, which is the behaviour you'd want on a release artifact anyway.upload-artifactv7'sarchive: falseis opt-in with the default unchanged, andcachev5/v6 are runtime + ESM only — the key/restore semantics I'd expected to change didn't.Runner requirement
These releases require Actions Runner ≥ 2.327.1. Every job here is
ubuntu-latestorubuntu-24.04— all GitHub-hosted, no self-hosted runners — so that's already met.Validating
backend.yml,backend-vulncheck.yml,cli.yml,cli-lint.ymlandcli-contract.ymlall run on thecilabel, which exercisescheckout,setup-goandcache— including thesetup-gotoolchain change, which is the one worth actually watching. The benchmark workflows (upload-artifact/download-artifact) areworkflow_dispatch-only and cost real money to run, so those two are argued from the changelogs and the call sites above rather than from a green run.Note for #315
frontend.yml, incoming via #315, addsactions/checkout@v4andactions/setup-node@v4. Worth bumping those to@v7there so it doesn't land already stale — this PR can't reach that file.🤖 Generated with Claude Code
Also: one docs recipe
docs/pages/client/js-sdk/sourcemap-upload.mdxships a copy-paste GitHub Actions recipe pinningcheckout@v4andsetup-node@v4— a reader following it lands on the same annotation. Bumped to@v7in a separate commit.Left alone deliberately: the
node-version: 20on the next line of that snippet (a question about what Node the JS SDK supports, not about the action runtime), andwebsite/content/blog/auto-fix-loop.mdx, which pinsupload-artifact@v4in a published, dated post.From a cleanup pass over this diff
backend.yml's Go caches would have carried a dead toolchain forever. Those three jobs setcache: falseon setup-go and hand-rollactions/cacheover~/.cache/go-buildand~/go/pkg/mod, keyed ongo.sumwith a${{ github.run_id }}suffix — so every run saves a fresh entry and the restore-keys carry the previous tree forward.Neither cached tree survives a Go version change.
go-buildentries are compiler-keyed, and until this branchGOTOOLCHAIN=automaterialised a ~250MBgolang.org/toolchain@...go1.26.6module insideGOMODCACHE. setup-go v7 never writes that module again — but nothing deletes it either, and the module cache has no trimming, so therun_idrotation would have copied a dead toolchain forward on every run indefinitely.Fixed by putting the resolved Go version in the key (
steps.setup-go.outputs.go-version, withid: setup-goadded to the three steps) rather than by a cleanup step. That fixes it for every future Go bump instead of this one — the cache generation now rotates whenever the compiler does. Costs one cold run per job, most of which was dead weight anyway.The vulncheck comment rewrite got tightened. The first version named
GOTOOLCHAIN=localfor both setup-go and the golang Docker bases while asserting the two behave differently, which destroyed the contrast the comment exists to draw — the real difference is which Go gets installed first. The setup-go half no longer mentions the variable, and the Docker half now says explicitly that it ignores thetoolchainline. The parenthetical recording v5's old behaviour is gone: no file pinssetup-go@v5any more, and git blame is the right home for a version delta.Follow-ups filed