ci: give action versions a watcher, and settle the Node pins - #332
ci: give action versions a watcher, and settle the Node pins#332FrameAutomata wants to merge 4 commits into
Conversation
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>
Cleanup pass over the previous commit; no behaviour change to the config. Drop `open-pull-requests-limit: 4`. With every action grouped it can never bind (two groups, default ceiling five), and its comment conceded as much while also claiming headroom for security updates -- which the key does not govern, those run against a separate limit. Dead config plus a false claim. Move the "detection, not validation" paragraph out of the YAML and into CLAUDE.md, which already owns the `ci`-label policy one paragraph above. It changed no key in the config, so an editor of that file could not act on it. Cut the `labels:` comment down for the same reason: the absence of the key needs a marker, not an essay that re-states what it points at. Note the three dtolnay/rust-toolchain@stable refs in the group comment. `stable` is a branch and that repo publishes no version tags, so those three never surface -- worth saying, or the third-party group looks like total coverage of the non-actions pins when it is 16 of 19. Reword the two node-version comments to the real cost and match the two-line form release-traceway.yml:63 already uses for the same decision. The win is the runner tool cache, which ships LTS lines and never Current, so "latest" re-downloaded Node on every deploy; npm caching was never affected, since setup-node keys that on platform, arch and the lockfile hash only. Split the CLAUDE.md paragraph in two -- Dependabot policy and Node pinning are separate topics -- and fix what it got wrong: not every Node image is alpine (Dockerfile.browser runs bookworm-slim), nothing asserts the images agree with engines.node, and testing/devtesting-nestjs is still on Node 20, so "pinned to 22 at every site" was false. Say plainly that CI pins per site *because* engines.node is a floor and node-version-file would resolve it to the newest release, which is the reasoning f95424c already applied to release-traceway.yml -- otherwise this contradicts the dev-shell paragraph above, which does read that file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review pass over the two prose changes. The config is unchanged; every fix here is a claim that did not match how the repo behaves. CLAUDE.md told a reviewer to validate a release-path bump with a workflow_dispatch dry run. There is no dry run on that path. Dispatching release-docs.yml or release-website.yml runs cloudflare/wrangler-action with `command: deploy` and the production Cloudflare token, and the other release-* workflows publish real assets with contents: write -- so following that instruction to check a wrangler-action major would have deployed tracewayapp.com from an unreviewed bot branch. Say what the path actually costs, and point validation at the action's release notes instead. Two landing sites were wrong in the same sentence. golangci-lint-action is label-reachable through cli-lint.yml, so it does not need any of this. traceway-autofix.yml has no workflow_dispatch at all -- only `issues: labeled` -- so claude-code-action, which runs with contents/pull-requests/ issues write and id-token, is the one pin with no pre-merge validation path whatever. That is worth knowing before its next major, not after. The third-party enumeration in the config under-listed the group it describes: `*` minus actions/* also captures Swatinem/rust-cache and anthropics/claude-code-action. Extend the not-covered note. Alongside the three @stable branch refs, three action pins ship inside documentation -- two in the source-map recipe this PR already edits, one in a website blog post -- and live outside .github/workflows, so Dependabot never sees them. Naming them keeps the file from reading as total coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This PR changed release-docs.yml and release-website.yml from node-version: "latest" to a literal 22, and documented "Node is pinned per site rather than read from one file" as the intended shape. #346 (closing #333) makes .nvmrc the single source of truth instead, so both are superseded: the two workflows now take node-version-file: .nvmrc, which fixes "latest" for the same reason and without adding a third and fourth hand-maintained literal. Dropping them here rather than reconciling them, since they touched the exact lines #346 does -- the two PRs would otherwise conflict, and this one is about Dependabot. What remains is the watcher and the docs recipe's node20 actions, which is what the PR was for. Refs #330, #333. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
abe1b1f to
d0b718b
Compare
|
Dropped the two They touched the exact lines #346 changes ( #346 supersedes them anyway: it fixes What's left is what the PR was actually for: the Dependabot watcher (#330) and the docs recipe's node20 action pins. Also rebased onto current Generated by Claude Code |
Closes #330. Follow-up to #326 (#328 / #329), which hand-bumped 68 action pins across 16 workflows after a human read a run annotation — twice in one day.
Independent of the #326 stack: I test-merged all three file edits against
ci/326-node24-third-partyand they auto-merge cleanly, so this targetsmainand can land in either order.Dependabot,
github-actionsonlynpm and Go modules are deliberately left unwatched —
backend/andcli/already rungovulncheckdaily, and those ecosystems would bury the signal this file exists for.Two groups, split the way #328/#329 split by hand — but on what a major means, not on who ships it:
actions/*wrangler-actionv4 silently moved its default Wrangler CLI from 3 to 4, which is the whole of #331A major/minor split would be dead config: all 79 updatable pins are bare major tags, so Dependabot can only ever propose majors here. Realistic volume is well under one PR/month.
ciis deliberately not auto-applied. The issue asks for a call onlabels:, and this is it. That label is the collaborator trust gate; an unattended bot PR proposing an action version nobody has read should not trip it.open-pull-requests-limitis deliberately not set — with every action grouped it could never bind, and a key that does nothing is worse than the default.Coverage is honest about its gaps. Three
dtolnay/rust-toolchain@stablerefs are branch pins against a repo with no version tags, so they never surface. Three more action pins ship inside documentation (sourcemap-upload.mdx,auto-fix-loop.mdx) and live outside.github/workflows, so Dependabot never sees them. Both are named in the config rather than left to be assumed covered.Validation is not what I first wrote
The first draft told reviewers to validate a release-path bump with a
workflow_dispatchdry run. There is no dry run on that path — dispatchingrelease-docs.ymlorrelease-website.ymlrunswrangler-actionwithcommand: deployand the production Cloudflare token, and the otherrelease-*.ymlworkflows publish real assets. Following that advice to check awrangler-actionmajor would have deployed tracewayapp.com from an unreviewed bot branch. Corrected to point at release notes instead.Two landing sites were also wrong:
golangci-lint-actionis label-reachable viacli-lint.yml, andtraceway-autofix.ymlhas no dispatch at all (onlyissues: labeled), soclaude-code-action— running withcontents/pull-requests/issues: writeandid-token— is the one pin with no pre-merge validation path whatsoever.The two Node questions, settled in the same pass
node-version: "latest"→22inrelease-docs.ymlandrelease-website.yml.latestresolves to Node Current, which the runner tool cache never ships, so every deploy re-downloaded a Node tarball — and neitherdocs/package.jsonnorwebsite/package.jsondeclares anenginesfloor to catch it. 22 matchesrelease-traceway.yml,benchmark-processor.ymland thenode:22-alpineimages.This follows f95424c rather than reversing it: that commit loosened
engines.nodeto>=22and deliberately replacednode-version-file:with a literal22, becausenode-version-fileresolves a floor to the newest release. A single-source-of-truth (.nvmrc+node-version-file:) is a real option, but it reverses a documented maintainer decision and belongs in its own issue, not folded in here.sourcemap-upload.mdx:93node-version: 20→22— the repo's lastnode-version: 20, recommending readers a major used nowhere here.Verification
.github/dependabot.ymland all 16 workflows parse; group keys resolve as intended.uses:refs — the partition is exact (63 first-party, 19 third-party, 3 unbumpable).ci/326-node24-third-party: clean, correctly combining ci: move every first-party action off the Node 20 runtime #328's@v7bumps with this branch'snode-version: 22.Dockerfile.browseris bookworm-slim), nothing asserts the images matchengines.node, andtesting/devtesting-nestjsis still on Node 20 — so "pinned to 22 at every site" was false.ci, and none of the touched workflows is label-reachable. The config itself is only exercised once merged to the default branch.🤖 Generated with Claude Code