Skip to content

chore(ci): pin CI/publish Node to 24.22.3 (floor 22.23.5), raise engines floor - #571

Open
SavioBS629 wants to merge 2 commits into
browserstack:mainfrom
SavioBS629:security/pin-node-24-engines
Open

SavioBS629 wants to merge 2 commits into
browserstack:mainfrom
SavioBS629:security/pin-node-24-engines

Conversation

@SavioBS629

@SavioBS629 SavioBS629 commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

What

Stop building, testing, and publishing on floating and EOL Node tags, and raise the engines floor. Changes:

  • .github/workflows/mcp-ci.yml — test matrix [22.x] → [22.23.5, 24.22.3] (stays a matrix; both run)
  • .github/workflows/npm-publish.yml — 22.x → 24.22.3
  • .github/workflows/beta-release.yml — 22.x → 24.22.3
  • .github/workflows/bump-version.yml — 22.x → 24.22.3, and pin actions/setup-node to its v4.4.0 SHA (was the moving @v4 tag; now matches the other workflows)
  • .github/workflows/mcp-registry-publish.yml — "lts/*" → 24.22.3
  • package.json — engines.node ">=20.9.0" → ">=22.23.5"
  • .nvmrc — v22.1.0 → 24.22.3 (local dev default now matches the target)
  • README.md / llms-install.md — stated Node floor refreshed off 20.9 / 22.15.0

Target Node is 24.22.3; 22.23.5 is the supported floor. All pins are exact — no floating tags (22.x, lts/*, @v4).

Why

22.x and lts/* are floating: they resolve to whatever Node the runner last cached, and lts/* will roll onto the next LTS line on its own. That non-determinism is the problem — it can silently land CI/publish on an unpatched or wrong-major runtime. Pinning to the current patch releases (24.22.3 / 22.23.5, both shipped this week) makes CI, publish, and release builds deterministic and keeps them on supported, patched Node.

Advisory, not breaking

The engines field stays advisory — no engine-strict, no .npmrc change:

  • npm / npx / pnpm on a below-floor Node print an EBADENGINE warning and install/run normally.
  • Yarn Classic (v1), and any consumer with engine-strict=true, will fail the install on the mismatch (--ignore-engines overrides). Rare for an npx-launched MCP server, but a real hard failure — called out here and worth a line in release notes.

src/lib/node-version-notice.ts is intentionally left unchanged. Its in-client notice fires below major 22, which is looser than the >=22.23.5 floor — users on 22.0–22.23.4 get npm's install warning but no in-client notice. Deliberate: the notice nudges off EOL majors; the exact patch floor is advisory via engines.

Pin maintenance

Exact pins go stale on each Node security release. This PR keeps explicit exact pins per the requirement (no floating tags). Centralizing future bumps — e.g. a Dependabot/Renovate rule for workflow node-version and the actions/* SHAs — is a sensible follow-up, out of scope here.

Validation

Full build + test + boot run locally on both pinned versions (fresh npm ci each):

Stage Node 22.23.5 Node 24.22.3
npm ci clean, 0 EBADENGINE clean
npm test (vitest) 143 files / 2112 pass 143 files / 2112 pass
npm run check:contract OK OK
tsc build OK OK
stdio boot — initialize + tools/list 52 tools, 0 bad schemas 52 tools, 0 bad schemas
  • No test failures on either target. (Earlier reports of ~27 failing fake-timer cases were Node-20-and-earlier artifacts; they pass on 22/24.)
  • Advisory floor confirmed: on Node 22.18.0 (below floor) npm ci emits only an EBADENGINE warning and installs.
  • Branch merges cleanly with main (no conflicts).
  • Repo CI has not run on this PR yet (gated on reviewer approval); it will exercise the full 22.23.5 + 24.22.3 matrix once approved.

🤖 Generated with Claude Code

…to 22.23.4

CI, publish, and release workflows were building, testing, and publishing
on floating and EOL Node tags (22.x, lts/*), which can silently resolve to
Node releases carrying known CVEs. Following the October-2026 Node security
release that fixed the Brotli decoder out-of-bounds write (CVE-2026-111497),
this pins every workflow to Node 24.22.1 and runs CI against a fixed
matrix of 22.23.4 (supported floor) and 24.22.1 (target).

- .github/workflows/mcp-ci.yml: matrix node-version [22.x] -> [22.23.4, 24.22.1]
- .github/workflows/npm-publish.yml: 22.x -> 24.22.1
- .github/workflows/beta-release.yml: 22.x -> 24.22.1
- .github/workflows/bump-version.yml: 22.x -> 24.22.1
- .github/workflows/mcp-registry-publish.yml: "lts/*" -> 24.22.1
- package.json: engines.node ">=20.9.0" -> ">=22.23.4"

The engines field stays advisory (no engine-strict / .npmrc), so customers
on older Node get a warning, not a hard install failure. node-version-notice.ts
is intentionally left unchanged: its major-22 floor is correct now that Node 22
LTS is patched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto (fallback from Default branch)
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Central YAML (base), Organization UI (inherited), Workspace UI (inherited); Enforced overrides: Organization
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: f46cf0be-b053-416b-ac90-b017dd8e1f24

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@sarve-shreyas sarve-shreyas 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 the full diff at d2e9c43 (6 one-line changes vs main; it merges cleanly with current main).

Verified: both pinned versions exist and are the 2026-10-20 security releases, and both carry the CVE-2026-111497 Brotli fix named in the description (checked against the Node changelogs).

Local run (stand-in for the CI matrix): on Node 24.7.0 (npm 11), npm ci, eslint and tsc --noEmit pass, and vitest passes 143 files / 2112 tests. On Node 22.15.0, tsc passes, all 2112 tests pass and npm run check:contract passes. I didn't have 22.23.4 or 24.22.1 installed, so these are same-major stand-ins. There were no failures at all on 22 or 24, so the ~27 failures in the description look specific to Node 20.9.0.

Note: mcp-ci.yml only runs on an approved review (pull_request_review + state == 'approved'), so the new matrix hasn't run on this PR yet. It first runs when someone approves.

Findings outside the diff (non-blocking):

  • .nvmrc is still v22.1.0, below the new floor and older than the Brotli fix. nvm use in the repo puts devs on a runtime this PR calls vulnerable, and npm prints EBADENGINE. Bump it with the rest. It could also become the single pin the workflows read (see the inline comment on npm-publish.yml).
  • package-lock.json still has >=20.9.0 in the root packages[""].engines. npm ci doesn't care (it only compares dependency versions, and it installed fine on Node 24), but the next npm install rewrites it and an unrelated PR picks up the change. npm install --package-lock-only fixes it here.
  • The docs disagree with the new floor: llms-install.md:12 says "Node.js 20.9 or newer", and README.md:57-58 says ">= 22" and recommends v22.15.0, which is below the new floor.
  • Nit, pre-existing: bump-version.yml pins actions/setup-node@v4 by tag, not by SHA like the other four workflows. Optional while you're in there.

Comment thread .github/workflows/mcp-ci.yml Outdated
strategy:
matrix:
node-version: [22.x]
node-version: [22.23.4, 24.22.1]

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.

Blocking: these pins are already one security release behind. Node shipped 24.22.3 (2026-11-10) and 22.23.5 (2026-11-11). Both are marked as security releases in nodejs.org/dist/index.json and fix a batch of High-severity http2/tls/http CVEs (e.g. CVE-2026-123864 and CVE-2026-123872; 24.22.3 also fixes CVE-2026-126051, a remotely reachable TLS server crash).

Scenario: if this merges as-is, CI, npm publish, beta release, version bump and registry publish all run on runtimes that a newer Node security release replaces. The description sets out to prevent exactly that.

Suggestion: bump to 22.23.5 / 24.22.3 here and in the four other workflows. If you keep the engines floor patch-precise, bump it too (see the comment on package.json).

Comment thread package.json Outdated
],
"engines": {
"node": ">=20.9.0"
"node": ">=22.23.4"

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.

Non-blocking: two things about the floor.

  1. Because it's patch-precise, it goes stale with every Node security release (22.23.5 already replaces 22.23.4). If the goal is "run a patched Node", the CI pins already do that. The advisory floor could stay at a release-line boundary such as >=22, which also matches node-version-notice.ts, so it doesn't need a bump every month. If you'd rather keep it patch-precise, make it >=22.23.5.
  2. "Never a hard failure" only holds with the default npm config. Consumers who set engine-strict=true themselves (some enterprise setups do) will get EBADENGINE as an error when they run npx @browserstack/mcp-server on Node 20 or on 22 below the floor. Worth a line in the release notes for the version that ships this.

Comment thread .github/workflows/npm-publish.yml Outdated
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22.x
node-version: 24.22.1

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.

Non-blocking: 24.22.1 is now hardcoded in four workflows, plus two versions in the CI matrix, and nothing bumps them. Every Node security release means editing six places, and missing one puts us back where the comment on mcp-ci.yml is. Two options:

  • Put the target in .nvmrc (still v22.1.0 today) and use node-version-file: .nvmrc in the publish and release workflows. A bump is then one line, and local nvm use matches what we publish with.
  • Or keep a release-line spec (24.x) and add check-latest: true. A spec like 22.x lags because setup-node uses the runner image's cached Node first when check-latest is false (the default). With it on, every run resolves the newest patch. Less deterministic, but never stale.

Either is fine; the first matches the PR's goal of deterministic builds.

uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: "lts/*"
node-version: 24.22.1

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.

Non-blocking (description accuracy): lts/* wasn't EOL. Node 26 became LTS on 2026-10-28, so this workflow currently runs on 26.13.1, and this change moves it back to 24. That's fine if the intent is one runtime across all publish jobs, but the description should say so rather than "EOL". The same goes for 22.x: Node 22 is in maintenance LTS until April 2027.

@SavioBS629 SavioBS629 changed the title chore(security): pin CI/publish Node to 24.22.1, raise engines floor to 22.23.4 chore(ci): pin CI/publish Node to 24.22.1, raise engines floor to 22.23.4 Nov 12, 2026
…eases)

Node shipped 24.22.3 (Nov 10) and 22.23.5 (Nov 11) as security releases.
Move every pinned runtime onto them so CI, publish, and release builds stay
on current, patched Node.

- mcp-ci matrix -> [22.23.5, 24.22.3]
- npm-publish / beta-release / bump-version / mcp-registry-publish -> 24.22.3
- bump-version: pin actions/setup-node to its v4.4.0 SHA (was moving @v4)
- engines floor -> >=22.23.5 (advisory; no engine-strict)
- .nvmrc -> 24.22.3 (was v22.1.0); README / llms-install doc floor refreshed

Exact pins, no floating tags. Full build/test/boot verified on Node 22.23.5
and 24.22.3: 2112 tests, contract gate, tsc, and a stdio initialize+tools/list
handshake (52 tools) all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@SavioBS629 SavioBS629 changed the title chore(ci): pin CI/publish Node to 24.22.1, raise engines floor to 22.23.4 chore(ci): pin CI/publish Node to 24.22.3 (floor 22.23.5), raise engines floor Nov 12, 2026

@sarve-shreyas sarve-shreyas 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.

Approved at 26c1216.

Re-reviewed d2e9c43..26c1216. At this head, npm ci, tsc --noEmit, vitest (143 files / 2112 tests) and npm run check:contract pass on Node 24.7.0.

Resolved:

  • All six pins are now 22.23.5 / 24.22.3, the latest Node security releases as of today.
  • .nvmrc is now 24.22.3.
  • The README and llms-install.md give the new minimum.
  • The lockfile root engines matches package.json.
  • bump-version.yml pins setup-node by SHA.
  • The description has the engine-strict/Yarn caveat and the note on the in-client notice.

Accepted as-is: exact pins in each workflow rather than one node-version-file (the ticket requires exact pins), and the patch-precise >=22.23.5 minimum (advisory, documented). The follow-up for automated bumps (Renovate/Dependabot) is noted in the description.

Nit, no change needed to merge: the first line of the description still says "floating and EOL Node tags".

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