A tag is a pointer, not a version — pin every checkout/cache to a commit #405

Merged
enricobuehler merged 1 commits from worktree-actions-pin into main 2026-08-27 09:21:15 +00:00
Owner

Follow-up to #396, kept separate because it is mechanical and touches every workflow.

actions/checkout@v4 re-resolves on every run, so whoever controls that tag controls step 0 of nearly every job in this repo — including the jobs that hold signing keys. This pins all of them to commits and moves off the stale v4 majors.

  • 52 × actions/checkout@v4@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  • 31 × actions/cache@v4@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0

announce.yml's lone existing SHA pin moves up with them, so the tree is uniformly pinned rather than half-pinned — the state where a reader can't tell a deliberate omission from a miss.

Why this needed proving first

v5+ of both actions declare runs.using: node24, and Gitea's runner only accepts node24 from a given version onward. Get this wrong and the whole fleet fails at once — including the runs that would tell you it broke. So, before touching 83 sites:

  • Every runner serving this repo is Gitea Runner v1.0.8, whose vendored act accepts node24 (checked in its source at that exact version).
  • runs.using is only a validation gate. act execs a bare node from PATH, so the image's node is the real interpreter — and the oldest here is 18.19.1 (ubuntu:24.04's nodejs, in rust-ci-noble).
  • So checkout v7's node24-targeted ESM bundle was run under that exact node in that exact image. It parsed every input, drove git through @actions/exec, created .git in the workspace, set up and tore down its credential config, and ran its post step — reaching a genuine git error against the synthetic file:// remote used for the test, not a module-load or missing-API failure.
  • Actions clone straight from github.com here (no Gitea mirror), so these SHAs are meaningful. Both tags are lightweight, pointing directly at the pinned commits — verified via git ls-remote and the GitHub API.

Breaking changes checked, none apply

  • checkout v6 changed credential persistence, v7 blocks fork-PR checkout for pull_request_target/workflow_run. This repo passes zero checkout inputs and uses neither event.
  • cache v5/v6 select the same legacy service path as v4, because the runner never sets ACTIONS_CACHE_SERVICE_V2.
  • bench-gpu.yml needed no carve-out: no gpu-labelled runner is registered, and its last 10 nightly runs sat unassigned.

Deliberately not swept

actions/upload-artifact@v3 (7 sites) stays. It is pinned low on purpose — Gitea's artifact backend identifies as GHES and v4 refuses it. A naive sweep would have broken every artifact upload.

Verification

All 26 workflows re-parse, and the uses: values extracted back out of the parsed YAML are clean SHAs (the trailing # v7.0.1 is a proper comment, not part of the value). Beyond that, this PR's own CI is the test — pull_request runs use the workflow files from this branch, so every job here checks out with the new pin.

Note for elsewhere

unom/infra/scripts/setup-gitea-runner-base.ps1 pins Node 20.18.0 with a comment saying "actions/checkout@v4 needs node20 on PATH". Still functional, but the comment is now stale.

Follow-up to #396, kept separate because it is mechanical and touches every workflow. `actions/checkout@v4` re-resolves on every run, so whoever controls that tag controls **step 0 of nearly every job in this repo** — including the jobs that hold signing keys. This pins all of them to commits and moves off the stale v4 majors. - **52** × `actions/checkout@v4` → `@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1` - **31** × `actions/cache@v4` → `@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0` `announce.yml`'s lone existing SHA pin moves up with them, so the tree is uniformly pinned rather than half-pinned — the state where a reader can't tell a deliberate omission from a miss. ## Why this needed proving first v5+ of both actions declare `runs.using: node24`, and Gitea's runner only accepts node24 from a given version onward. Get this wrong and the whole fleet fails at once — including the runs that would tell you it broke. So, before touching 83 sites: - Every runner serving this repo is **Gitea Runner v1.0.8**, whose vendored `act` accepts `node24` (checked in its source at that exact version). - **`runs.using` is only a validation gate.** act execs a *bare* `node` from PATH, so the image's node is the real interpreter — and the oldest here is **18.19.1** (`ubuntu:24.04`'s nodejs, in `rust-ci-noble`). - So checkout v7's node24-targeted **ESM** bundle was run under that exact node in that exact image. It parsed every input, drove `git` through `@actions/exec`, created `.git` in the workspace, set up and tore down its credential config, and ran its post step — reaching a genuine `git` error against the synthetic `file://` remote used for the test, **not** a module-load or missing-API failure. - Actions clone straight from github.com here (no Gitea mirror), so these SHAs are meaningful. Both tags are lightweight, pointing directly at the pinned commits — verified via `git ls-remote` and the GitHub API. ## Breaking changes checked, none apply - **checkout v6** changed credential persistence, **v7** blocks fork-PR checkout for `pull_request_target`/`workflow_run`. This repo passes **zero** checkout inputs and uses **neither** event. - **cache v5/v6** select the same legacy service path as v4, because the runner never sets `ACTIONS_CACHE_SERVICE_V2`. - `bench-gpu.yml` needed no carve-out: no `gpu`-labelled runner is registered, and its last 10 nightly runs sat unassigned. ## Deliberately not swept `actions/upload-artifact@v3` (7 sites) stays. It is pinned low **on purpose** — Gitea's artifact backend identifies as GHES and v4 refuses it. A naive sweep would have broken every artifact upload. ## Verification All 26 workflows re-parse, and the `uses:` values extracted back out of the parsed YAML are clean SHAs (the trailing `# v7.0.1` is a proper comment, not part of the value). Beyond that, **this PR's own CI is the test** — pull_request runs use the workflow files from this branch, so every job here checks out with the new pin. ## Note for elsewhere `unom/infra/scripts/setup-gitea-runner-base.ps1` pins Node 20.18.0 with a comment saying *"actions/checkout@v4 needs node20 on PATH"*. Still functional, but the comment is now stale.
enricobuehler added 1 commit 2026-08-26 19:08:46 +00:00
ci: pin every checkout/cache to a commit, and move off the stale v4 majors
installer-smoke / smoke (arch) (pull_request) Successful in 53s
windows-drivers / driver-build (pull_request) Successful in 1m45s
apple / swift (pull_request) Successful in 2m18s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
android / android (pull_request) Successful in 10m8s
installer-smoke / smoke (fedora-44) (pull_request) Successful in 2m59s
installer-smoke / smoke (debian-13) (pull_request) Successful in 3m52s
nix / flake (pull_request) Successful in 8m11s
windows-drivers / probe-and-proto (pull_request) Successful in 34s
ci / docs-drift (pull_request) Successful in 34s
ci / bun-nix (pull_request) Successful in 29s
ci / web (pull_request) Successful in 1m12s
ci / docs-site (pull_request) Successful in 1m10s
ci / rust-arm64 (pull_request) Successful in 1m39s
ci / rust (pull_request) Successful in 6m4s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 2m58s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 7m44s
d3a5f13a45
A tag is a pointer, not a version. `actions/checkout@v4` re-resolves on
every run, so whoever controls that tag controls the first step of nearly
every job in this repo — including the jobs holding signing keys. 52
checkout sites and 31 cache sites now name a commit; announce.yml's lone
existing SHA pin moves up with them so the tree is uniformly pinned rather
than half-pinned, which is the state where a reader cannot tell a
deliberate omission from a miss.

checkout v4 -> v7.0.1, cache v4 -> v6.1.0, both by commit.

The reason this needed proving rather than just doing: v5+ of both declare
`runs.using: node24`, and Gitea's runner only accepts node24 from a certain
version on. Checkout is step 0 of almost everything here, so getting it
wrong fails the whole fleet at once — including the runs that would tell
you it broke.

What was established first:
- every runner serving this repo is Gitea Runner v1.0.8, whose vendored
  act accepts node24;
- `runs.using` is only a validation gate — act execs a BARE `node` from
  PATH, so the image's node is the real interpreter, and the oldest one
  here is 18.19.1 (ubuntu:24.04's nodejs, in rust-ci-noble);
- so checkout v7's node24-targeted ESM bundle was run under that exact
  node, in that exact image: it parsed inputs, drove `git` through
  @actions/exec, created .git, set up and tore down credential config, and
  ran its post step. It reached a genuine git error against the synthetic
  file:// remote used for the test — not a module-load or missing-API
  failure. It works.
- actions clone straight from github.com here (no Gitea mirror), so these
  SHAs are meaningful; both tags are lightweight, pointing directly at the
  commits pinned.

No breaking change in v5..v7 applies: this repo passes zero checkout
inputs, and uses neither `pull_request_target` nor `workflow_run` (v7's
fork-PR restriction). cache v5/v6 pick the same legacy service path as v4
because the runner never sets ACTIONS_CACHE_SERVICE_V2.

upload-artifact@v3 is deliberately NOT swept — it is pinned low on purpose,
because Gitea's artifact backend identifies as GHES and v4 refuses it.
enricobuehler merged commit 5f77074e51 into main 2026-08-27 09:21:15 +00:00
enricobuehler deleted branch worktree-actions-pin 2026-08-27 09:21:25 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#405