Skip to content

chore(opencode): require Node >=22, dropping end-of-life 18 and 20 - #24

Merged
prathamesh-sonpatki merged 4 commits into
masterfrom
coder9io/issue-23
Oct 21, 2026
Merged

prathamesh-sonpatki merged 4 commits into
masterfrom
coder9io/issue-23

Conversation

@coder9io

@coder9io coder9io commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

First part of the eMudhra Node remediation. No Node release contains the fix yet, so this PR does the part that can be done now (drop EOL majors) and records the inventory; pinning the fixed release is the follow-up.

What

  • plugins/opencode-last9/package.json: engines.node >=18 → >=22. Node 18 (EOL 2025-04-30) and 20 (EOL 2026-04-30) will never get the blocklist backport.

Node execution surfaces in this repo

Surface Node source Notes
@last9/opencode-plugin runtime Host OpenCode process (Bun) index.ts only registers the MCP URL and skill paths; it opens no TLS connections. engines.node is advisory.
CI sync-parity job (scripts/check-skill-pack.sh: npm run prepack, npm pack) ubuntu-latest runner default Node No actions/setup-node; packs a local tarball, no runtime HTTPS beyond the runner.
npm publish Not in this repo (release-please.yml only cuts releases) Publisher's Node is outside this repo.
Local dev (npm install, npm test, npm run typecheck) Developer's Node @types/node ^22 already matches the new floor.

No .nvmrc, .node-version, .tool-versions, Dockerfile or container image exists.

Why not pin a fixed release

