Skip to content

ci: clear Node 20 deprecation warnings by bumping action runtimes - #1407

Merged
clay-good merged 2 commits into
mainfrom
ci/node24-actions-sweep
Jul 22, 2026
Merged

ci: clear Node 20 deprecation warnings by bumping action runtimes#1407
clay-good merged 2 commits into
mainfrom
ci/node24-actions-sweep

Conversation

@clay-good

@clay-good clay-good commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Status: Ready for review. Follow-up to the sweep suggested by @TabishB in #1406 review. Version-tag bumps plus one review-driven hardening — no workflow logic, job structure, or filenames change.

What was missing / the motivation: Every JS action we use except changesets/action still declares a Node 20 runtime. GitHub deprecated Node 20 on runners (2025-09-19 changelog): since June 16, 2026 these actions are force-run on Node 24 with the warning quoted in #1406, and on September 16, 2026 Node 20 is removed from runners entirely. The devcontainer also pinned a Node 20 image (Node 20 is EOL since April 2026).

What it does: Bumps each action to its current Node 24 major, verified against each action's action.yml and release notes before choosing the target:

Action From → To Why this major
actions/checkout v4 → v5 Runtime-only bump. v6 also relocates persisted credentials — deliberately avoided near the changesets push path.
actions/setup-node v4 → v6 Caching-default changes in v5/v6 don't apply because every call site sets cache: 'pnpm' explicitly. node-version and registry-url inputs unchanged.
pnpm/action-setup v4 → v6 Resolves pnpm from packageManager: "pnpm@9.15.9" exactly as before; no call site passes a version input.
actions/upload-artifact v4 → v6 v5 still declares node20. v6 inputs are identical to v4's.
dorny/paths-filter v3 → v4 Inputs identical.
actions/create-github-app-token v2 → v3 v3 only removed custom proxy handling; we use hosted runners, no proxy.
changesets/action v1 (unchanged) Floating v1 already runs on node24.

Also bumps .devcontainer image typescript-node:1-20-bookworm1-22-bookworm.

