Skip to content

ci: pin workflow actions to Node 24 release SHAs (#301) - #307

Merged
HemSoft merged 1 commit into
mainfrom
ci/301-pin-node24-actions
Nov 6, 2026
Merged

HemSoft merged 1 commit into
mainfrom
ci/301-pin-node24-actions

Conversation

@HemSoft

@HemSoft HemSoft commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Risk level: 4/10 (codexbar)
Worked on by: Claude Opus 5.5 on Home, for chief-dispatch-0cb32946

Closes #301.

Summary

CI and Package referenced every action by a movable tag, and four of them (checkout@v4, upload-artifact@v4, setup-node@v4, setup-python@v5) target Node 20, which GitHub removed from Actions on 2026-09-23. Each run carried a "Node.js 20 is deprecated" annotation on every job.

All 25 uses: lines (17 in ci.yml, 8 in package.yml) now name a full commit SHA with the release in a trailing comment. Every pinned release's action.yml declares runs.using: node24:

Action Before After Pinned SHA
actions/checkout v4 v7.0.1 3d3c42e5…
actions/upload-artifact v4 v7.0.2 cf430e03…
actions/setup-node v4 v7.1.0 949feb24…
actions/setup-python v5 v7.1.0 6d4fd22b…
actions/setup-dotnet v4 v6.1.0 0f4a354d…
github/codeql-action/upload-sarif v4 v4.39.3 33d7b85d…
Swatinem/rust-cache v2 v2.9.3 d1527c8f…

Each tag was resolved to its commit on the upstream repository, and the SHAs were checked a second time independently. Inputs, triggers, job names, artifact names and artifact paths are unchanged, so no docs needed updating.

scripts/tests/ci-workflow.test.cjs gains one test: every uses: line in both workflows must be owner/repo[/path]@<40 hex chars> # vX.Y.Z. It fails on main's workflows (first offender actions/checkout@v4) and passes here.

Release-note impact

I read the release notes for every major version between the old and new tags, and checked each change against how these workflows use the action:

  • checkout v5.1/v6.1 allow-unsafe-pr-checkout (marked breaking): it applies only to fork code under pull_request_target or workflow_run. These workflows use push, pull_request and workflow_dispatch, and v7.0.1 skips the check when the input keeps its default.
  • checkout v6 credentials in a separate file: persist-credentials now writes the token to a file under $RUNNER_TEMP, which the repo's git config reaches through includeIf, and v6.0.1 extended that to worktrees. rust-metrics runs git worktree add and checks for untracked inputs. Both stay local and the credential file is outside the workspace, so neither changes.
  • checkout v5 / setup-node v5 / setup-python v6 / setup-dotnet v5 / upload-artifact v6 minimum runner 2.327.1: all jobs run on GitHub-hosted runners, which are newer than that.
  • setup-node v5 automatic caching: it turns on only when package.json names npm in packageManager or devEngines.packageManager. This repo has neither field and already sets cache: 'npm' explicitly.
  • setup-node v7 removed the placeholder NODE_AUTH_TOKEN export: build doesn't publish or use a registry token.
  • setup-python v7 removed the pip-install input and EOL Pythons: neither is used; 3.13 is still supported.
  • setup-dotnet v5 dropped installers for old .NET versions: 9.0.x is current. The input classifier treats .github/ and scripts/ changes as retired C# inputs, so this PR selects the .NET steps. Setup .NET v6.1.0 and all remaining gates passed in the current CI build job.
  • upload-artifact v7 archive input: it defaults to true, the same zip upload as before. Artifact names stay security-scan-reports, rust-metrics, rust-mutations, npm-audit, stryker-report, ci-inputs, codexbar-macos and codexbar-linux.
  • codeql-action and rust-cache: same major version; only pinned.

Acceptance Criteria

  • A CI run shows no Node 20 deprecation annotation on any job: all 7 CI jobs and all 6 jobs in the two Package runs passed. The complete check-run annotations were read; none mentions Node 20.
  • Every uses: in ci.yml and package.yml is a full 40-character SHA with its version in a trailing comment: grep -nE "uses: [^ ]+@[^ ]+" .github/workflows/*.yml lists 25 lines, all SHAs, and the new test enforces it.
  • Artifact names and paths are unchanged, and the breaking changes in the new versions were checked against their release notes (above).

Definition of Done

  • A full CI run and a workflow_dispatch run of Package pass on the final head: CI, PR Package, and manual Package all completed successfully at 922b6a3945309356d46bc93930297c87c3da4e61.
  • scripts/tests/ci-workflow.test.cjs passes, with the new pin test: node --test scripts/tests/ci-workflow.test.cjs gives 5 passed, 0 failed.

Validation

  • node --test scripts/tests/ci-workflow.test.cjs on 922b6a3 (Node 24.22.1, js-yaml from npm ci --ignore-scripts): 5 passed, 0 failed.

  • The same test file run against main's two workflows: 4 passed, 1 failed (every action reference ... is a full commit SHA, actual - uses: actions/checkout@v4).

  • Both workflows parse with js-yaml and keep their job lists (security-scan, rust, rust-metrics, rust-mutations, build; msix, macos-app, linux-deb).

  • The Rust gates were not run locally, since no Rust file changed. They run in this PR's CI on all three platforms.

  • Hosted validation: all 7 required CI checks passed; all 3 jobs in each Package run passed. There were no Node 20 annotations across all 13 jobs. Other annotations report hosted macOS runner capacity, the Ubuntu image migration, and a metrics fallback to completed base-run coverage after base tests failed. Candidate tests and the declared coverage/CRAP regression gates passed; the baseline-test failure cause was not diagnosed in this change.

  • Reviews: SFL Round 1 PASS and Codex clean receipt both cover the final head. Bot authors, editors and complete edit histories were authenticated; zero unresolved review threads. The SFL Low test-spelling note is nonblocking under the maintainer policy.

Limits

  • actions/setup-dotnet v6.1.0 was exercised successfully by the current CI build job. .github/ and scripts/ changes select retired C# qualification. This step result does not establish that the whole CI run passed.
  • The Upload Gitleaks SARIF step runs only on push, so codeql-action/upload-sarif v4.39.3 first runs on the merge commit's CI on main.

🤖 Generated with Claude Code

Every `uses:` in CI and Package now names a full commit SHA with its
release in a trailing comment, and each action moves to a release whose
action.yml runs on node24:

- actions/checkout v4 -> v7.0.1
- actions/upload-artifact v4 -> v7.0.2
- actions/setup-node v4 -> v7.1.0
- actions/setup-python v5 -> v7.1.0
- actions/setup-dotnet v4 -> v6.1.0
- github/codeql-action/upload-sarif v4 -> v4.39.3
- Swatinem/rust-cache v2 -> v2.9.3

Inputs, triggers, artifact names and paths are unchanged. A new
workflow binding test rejects any action reference that is not a
40-character SHA with a version comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HemSoft HemSoft added the model:claude-opus-5.5 PR authored by claude-opus-5.5 label Nov 6, 2026
@HemSoft

HemSoft commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator Author

@sfl review

@HemSoft

HemSoft commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T01:22:06.161407Z 922b6a3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: 922b6a3945

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@hemsoft-sfl-reviewer hemsoft-sfl-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Verdict: PASS • Round 1

Confidence: 9/10

Review done by claude-opus-5-5 (same family: same-family: codex gated: codex Weekly 171% SUS 59 🔴 pause, defer)

The PR pins all 25 uses: references in ci.yml and package.yml to full commit SHAs on releases that run on node24. It also adds a static test that requires SHA pins with version comments. Every pin resolves to its upstream tag, and the inputs these workflows use still exist at those SHAs. The only finding is a Low gap in how strictly the new test matches uses: lines, so it does not block approval.

🔨 Full-Spectrum Review Summary

Effort: high
Review time: 1m 41s
Token count: Unavailable

Pass 🔴 Critical 🟠 High 🟡 Medium ⚪ Low
🔒 Security 0 0 0 0
✅ Accuracy 0 0 0 0
🧰 Quality & Maintainability 0 0 0 1
Total 0 0 0 1

Key Findings

  1. ⚪ LOW — Quality & Maintainability: Pin test's line filter misses valid YAML step spellings. scripts/tests/ci-workflow.test.cjs:72: The test selects lines with /^\s*(- )?uses:/. A valid YAML step written as - uses: actions/checkout@​v4 (more than one space after the dash), or in flow style - { uses: ... }, is never selected, so a floating tag could pass the test. The test also reads only the hardcoded ci.yml and package.yml, so a new workflow file is not checked. Neither spelling appears in this PR, so current CI is not affected. The impact is weaker protection against future regressions. Parsing the workflows with the js-yaml already loaded in this file and checking every steps[].uses and job-level uses would close the gap. (non-blocking)

Coverage

  • Files reviewed:
    • .github/workflows/ci.yml
    • .github/workflows/package.yml
    • scripts/tests/ci-workflow.test.cjs
  • Context read:
    • AGENTS.md
    • package.json
    • scripts/ci-inputs.py
    • scripts/rust-metrics.py
    • scripts/rust-mutations.py
    • scripts/Invoke-SecurityScan.ps1
    • .github/workflows (directory listing)
    • upstream action.yml at each pinned SHA
    • upstream release notes for checkout v5-v7, upload-artifact v5-v7, setup-node v5-v7, setup-python v6-v7, setup-dotnet v5-v6
  • Verified:
    • Compare base_commit.sha = 7ff35cbe248757d5eb877206f91ec34f982a2069, last commit = 922b6a3945309356d46bc93930297c87c3da4e61, ahead_by 1, behind_by 0
    • Each pinned SHA matches its tag upstream (annotated tags dereferenced for codeql-action v4.39.3 and rust-cache v2.9.3)
    • Each pinned action.yml (including upload-sarif/action.yml) declares runs.using: node24
    • Counted 25 uses: lines at head (17 in ci.yml, 8 in package.yml), all SHA-pinned with matching version comments; only these two workflow files exist
    • Inputs still used (fetch-depth, ref, name, path, retention-days, python-version, dotnet-version, node-version, cache, sarif_file, category) all exist in the pinned action.yml files
    • upload-artifact v7 archive defaults to true, so zipped uploads are unchanged; include-hidden-files default is unchanged
    • checkout allow-unsafe-pr-checkout only affects pull_request_target/workflow_run; these workflows use push, pull_request and workflow_dispatch
    • checkout v6 moves persisted credentials to a separate file and v6.0.1 adds worktree support; rust-metrics.py uses only local git worktree add/remove, rev-parse, diff and ls-files, with no authenticated fetch
    • package.json has no packageManager/devEngines, so setup-node's automatic caching stays off; cache: 'npm' is set explicitly and npm ci --ignore-scripts skips the postinstall script
    • Job names and artifact names are unchanged, so existing tests that check job keys and step names are unaffected
    • PR text says setup-dotnet is not exercised here, but ci-inputs.py needs_retired returns true for .github/ and scripts/ paths, so this PR's CI should select the retired steps and run setup-dotnet v6.1.0. This affects only the PR description, not the code
  • Not verified:
    • Runtime CI or Package results on this head, and whether Node 20 deprecation annotations disappear (execution is forbidden)
    • upload-sarif v4.39.3 behavior, which runs only on push to main
    • GitHub-hosted runner versions against the 2.327.1 minimum (taken from GitHub-hosted runner policy, not checked)
    • Release notes for codeql-action and rust-cache within the same major version were not read in full
  • Tests run: None. Reviewer execution is disabled.

HemSoft full-spectrum review • 3 evidence-based passes • Reviewed head 922b6a3945309356d46bc93930297c87c3da4e61 • SFL v0

@HemSoft
HemSoft merged commit 27d29f2 into main Nov 6, 2026
13 checks passed
@HemSoft
HemSoft deleted the ci/301-pin-node24-actions branch November 8, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model:claude-opus-5.5 PR authored by claude-opus-5.5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update workflow actions that still target Node 20

1 participant