Repository navigation
ci: three actions still target Node.js 20, and sixteen SHA-pinned actions cannot be checked at all #15332
Description
Activity
- added a commit that references this issue
on Aug 31, 2026 Partially landed — staying open on one criterion.
79813b1533(PR #15347), verified against mergedDev_new_gui.Met: all three Node-20 pins bumped to the version already standard elsewhere in the repo —
setup-python-ci/action.yml:176andsetup-python-suite/action.ymltoactions/cache@v6,auto-merge-base-into-parked-branches.yml:79toactions/checkout@v7.The issue's second premise was already stale. It says sixteen SHA-pinned actions "cannot be checked at all"; in fact all 44 SHA-pinned call sites already carry a
# vX.Y.Zcomment. So rather than build the checking mechanism the issue asked for,repo_tests/workflow_action_version_regression_test.pynow enforces the invariant that already holds — every SHA pin must keep a readable version comment, and no tag-pinned action may be older than the repo's own maximum for that exact action string.NOT met, deliberately: cross-checking SHA-pinned versions against each other.
docker/login-action,docker/build-push-actionandsigstore/cosign-installerare pinned to genuinely different releases in different workflows today. Enforcing consistency would break CI immediately and requires an owner decision on which version is canonical for each — so it is recorded as an explicit scope exclusion in the guard's docstring rather than silently dropped. That is the one thing keeping this issue open.On the
actions/cache@v6risk, since it was raised and could not be settled from source: that bump is gated onrunner.environment == 'self-hosted', self-hosted runner binaries do not auto-update, and a Node-runtime mismatch fails a job outright rather than warning. Nothing in the repo tracks the runner version. Settled empirically instead —code-qualitycompleted success on the bumped head, and that job isruns-on: [self-hosted, Linux, X64]using the very action file the bump lives in. Observed, not inferred.One guard improvement worth recording: the version-comparison test was unfalsifiable as first written — with zero tag drift in the repo,
version < bestis never true and an inverted operator would have passed identically. It is now pinned by planted fixtures and proven by mutation (inverting the operator fails it; restoring passes).Branch-freeze re-verification against current
origin/main(2026-09-20). Tracked branchissue-15332-ci-actionsis already gone from origin.AC1-2, 4 met; AC3 met via a documented, reasoned substitute; AC5 spot-checked live:
- All 3 version-tagged call sites now match the repo standard:
.github/actions/setup-python-suite/action.yml:225andsetup-python-ci/action.yml:195bothactions/cache@v6;auto-merge-base-into-parked-branches.yml:79isactions/checkout@v7. - Composite actions are in scope —
repo_tests/workflow_action_version_regression_test.py's own docstring says so explicitly: "a sweep over.github/workflows/*.ymlalone would have missed them, which is why this guard walks both directories." - / substitute: AC3 as literally written ("Node runtime alongside the pin") was not implemented — a documented alternative was, in its place. The guard's docstring states this directly: every SHA pin now carries a readable
# vX.Y.Zcomment (spot-checked:actions/checkout@9c091bb... # v7.0.0,github/codeql-action/*@b96794f... # v4.38.0), plus a cross-consistency check that every pin of the same SHA carries agreeing version labels — which caught and is regression-tested against a real prior bug (codeql-actionlabelled# v3in one workflow and# v4in another, same SHA). The reasoning given for not resolving to Node runtime: that needs network access a repo_tests guard doesn't have. Judgment call, not an oversight — flagging it as a deviation from the literal AC rather than silently counting it as done. -
test_no_tag_pinned_action_is_older_than_the_repo_standardis the required fail-on-regression check, with a negative control (test_the_comparison_flags_a_planted_regression) proving it actually catches a planted regression rather than just reading clean today. It runs as part ofrepo_tests/underpython-suite, which is now a required context (independently confirmed while triaging ci: the backend Python suite gates nothing — python-suite is not a required check #14353 in this same pass) — so this does gate merges, just via the existing required suite rather than a dedicated new check. - Spot-checked a real completed run (
ci.ymlrun 35525014904,python-suite shardjob): zero annotations of any kind, zero Node 20 mentions. Not exhaustive across every job type, but a real run, not a file read.
4 of 5 fully met, 1 deliberately substituted with reasoning recorded. Leaving open for a decision on whether the AC3 substitute is accepted as closing that criterion, since I don't think that call is mine to make.
- All 3 version-tagged call sites now match the repo standard:
What
Every CI job currently emits this annotation:
"Forced to run on Node.js 24" is a compatibility shim GitHub applies today and will remove. When it goes, those steps stop working — and the timing is not ours to choose, which is the argument for fixing it before it becomes an outage rather than after.
Measured
The repository is mostly current —
actions/checkout@v7,actions/cache@v6,actions/setup-python@v7,actions/upload-artifact@v7. Three call sites are not:actions/cache@v4.github/actions/setup-python-suite/action.yml:155@v6actions/cache@v4.github/actions/setup-python-ci/action.yml:176@v6actions/checkout@v4.github/workflows/auto-merge-base-into-parked-branches.yml:79@v7The two
cache@v4sites are the ones producing the annotation, and they sit inside composite actions — which is why they were missed by whatever bumped the workflows: a sweep over.github/workflows/*.ymldoes not reach.github/actions/*/action.yml.The
checkout@v4is mine, introduced in #15316. I wrote it against the older example rather than checking what the repo standardised on, and no check caught the divergence.The part worth a decision, not just a bump
Sixteen actions are SHA-pinned:
SHA-pinning is correct for supply-chain integrity — it is what stops a moved tag executing new code. But it also means these never pick up a runtime bump, and their Node version cannot be read from the ref. So the annotation above names only the version-tagged stragglers; any SHA-pinned action still targeting Node 20 is invisible to it and will break with equally little warning.
That tension is the real content of this issue. Un-pinning to fix a runtime deprecation would trade a supply-chain control for convenience, which is the wrong direction. The workable answer is to resolve each pinned SHA to its release and record the Node runtime alongside the pin, so the next deprecation is a lookup rather than an archaeology exercise.
Acceptance criteria
.github/actions/are included in whatever sweep keeps action versions current — the gap that let two of these surviveNote on the last criterion
The annotation is the only signal that surfaced this, and it appears in job annotations rather than in any check's pass/fail. Nothing fails today, which is precisely why three call sites drifted. Whatever check comes out of this should be the thing that fails — an annotation nobody is required to read is how this reached three sites and sixteen unreadable pins.