Per CodeRabbit's review, the five ci.yml checkouts now set persist-credentials: false — safe because every ci.yml job is read-only after checkout (the changeset-validation job's git diff origin/main...HEAD works off fetch-depth: 0, fetched during the checkout action itself). The equivalent restructure in release-prepare.yml was deliberately declined there: its persisted App token is intentional (#477/#478 — changesets pushes must trigger CI) and unverifiable from a PR.

Deliberately untouched: node-version: '20.19.0' in CI (floor-testing the declared engines: >=20.19.0 support contract — the runtime warnings are about the actions' own runtime, which is orthogonal), node-version: '24' in release, package.json engines, docs, and the release-prepare.yml filename (npm trusted publishing binds to repo + workflow filename, not to action versions inside it).

Proof it works: This PR edits ci.yml, so the full CI matrix — including nix-flake-validate via the paths filter — runs on these exact changes. Caveat: the release-prepare path only executes on the next version PR / beta dispatch; the bumps there are tag-only with inputs verbatim.

Notes: The repo has no .github/dependabot.yml, which is why six actions aged into deprecation together — happy to add a monthly github-actions ecosystem entry in a follow-up if wanted.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated the development container to use a newer TypeScript/Node toolchain.
    • Refreshed CI tooling versions for test runs, linting, artifact uploads, and change-detection.
    • Updated the release preparation workflows for improved compatibility and continued reliable execution (including GitHub App token creation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The development container now uses Node 22, while CI and release workflows upgrade their GitHub Actions, pnpm setup, Node setup, path filtering, artifact upload, and GitHub App token actions.

Changes

Runtime and workflow action upgrades

Layer / File(s) Summary
Development container runtime
.devcontainer/devcontainer.json
The base TypeScript/Node image changes from the Node 20-based bookworm variant to the Node 22-based variant.
CI action upgrades
.github/workflows/ci.yml
CI jobs upgrade checkout, path filtering, pnpm setup, Node setup, and coverage artifact upload actions.
Release workflow action upgrades
.github/workflows/release-prepare.yml
Prepare and beta jobs upgrade GitHub App token, checkout, pnpm setup, and Node setup actions.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested reviewers: tabishb

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: updating CI action runtimes to address Node 20 deprecation warnings.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/node24-actions-sweep

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 28: Update checkout steps at .github/workflows/ci.yml:28-28,
.github/workflows/ci.yml:71-71, .github/workflows/ci.yml:126-126,
.github/workflows/ci.yml:168-168, and .github/workflows/ci.yml:226-226 to set
persist-credentials to false. In .github/workflows/release-prepare.yml:32-35 and
.github/workflows/release-prepare.yml:73-75, keep App and default GitHub tokens
unavailable during dependency installation, then explicitly re-authenticate
immediately before the changesets/tag-push release step.

In @.github/workflows/release-prepare.yml:
- Around line 27-30: Update the actions/create-github-app-token@v3 step to add
explicit permission-* inputs, granting only the minimum repository permissions
required by the workflow’s checkout, version-update, and release steps. Remove
reliance on the GitHub App installation’s inherited full permission set while
preserving the existing app-id and private-key configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f44614a-ba40-42f0-a13e-8fa10dfdaf58

📥 Commits

Reviewing files that changed from the base of the PR and between 60f720c and 2736c1f.

📒 Files selected for processing (3)
  • .devcontainer/devcontainer.json
  • .github/workflows/ci.yml
  • .github/workflows/release-prepare.yml

Comment thread .github/workflows/ci.yml
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5

@coderabbitai coderabbitai Bot Jul 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== ci.yml ==\n'
nl -ba .github/workflows/ci.yml | sed -n '1,260p'

printf '\n== release-prepare.yml ==\n'
nl -ba .github/workflows/release-prepare.yml | sed -n '1,220p'

Repository: Fission-AI/OpenSpec

Length of output: 211


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 4 'actions/checkout@v5|persist-credentials|token:|git push|changesets|release' .github/workflows/ci.yml .github/workflows/release-prepare.yml

Repository: Fission-AI/OpenSpec

Length of output: 15174


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== ci.yml top ==\n'
sed -n '1,90p' .github/workflows/ci.yml

printf '\n== release-prepare.yml relevant sections ==\n'
sed -n '1,190p' .github/workflows/release-prepare.yml

Repository: Fission-AI/OpenSpec

Length of output: 8951


Avoid persisting checkout credentials during installs. actions/checkout writes the token into git config by default, so pnpm install runs with writable release credentials in both release-prepare jobs. Set persist-credentials: false on the CI checkouts, and in release-prepare.yml authenticate only for the changesets/tag-push steps.

  • .github/workflows/ci.yml: add persist-credentials: false to the checkout steps.
  • .github/workflows/release-prepare.yml: don’t keep the App token or default GITHUB_TOKEN available during dependency install; re-authenticate right before the git push / release step.
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 27-28: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 2 files
  • .github/workflows/ci.yml#L28-L28 (this comment)
  • .github/workflows/ci.yml#L71-L71
  • .github/workflows/ci.yml#L126-L126
  • .github/workflows/ci.yml#L168-L168
  • .github/workflows/ci.yml#L226-L226
  • .github/workflows/release-prepare.yml#L32-L35
  • .github/workflows/release-prepare.yml#L73-L75
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml at line 28, Update checkout steps at
.github/workflows/ci.yml:28-28, .github/workflows/ci.yml:71-71,
.github/workflows/ci.yml:126-126, .github/workflows/ci.yml:168-168, and
.github/workflows/ci.yml:226-226 to set persist-credentials to false. In
.github/workflows/release-prepare.yml:32-35 and
.github/workflows/release-prepare.yml:73-75, keep App and default GitHub tokens
unavailable during dependency installation, then explicitly re-authenticate
immediately before the changesets/tag-push release step.

Source: Linters/SAST tools

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Applied the ci.yml half: all five checkouts now set persist-credentials: false — safe because every ci.yml job is read-only after checkout (the one git diff origin/main...HEAD consumer uses fetch-depth: 0, so all refs land during the checkout action itself; dorny/paths-filter authenticates via its API token input, not git config).

Deliberately NOT restructuring release-prepare.yml auth in this PR: the App token in those checkouts is intentional (see #477/#478 — changesets pushes must be authored by the App so they trigger CI), the release path only executes on the next version PR / beta dispatch so a restructure is unverifiable from this PR, and this configuration predates the version bumps here. Happy to tackle it as its own reviewed change if the maintainers want.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@clay-good, confirmed: all five CI checkout steps now disable credential persistence, and the fetch-depth: 0 checkout preserves the origin/main...HEAD validation path.

Your rationale for keeping the intentionally App-authenticated release-prepare.yml flow out of this action-version PR is reasonable. The remaining release-token hardening is best evaluated and validated as a dedicated change, since preserving App-authored Changesets pushes is a functional requirement.

Would you like me to open a follow-up GitHub issue for that review?

🐇 💭


✏️ Learnings added
Learnt from: clay-good
Repo: Fission-AI/OpenSpec PR: 1407
File: .github/workflows/ci.yml:28-28
Timestamp: 2026-07-21T14:07:08.006Z
Learning: In `.github/workflows/release-prepare.yml`, the checkout’s GitHub App token is intentionally persisted because Changesets tag/release pushes must be authored by the GitHub App to trigger CI (referenced as GitHub issues `#477` and `#478`). Any authentication hardening there must preserve that App-authored push behavior and should be evaluated as a separately validated change.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +27 to 30
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}

@coderabbitai coderabbitai Bot Jul 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

actions/create-github-app-token v3 permissions inputs install token inherits all permissions

💡 Result:

In the actions/create-github-app-token action, including v3, the token inherits all permissions from the app installation by default if no specific permission-* inputs are provided [1][2][3]. When you explicitly define permission-* inputs, the action limits the generated token's permissions to the specified subset [3]. If you provide no permission-* inputs, the action defaults to requesting a token with all permissions currently granted to the GitHub App installation [1][3]. Important points regarding this behavior: 1. Inheritance: If no permission-* inputs are set, the action generates a token with the full set of permissions defined in the app installation [1][2][3]. 2. Restriction: If you use the permission-* inputs, the generated token is restricted to the permissions you explicitly defined [3]. These defined permissions must still be a subset of the permissions already granted to the app installation; otherwise, the action will return an error [1][2][4]. 3. Best Practice: The action's documentation recommends explicitly listing only the permissions required for your specific use case to follow the principle of least privilege, rather than relying on the default inheritance of all permissions [1][2].

Citations:


Restrict the GitHub App token permissions.

Without permission-* inputs, create-github-app-token@v3 inherits the app installation’s full permission set. Limit it to the minimum needed for checkout, version updates, and releases.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 27-27: dangerous use of GitHub App tokens (github-app): app token inherits blanket installation permissions

(github-app)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-prepare.yml around lines 27 - 30, Update the
actions/create-github-app-token@v3 step to add explicit permission-* inputs,
granting only the minimum repository permissions required by the workflow’s
checkout, version-update, and release steps. Remove reliance on the GitHub App
installation’s inherited full permission set while preserving the existing
app-id and private-key configuration.

Source: Linters/SAST tools

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declining in this PR, with reasoning: the unscoped App token predates this change (v2 had the same default — the bump to v3 doesn't widen anything), and scoping it needs knowledge of the App installation's actual permission set plus a live release run to validate — neither is available from this PR (the release path only executes on the next version PR / beta dispatch). Getting the permission-* scopes wrong here would break version-PR creation or tag pushes silently. Flagging it to the maintainers as a candidate follow-up: likely permission-contents: write + permission-pull-requests: write, validated against a real release cycle.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@clay-good, agreed—this is pre-existing configuration rather than a permission expansion caused by the v2v3 upgrade. Deferring explicit App-token scoping until the installation permissions and a real release-path validation are available is reasonable.

Would you like me to open a follow-up GitHub issue for the least-privilege hardening, including validation of permission-contents: write and permission-pull-requests: write against an actual release cycle?

🐇💭


✏️ Learnings added
Learnt from: clay-good
Repo: Fission-AI/OpenSpec PR: 1407
File: .github/workflows/release-prepare.yml:27-30
Timestamp: 2026-07-21T14:07:13.648Z
Learning: In `.github/workflows/release-prepare.yml`, the `prepare` job’s GitHub App token intentionally remains unscoped during the `actions/create-github-app-tokenv2` to `v3` upgrade because this is pre-existing behavior, not a regression. Explicit `permission-*` scopes should be handled as a separate hardening task after confirming the GitHub App installation permissions and validating version-PR creation and tag pushes through a real release cycle.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 37cebb7. Each bumped tag exists and declares node24, the inputs used here remain compatible, CI checkouts no longer persist credentials, the clean build passes, and the full exact-head CI, Nix, CodeQL, and CodeRabbit matrix is green.

@clay-good
clay-good added this pull request to the merge queue Jul 22, 2026
Merged via the queue into main with commit d3a9982 Jul 22, 2026
14 checks passed
@clay-good
clay-good deleted the ci/node24-actions-sweep branch July 22, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants