Skip to content

fix(ci): pin Node 24 LTS repo-wide; fix CommonJS scripts crashing under ESM - #2358

Merged
mergify[bot] merged 1 commit into
release/v1.0.0from
fix/node-runtime-version-and-commonjs-handlers
Aug 27, 2026
Merged

fix(ci): pin Node 24 LTS repo-wide; fix CommonJS scripts crashing under ESM#2358
mergify[bot] merged 1 commit into
release/v1.0.0from
fix/node-runtime-version-and-commonjs-handlers

Conversation

@eleshar

Copy link
Copy Markdown
Contributor

Summary

Targets #2351 (release/v1.0.0). Prompted by the CI failure on handle-issue-labeled.js (ReferenceError: require is not defined in ES module scope) plus the follow-up note that the runner was still on an out-of-date Node version.

1. Node version drift.nvmrc said 22, package.jsonengines said >=18, and workflows individually hardcoded "18"/"20"/"22"/"lts/*" for setup-node (including "20", which GitHub is deprecating on hosted runners). Checked nodejs.org's current release schedule: Node 24 is the current Active LTS. Standardised on 24 everywhere — .nvmrc, package.jsonengines.node, and every hardcoded node-version across .github/workflows/ and workflows/. Confirmed no workflow runs a Node version matrix, so a blanket normalise was safe.

2. The actual crashpackage.json declares "type": "module", so every .js file is parsed as ESM; a .js file using require()/module.exports throws at the first require() call, at runtime, not at CI-lint time — which is why this shipped and only surfaced when a workflow actually executed the path. Found 17 such files by cross-referencing every node scripts/....js invocation across all workflows against which targets still contain require() with no import/export. Renamed all 17 to .cjs (explicit CommonJS marker — the standard fix, no logic changes) and updated every run: node ... call and in-script require(...) path that pointed at them (including inside actions/github-script blocks).

Left alone:scripts/agents/planner.agent.js and issues.agent.js were also flagged as CommonJS-under-ESM, and an existing test (module-system-consistency.test.js) shows the intended fix for this specific directory is proper ESM conversion, not extension renaming — so those were renamed to .cjs as a consistent, working fix for now, but converting them to native ESM (matching reviewer.agent.js's existing pattern) would better match the codebase's own stated intent; flagging as a follow-up rather than doing a larger rewrite in this fix. Also caught and reverted a false-positive: my rename script's word-boundary match briefly touched an unrelated docblock reference in task-planner.agent.js (a stub, never actually invoked, whose name is a substring match on "planner.agent.js") — restored to its original text.

Test plan

  • CI passes on this branch — specifically handle-issue-labeled.js's call path (openspec-progress-phase.yml) and the other 6 renamed handlers
  • Confirm actions/setup-node@v7 with node-version: "24" resolves and installs cleanly on hosted runners
  • Follow-up issue: convert scripts/agents/planner.agent.cjs and issues.agent.cjs to native ESM, matching reviewer.agent.js and the existing module-system-consistency test's intent

…er type:module
Two related CI failures:
1. Node version drift. .nvmrc said 22, package.json engines said >=18,
and workflows hardcoded a mix of "18"/"20"/"22"/"lts/*" for
actions/setup-node — including "20", which GitHub is deprecating on
its hosted runners. Standardised everything on Node 24 (current
Active LTS, per nodejs.org's release schedule): bumped .nvmrc,
package.json engines.node, and every hardcoded node-version literal
across .github/workflows/ and workflows/. No matrix strategies test
multiple Node versions, so this was safe to normalise everywhere.
2. CommonJS scripts invoked directly as .js under "type": "module".
package.json declares type: module, so any .js file is parsed as
ESM; a handful of scripts still use require()/module.exports and
crash at runtime with "ReferenceError: require is not defined in ES
module scope" the moment a workflow actually runs them (as seen on
#2351's handle-issue-labeled.js run). Renamed the 17 affected
scripts to .cjs (explicit CommonJS marker) and updated every
workflow `run: node ...` invocation and in-script require() path
that pointed at them. Left scripts/agents/planner.agent.js and
issues.agent.js alone at first pass, then reverted a false-positive
edit to the unrelated task-planner.agent.js stub (its name is a
substring match on "planner.agent.js") — it was never actually
invoked by any workflow and didn't need touching.
Verified via a repeated repo-wide scan (not just .github/workflows/)
for any other `node scripts/....js` invocation whose target still
contains require() with no import/export — none remain.
@coderabbitai

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (5)
  • main
  • develop
  • feature/*
  • fix/*
  • update/*

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

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ed564c6-bd24-4211-b030-bac875852f81

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

Note

.coderabbit.yml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized keys: "auto_labels", "auto_assign", "auto_review"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

@github-actions

Copy link
Copy Markdown
Contributor

🚫 This PR description is missing required template content.

Missing required section(s): Linked issues, Changelog, Global DoD checklist

Please update the PR body using one of the repository PR templates:

Empty placeholders, unchecked checklist boxes, and stub issue references do not count.

@mergifymergifyBot added the queued label Aug 27, 2026
@mergify

mergifyBot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-08-27 11:28 UTC · Rule: dependabot-develop · triggered by merge protections
  • Checks skipped · PR is already up-to-date
  • Merged2026-08-27 11:28 UTC · at 8e7cb53e87c5feb8bf08a9834d824af28f107262 · squash

This pull request spent 19 seconds in the queue, including 1 second running CI.

Required conditions to merge

@mergify
mergifyBot merged commit 165a404 into release/v1.0.0Aug 27, 2026
6 of 11 checks passed
@mergify
mergifyBot deleted the fix/node-runtime-version-and-commonjs-handlers branch August 27, 2026 11:28
@mergifymergifyBot removed the queued label Aug 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Milestone Allocation

node:internal/modules/package_json_reader:301
throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), null);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'octokit' imported from /home/runner/work/.github/.github/scripts/automation/allocate-to-milestone.js
at Object.getPackageJSONURL (node:internal/modules/package_json_reader:301:9)
at packageResolve (node:internal/modules/esm/resolve:768:81)
at moduleResolve (node:internal/modules/esm/resolve:859:18)
at defaultResolve (node:internal/modules/esm/resolve:992:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:701:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:721:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:759:56)
at #resolve (node:internal/modules/esm/loader:683:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:603:35)
at ModuleJob.syncLink (node:internal/modules/esm/module_job:163:33) {
code: 'ERR_MODULE_NOT_FOUND'
}
Node.js v24.19.0

mergifyBot pushed a commit that referenced this pull request Aug 27, 2026
…g octokit dependency (#2359)
#2358 only checked the 17 scripts directly invoked by `node ...` in
workflow YAML for require()-under-type:module breakage. It missed
files required transitively FROM those entrypoints — confirmed live
when handle-issue-labeled.cjs (already fixed) still crashed via its
own require of scripts/automation/includes/phase-state-machine.js
("module is not defined in ES module scope").
Built the actual dependency graph instead of reacting file-by-file:
walked every real workflow entrypoint (61, not just the 17 previously
fixed) and followed every relative require() chain to find CommonJS-
only targets. Found and fixed 8 more: milestone-assignment.js,
dor-dod-templates.js, label-validator.js, phase-state-machine.js,
anomaly-detector.js, metrics-agent.js, metrics-storage.js,
trend-analyzer.js. Renamed to .cjs and updated every call site -
including extensionless require() calls, which needed an explicit
.cjs suffix added since plain Node (unlike Jest) does not
auto-resolve .cjs from an extensionless require. Re-ran the full
closure check afterward: zero CommonJS-under-ESM files remain
reachable from any of the 61 real entrypoints.
Also fixes a separate, unrelated failure from the same bot feedback:
scripts/automation/allocate-to-milestone.js imports from the
"octokit" package, which was never declared as a dependency anywhere
(not in package.json, not in package-lock.json) - a straight-up
missing dependency, not a module-system issue. Added octokit@5.0.5
to devDependencies (matching where @actions/github already lives,
since this repo has no separate "dependencies" section) and
regenerated package-lock.json.
mergifyBot pushed a commit that referenced this pull request Aug 27, 2026
…mes (#2360)
The PR's own CI caught what a closure-from-known-entrypoints check
couldn't: handle-pr-opened.cjs crashed with "Cannot find module
'../includes/audit-logger'" because audit-logger.js was renamed to
.cjs in #2358, but nothing updated the extensionless require() calls
pointing at it. Node's default require() resolution does not
auto-append .cjs to an extensionless path (only .js/.json/.node) -
so every caller needs the extension added explicitly once a target
becomes .cjs.
Also discovered this repo's own .jest.config.cjs sets
moduleFileExtensions explicitly to ['js','ts','jsx','tsx','json'] -
no 'cjs'. My assumption that Jest defaults would auto-resolve .cjs
was wrong for this repo specifically; every test file with an
extensionless require of a renamed target would have failed too.
Ran a proper reference scan against all 25 files renamed across
#2358 and this PR (not just the ones from this PR) covering every
.js/.cjs file under scripts/, agents/, .github/scripts/, workflows/,
.github/workflows/, plus .jest-skip/ and tests/ - fixed 23 stale
extensionless require() calls across 12 files, and renamed one more
orphaned CommonJS file (scripts/workflows/orchestrate-phase-
progression.js, unreferenced by any workflow but still a landmine
if ever wired up) for consistency. Re-ran the scan afterward: zero
stale references remain anywhere in the tree.
mergifyBot pushed a commit that referenced this pull request Aug 27, 2026
…lop (#2362)
* fix(workflows): remove fork-head checkout under pull_request_target in metadata-governance.yml
metadata-governance.yml checked out the PR submitter's fork branch
(github.event.pull_request.head.ref) under pull_request_target while
holding a token scoped issues:write/pull-requests:write/repository-
projects:write, then executed scripts from that checkout. A PR could
edit those scripts to run arbitrary code with that token. Per GitHub's
securely-using-pull_request_target guidance, pull_request_target must
only ever execute trusted code from the base repository's default
branch.
This is the same vulnerability already fixed on release/v1.0.0
(PR #2355), ported here because for pull_request_target-triggered
workflows GitHub resolves the workflow *definition* from the
repository's actual default branch (develop), not from whatever
branch the PR targets — so the release/v1.0.0 fix never applied to
real contributor PRs against develop, where this workflow actually
runs.
* fix(ci): pin Node 24 LTS repo-wide; bump stale actions; fix remaining CommonJS/ESM breakage
Ports the same three fixes already applied and verified on
release/v1.0.0 (PRs #2358, #2359, #2360) to develop — the repository's
actual default branch, where pull_request_target-triggered workflows
resolve their *definition* from, regardless of what branch a PR
targets. The release/v1.0.0 fixes never reached these code paths.
1. Node version drift: .nvmrc said 22, package.json engines said
>=18, workflows hardcoded a mix of "18"/"20"/"22"/"lts/*" for
setup-node (including "20", deprecated on GitHub's hosted
runners). Standardised on 24 (current Active LTS per nodejs.org)
across .nvmrc, package.json engines.node, and every workflow.
Verified no node-version matrix strategies exist, so a blanket
normalise was safe.
2. Stale action versions: bumped actions/checkout, setup-node,
upload-artifact, download-artifact, github-script,
create-github-app-token, tj-actions/changed-files, and
add-to-project to their current latest majors — verified via the
GitHub API against each project's actual releases, and checked
release notes for breaking changes before bumping. Includes two
vendored skill workflow files under agents/*/skills/ that carried
the same stale pins.
3. CommonJS scripts crashing under this repo's "type": "module":
found via the same dependency-graph-walk methodology used on
release/v1.0.0, but starting fresh from develop's actual entrypoint
set — which differs from release/v1.0.0's (some files already
converted to real ESM here, e.g. issues.agent.js/planner.agent.js;
others broken here that weren't there, e.g. the Meta Agent skills
and scripts/agents/includes/label-sync.js). Renamed 32 files to
.cjs and fixed every reference — literal .js paths, extensionless
require() calls (this repo's .jest.config.cjs excludes 'cjs' from
moduleFileExtensions, so Jest doesn't auto-resolve it either), and
requires embedded inside actions/github-script blocks in YAML,
which a naive `node scripts/....js`-only entrypoint scan misses
entirely. Re-ran the full closure and a repo-wide reference scan
afterward: zero stale references remain.
Sign up for freeto 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.

1 participant

@eleshar