The upstream fix (nodejs/node#66871, commit d9a3f3d150f7959f2d448d9a61aa11f5a75aa2b3, merged 2026-10-20) is not in any release yet:

  • GET /repos/nodejs/node/compare/<ref>...d9a3f3d1 returns diverged for v26.12.0, v24.22.0, v22.23.3 and for the v26.x, v24.x, v22.x release branches; no backported-to-* labels on the PR.
  • TLS check on the current latest LTS, still unpatched:
$ node --use-env-proxy -e 'fetch(u)…'
v24.22.0 https://dv-g3b-emudhra.we-have-a-problem.com/ OK 200
v24.22.0 https://nodejs.org/ OK 200

Once the first 22.x/24.x/26.x releases carrying the backport ship, the follow-up raises the engines floor to them and repeats this check expecting a certificate error.

Not done here (needs a maintainer)

  • Pinning CI's Node with actions/setup-node would edit .github/workflows/, which I don't change without an explicit request; CI's npm pack makes no external TLS connections that matter here.
  • Republishing the npm package is a release-process step, not a code change.

Tests

Config-only change, no new test. Ran locally: npm test (11/11 pass) and npm run typecheck in plugins/opencode-last9. scripts/check-skill-pack.sh (runs npm pack) is left to CI's sync-parity job. One commit, passing on its own.

Refs #23 (one part; the issue stays open)

Agent usage


Opened by coder9io. Review comments and CI results on this PR are picked up automatically.

Node 18 (EOL 2025-04-30) and 20 (EOL 2026-04-30) will not receive the
eMudhra intermediate SPKI blocklist (nodejs/node#66871), so advertising
them as supported would point users at runtimes that can never be
patched. 22, 24 and 26 are the lines the backport targets.

Refs #23
@coder9io coder9io added the security Security vulnerability or incident label Oct 21, 2026

@reviewer9io reviewer9io 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.

Reviewed the complete change at 18faebe457b31da894d54ba7b8d5284c78715187 and its plugin/packaging consumers. No actionable blocker found. Runtime and dependency declarations are otherwise unchanged.

Fresh Node 22.21.0 verification passed: all 11 existing tests, typecheck, a seeded 40-input URL/configuration probe, and actual npm pack output containing both entrypoints and all 23 canonical skill files. GitHub's exact-head guardrail and skill-sync checks also passed.

The local packaging check used a fresh index of the exported canonical skills. OpenCode/Bun, OAuth and live TLS were not exercised; dependencies are resolved from the repository's unlocked manifest. The engine floor is advisory and this is the documented preparatory change, not evidence that the host runtime already contains the TLS fix.

@nishantmodak

Copy link
Copy Markdown
Member

@coder9io Do not mark this Ready to merge under security issue #23. Raising an advisory engine floor to an unpatched major does not satisfy the issue, and the CI/publishing Node execution surfaces remain unpinned.

Wait for official patched releases, set engines.node to supported fixed minima, pin CI with actions/setup-node to the exact selected release, run tests/typecheck/package validation plus the TLS reject/accept probe, and obtain approval on the final head. Republish the npm artifact through the normal release process afterward.

@coder9io

Copy link
Copy Markdown
Contributor Author

@nishantmodak Question before I continue:

No Node release contains the eMudhra blocklist fix yet (latest is v26.12.0, with no backports labelled on nodejs/node#66871). Should I keep PR #24 open as the holding PR and finish it here once the patched releases ship (re-assign or re-trigger me then)? Or should it be closed, with one complete PR opened later?

Issue #23: Node releases before 22.23.4 and 24.22.1 accept chains
through the revoked eMudhra intermediates. Pin the exact release in
.nvmrc and floor engines.node at the fixed release of each supported
line, excluding lines with no fix.
engines.node becomes ^22.23.4 || ^24.22.1, the first releases carrying
the SPKI blocklist (nodejs/node#66871); Node 26 has no fixed release
yet. .nvmrc pins 24.22.1 as the single exact version for development
and CI. scripts/tls-probe.mjs is the acceptance check: it exits
non-zero unless the eMudhra test endpoint fails with CERT_REVOKED and
a trusted endpoint connects.
CI used the ubuntu-latest default Node, which is unpinned and may
predate the eMudhra fix. Every setup-node step now reads
plugins/opencode-last9/.nvmrc (action pinned by commit), the plugin's
tests and typecheck run in CI, and the TLS probe proves the pinned
release rejects the revoked chain. A test keeps workflows from setting
node-version inline. Kept as the last commit since it edits workflows.
@coder9io

Copy link
Copy Markdown
Contributor Author

Updated to the patched releases (per @nishantmodak in #23):

  • 94fcae5: test/node-version.test.ts. .nvmrc must be an exact release on a patched line. engines.node must equal the fixed floors. Every setup-node step must read .nvmrc.
  • 744e614: .nvmrc = 24.22.1. engines.node = ^22.23.4 || ^24.22.1 (first releases with tls: reject chains containing blocked public keys nodejs/node#66871; Node 26 is excluded because it has no fixed release yet). Adds scripts/tls-probe.mjs. README updated.
  • 2cab2cf: sync-parity (npm pack) and the new opencode-plugin.yml jobs (tests, typecheck, TLS probe) all use actions/setup-node@2499707 (v6.5.0) with node-version-file. Until now, CI ran the runner's default Node.

Node execution surfaces: local dev (.nvmrc), CI sync-parity / npm pack, CI plugin tests. The OpenCode runtime is Bun and the plugin makes no HTTPS calls. There is no Dockerfile or in-repo publish workflow.

Evidence so far: the probe on the unpatched v24.22.0 gets HTTP 200 from dv-g3b-emudhra.we-have-a-problem.com and exits 1. The node-v24.22.1-linux-x64.tar.xz I downloaded matches the published SHASUMS256 (6c172a9a…). The sandbox won't execute that binary, so the CI TLS revocation probe job is the proof: it prints process.version and must show CERT_REVOKED for the eMudhra endpoint and a connection to registry.npmjs.org.

Local: npm test 14/14, npm run typecheck clean. check-skill-pack.sh is left to CI.

After merge, the npm package should be republished through release-please / the normal release process. @reviewer9io please re-review the new head once CI is green. Leaving this PR as not ready until CI and that review are clean.

@coder9io
coder9io requested a review from reviewer9io October 21, 2026 16:51

@reviewer9io reviewer9io 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.

Reviewed the complete current diff at 2cab2cf1c7c15ab05b56dffc16588d8254240e3f. The new jobs and packaging job read the same exact pin, and the engine range excludes unpatched releases. No actionable defect found.

Fresh Node 24.22.1 verification passed: all14 plugin/version tests, typecheck, the actual skill-distribution/npm pack check, and five probes of the real TLS script. The latter mocked fetch and verified that accepted revoked chains, DNS failures, other certificate errors and an unavailable trusted control fail; only CERT_REVOKED plus a successful trusted control passes. Reverting .nvmrc to24.22.0 failed the new test; restored pin tests passed.

All six current-head CI checks are green, including the TLS revocation probe, plugin tests/typecheck and package parity. Live TLS was tested by CI, not locally. OpenCode/Bun, OAuth and publication were not exercised here. There is no committed npm lockfile, so local results cover this run's recorded resolution.

Prior completed inspection is reused only for verified Git-identical plugin/URL/pack code; tests above were freshly executed. Advisory — rollout: republishing and selecting the supported host runtime remain release/operator work; the plugin's advisory engine metadata does not upgrade an existing host.

Coverage

  • Ran: Intent, Correctness and safety, Reliability, Cost and resource, Contract and rollout, Tests, Prior discussion
  • Skipped: Maintainability and design (Small configuration/workflow and standalone probe change.), Guidance compliance (Manifest contains no applicable committed guidance.)

@prathamesh-sonpatki
prathamesh-sonpatki merged commit 7ff760d into master Oct 21, 2026
6 checks passed
coder9io added a commit that referenced this pull request Oct 21, 2026
Node 26.12.1 is the first 26.x release with the eMudhra SPKI blocklist
(a2caddd20e, nodejs/node#66871); before it, engines rejected every
Node 26 install, patched or not. ^26.12.1 floors the line at the fix,
matching 22 and 24.

A fix commit also lets release-please cut a release, so the published
package finally carries the patched engines range: #24 landed as a
chore, which does not trigger one.
nishantmodak pushed a commit that referenced this pull request Oct 22, 2026
…ines (#25)

* chore(opencode): require Node >=22, dropping end-of-life 18 and 20

Node 18 (EOL 2025-04-30) and 20 (EOL 2026-04-30) will not receive the
eMudhra intermediate SPKI blocklist (nodejs/node#66871), so advertising
them as supported would point users at runtimes that can never be
patched. 22, 24 and 26 are the lines the backport targets.

Refs #23

* test(opencode): require a patched Node pin in .nvmrc and engines

Issue #23: Node releases before 22.23.4 and 24.22.1 accept chains
through the revoked eMudhra intermediates. Pin the exact release in
.nvmrc and floor engines.node at the fixed release of each supported
line, excluding lines with no fix.

* chore(opencode): pin Node 24.22.1 and floor engines at eMudhra fixes

engines.node becomes ^22.23.4 || ^24.22.1, the first releases carrying
the SPKI blocklist (nodejs/node#66871); Node 26 has no fixed release
yet. .nvmrc pins 24.22.1 as the single exact version for development
and CI. scripts/tls-probe.mjs is the acceptance check: it exits
non-zero unless the eMudhra test endpoint fails with CERT_REVOKED and
a trusted endpoint connects.

* ci(opencode): run plugin checks and TLS probe on the pinned Node

CI used the ubuntu-latest default Node, which is unpinned and may
predate the eMudhra fix. Every setup-node step now reads
plugins/opencode-last9/.nvmrc (action pinned by commit), the plugin's
tests and typecheck run in CI, and the TLS probe proves the pinned
release rejects the revoked chain. A test keeps workflows from setting
node-version inline. Kept as the last commit since it edits workflows.

* test(opencode): require engines to admit patched Node 26.12.1

Node 26.12.1 (2026-10-21) carries the eMudhra SPKI blocklist
(a2caddd20e, nodejs/node#66871), so Node 26 is now a patched line and
belongs in the floors table that engines.node is derived from.

* fix(opencode): admit patched Node 26.12.1 in engines

Node 26.12.1 is the first 26.x release with the eMudhra SPKI blocklist
(a2caddd20e, nodejs/node#66871); before it, engines rejected every
Node 26 install, patched or not. ^26.12.1 floors the line at the fix,
matching 22 and 24.

A fix commit also lets release-please cut a release, so the published
package finally carries the patched engines range: #24 landed as a
chore, which does not trigger one.

---------

Co-authored-by: coder9io <342252087+coder9io@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security vulnerability or incident

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants