Skip to content

fix(scripts): avoid DEP0190 when spawning .cmd files on Windows (Node.js v24)#62910

Merged
BradGroux merged 2 commits intoopenclaw:mainfrom
nandanadileep:fix/dep0190-shell-true-args
May 8, 2026
Merged

fix(scripts): avoid DEP0190 when spawning .cmd files on Windows (Node.js v24)#62910
BradGroux merged 2 commits intoopenclaw:mainfrom
nandanadileep:fix/dep0190-shell-true-args

Conversation

@nandanadileep
Copy link
Copy Markdown
Contributor

@nandanadileep nandanadileep commented Apr 8, 2026

Summary

Fixes #62881

On Node.js v24, child_process.spawn / spawnSync with { shell: true } and a separate args array triggers DEP0190: Node warns because arguments are only concatenated, not escaped.

In scripts/ui.js, Windows UI runners that resolve to .cmd / .bat launchers (for example pnpm.cmd) used to take the guarded shell: true path and could hit that pattern.

Fix (current): resolveSpawnCall detects Windows .cmd / .bat runner paths (shouldUseCmdExeForCommand) and launches them via ComSpec (cmd.exe) with /d /s /c, using a single command line from buildCmdExeCommandLine (scripts/windows-cmd-helpers.mjs), with shell: false and windowsVerbatimArguments: true. That removes the DEP0190 trigger without ad-hoc string joining and keeps argument boundaries explicit. .exe / .com launchers and non-Windows paths still spawn the resolved executable directly with shell: false.

An earlier revision folded args for shell: true; the branch was rebased onto current main and now follows the shared cmd.exe helper path described in maintainer prep.

Test plan

  • On Windows with Node.js v24, run node scripts/ui.js install — no DEP0190 warning should appear
  • On Windows, run node scripts/ui.js dev and node scripts/ui.js build — UI builds/serves correctly
  • On non-Windows, no behaviour change (cmd.exe wrapping is never taken)
  • pnpm exec oxfmt --check --threads=1 scripts/ui.js test/scripts/ui.test.ts CHANGELOG.md
  • pnpm exec vitest run --config test/vitest/vitest.unit-fast.config.ts test/scripts/ui.test.ts
  • git diff --check

@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts size: XS labels Apr 8, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 8, 2026

Greptile Summary

This PR fixes DEP0190 on Node.js v24 by refactoring createSpawnOptions into resolveSpawnCall, which folds args into the command string when shell: true is required (Windows .cmd/.bat paths), eliminating the spawn(file, args, { shell: true }) pattern that triggers the deprecation warning. The security invariant is preserved — assertSafeWindowsShellArgs runs before the join to reject shell metacharacters.

Confidence Score: 5/5

Safe to merge — the fix correctly eliminates the DEP0190 pattern while preserving the existing security validation.

No P0 or P1 findings. The arg-folding logic is equivalent to what Node.js was doing internally before v24, assertSafeWindowsShellArgs runs before the join, and non-Windows code paths are untouched.

No files require special attention.

Vulnerabilities

No security concerns identified. The assertSafeWindowsShellArgs guard continues to run before args are folded into the shell command string, and the WINDOWS_UNSAFE_SHELL_ARG_PATTERN pattern correctly rejects shell metacharacters ( "&|<>^%!) prior to concatenation.

Reviews (1): Last reviewed commit: "fix(scripts): avoid DEP0190 by folding a..." | Re-trigger Greptile

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 27, 2026

Codex review: needs maintainer review before merge.

Summary
The PR updates scripts/ui.js to launch Windows .cmd/.bat UI runners through cmd.exe with shell: false, adds focused tests, and adds a changelog entry.

Reproducibility: yes. source-backed: current main can select shell: true for Windows UI .cmd/.bat launchers and still pass a separate args array to spawn()/spawnSync(), matching DEP0190. I did not run a live Windows Node 24 repro in this read-only review.

Real behavior proof
Override: The PR has proof: override, so the external after-fix real behavior proof gate is waived despite no posted Windows Node 24 runtime output.

Next step before merge
No repair lane is needed; this is a focused, mergeable implementation PR with no actionable review finding, so maintainers should let CI and merge policy decide.

Security
Cleared: No concrete security or supply-chain regression found; the diff reduces shell-mode process spawning and adds no dependencies, workflows, lockfile, secret, or release-script changes.

Review details

Best possible solution:

Land this refreshed cmd.exe wrapper implementation after required CI/checks pass, or an equivalent patch that removes shell: true from the Windows UI runner path.

Do we have a high-confidence way to reproduce the issue?

Yes, source-backed: current main can select shell: true for Windows UI .cmd/.bat launchers and still pass a separate args array to spawn()/spawnSync(), matching DEP0190. I did not run a live Windows Node 24 repro in this read-only review.

Is this the best way to solve the issue?

Yes: using the existing buildCmdExeCommandLine cmd.exe wrapper with shell: false is the narrow maintainable fix for .cmd/.bat launchers, and .exe/.com plus non-Windows paths remain direct spawns. The remaining work is validation and merge policy, not a different code direction.

What I checked:

  • Current-main warning path: Current main selects shell mode for Windows command launchers and passes the separate args array to spawn()/spawnSync(), matching Node DEP0190's documented runtime-deprecation pattern. (scripts/ui.js:83, ac5acaeb8f68)
  • Node dependency contract: Node's DEP0190 documentation says passing an args array to child_process.spawn or execFile with shell: true is a runtime deprecation because values are space-separated, not escaped.
  • PR head implementation: The PR head resolves .cmd/.bat runners to cmd.exe /d /s /c <command line>, sets shell: false, and enables windowsVerbatimArguments, while leaving direct launchers on argv spawning. (scripts/ui.js:64, c49f3d56fae0)
  • Regression coverage: The refreshed tests cover cmd.exe wrapping, direct .exe/.com and non-Windows launches, and unsafe cmd.exe argument rejection. (test/scripts/ui.test.ts:5, c49f3d56fae0)
  • Shared helper precedent: Current main already uses buildCmdExeCommandLine with cmd.exe, shell: false, and windowsVerbatimArguments in other Windows runner paths, so the PR follows an established local pattern. (scripts/windows-cmd-helpers.mjs:18, ac5acaeb8f68)
  • Changelog coverage: The PR adds a user-facing changelog entry for the Scripts/UI/Windows DEP0190 fix. (CHANGELOG.md:665, c49f3d56fae0)

Likely related people:

  • steipete: Recent GitHub history shows work on Windows UI runner quoting and extraction of the shared cmd.exe helper used by this PR. (role: adjacent Windows process maintainer; confidence: high; commits: 4c7a94aac41e, c88870ac931d, 1de4aff06ddd; files: scripts/ui.js, scripts/windows-cmd-helpers.mjs, scripts/pnpm-runner.mjs)
  • sebslight: Merged history shows the current Windows UI shell-extension guard, unsafe-argument rejection, and focused UI spawn tests trace back to this author. (role: introduced current guarded Windows shell behavior; confidence: high; commits: bbb5fbc71f1a; files: scripts/ui.js, test/scripts/ui.test.ts)
  • BradGroux: PR comments and current PR commits show this maintainer refreshed the branch, replaced the older workaround with the shared cmd.exe helper path, and reported focused validation. (role: recent maintainer prep and likely follow-up owner; confidence: medium; commits: ef38ec71e7f1, c49f3d56fae0; files: scripts/ui.js, test/scripts/ui.test.ts, CHANGELOG.md)

Remaining risk / open question:

  • No live Windows Node 24 runtime output is posted; the proof: override label waives that contributor proof gate for maintainer handling.
  • The PR head is close to current main and reports clean mergeability, but final landing should still wait for the fresh required checks mentioned by the maintainer refresh comment.

Codex review notes: model gpt-5.5, reasoning high; reviewed against ac5acaeb8f68.

@BradGroux BradGroux force-pushed the fix/dep0190-shell-true-args branch from fc2d117 to 87ace89 Compare May 6, 2026 05:34
@BradGroux BradGroux added the proof: override Maintainer override for the external PR real behavior proof gate. label May 6, 2026
@BradGroux
Copy link
Copy Markdown
Member

BradGroux commented May 6, 2026

Maintainer prep complete for #62910.

What changed:

  • Rebased/reseated the PR onto current main and replaced the submitted args.join(" ") shell workaround with the shared buildCmdExeCommandLine path.
  • Windows .cmd/.bat UI runner calls now spawn cmd.exe /d /s /c <escaped command line> with shell: false and windowsVerbatimArguments: true, preserving argument boundaries and avoiding Node.js v24 DEP0190.
  • Ordinary .exe launchers and non-Windows launches remain direct spawns.
  • Added focused regression coverage and changelog.

Prepared head: 87ace89dca4f3620bba8b6d699cad061023aa0f1
Previous head: fc2d117ecf34077bddd041cf9d9e91b4c603cc41

Verification:

  • pnpm install --frozen-lockfile passed
  • pnpm exec oxfmt --check --threads=1 scripts/ui.js test/scripts/ui.test.ts CHANGELOG.md passed
  • pnpm exec vitest run --config test/vitest/vitest.unit-fast.config.ts test/scripts/ui.test.ts passed (4 tests)
  • git diff --check passed

Notes:

  • pnpm test test/scripts/ui.test.ts test/scripts/pnpm-runner.test.ts ran test/scripts/ui.test.ts successfully, then the tooling shard failed before collecting test/scripts/pnpm-runner.test.ts with TypeError: Class extends value undefined is not a constructor or null from test/non-isolated-runner.ts.
  • pnpm check:changed failed in lint:scripts during plugin-sdk boundary artifact preparation with broad dependency/type-resolution errors (for example missing typebox and @openclaw/fs-safe/* declarations), unrelated to this three-file UI runner change.
  • Added proof: override because live Windows Node 24 proof is unavailable from this maintainer macOS workspace; the regression tests cover the exact spawn spec.

Re-review progress:

@BradGroux BradGroux force-pushed the fix/dep0190-shell-true-args branch from 87ace89 to bb4f159 Compare May 6, 2026 07:41
@BradGroux
Copy link
Copy Markdown
Member

Maintainer refresh: rebased the prepared branch onto current main after main moved.\n\nNew prepared head: bb4f1598abed90a276578c22f4454aaa6123cff4\nPrevious prepared head: 87ace89dca4f3620bba8b6d699cad061023aa0f1\n\nFocused verification after refresh:\n- pnpm exec oxfmt --check --threads=1 scripts/ui.js test/scripts/ui.test.ts CHANGELOG.md passed\n- pnpm exec vitest run --config test/vitest/vitest.unit-fast.config.ts test/scripts/ui.test.ts passed (4 tests)\n- git diff --check passed\n\nFresh CI is running on the refreshed head.

@nandanadileep nandanadileep force-pushed the fix/dep0190-shell-true-args branch from bb4f159 to f9aba20 Compare May 6, 2026 17:47
@nandanadileep
Copy link
Copy Markdown
Contributor Author

nandanadileep commented May 6, 2026

@greptile-apps[bot] Thanks for the review — the Greptile summary matches an older head (it references the resolveSpawnCall + folded shell: true approach and commit 84a74625c3682d7ff2d045732ffb2701d0426239).

The branch has been rebased onto current main and the implementation now matches what maintainers landed afterward: Windows .cmd / .bat UI runners go through cmd.exe /d /s /c + buildCmdExeCommandLine with shell: false and windowsVerbatimArguments: true in scripts/ui.js, so DEP0190 is avoided without passing a separate args array alongside shell: true. Focused coverage lives in test/scripts/ui.test.ts.

If you want an updated bot pass, a Greptile re-trigger on the refreshed head should re-summarize against the current diff.

Re-review progress:

@BradGroux BradGroux force-pushed the fix/dep0190-shell-true-args branch from f9aba20 to 252f744 Compare May 8, 2026 06:26
@BradGroux
Copy link
Copy Markdown
Member

Maintainer prep refresh for #62910.

Prepared head: 252f744c232fbeb0282a4175fc570a457ae1eda6

What I changed:

  • Rebased onto current origin/main.
  • Resolved the test/scripts/ui.test.ts rebase conflict by keeping current test structure and preserving the new cmd.exe/shell:false Windows launcher coverage.
  • Moved the changelog entry to the SOP-required tail position for the current section.

Verification:

  • node scripts/test-projects.mjs test/scripts/ui.test.ts passed (4 tests).
  • pnpm build passed.
  • pnpm check passed.

Fresh CI should start on the prepared head. Not merging until required/full checks are green.

@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label May 8, 2026
@BradGroux BradGroux force-pushed the fix/dep0190-shell-true-args branch from 4fd2844 to c49f3d5 Compare May 8, 2026 23:13
@openclaw-barnacle openclaw-barnacle Bot removed the agents Agent runtime and tooling label May 8, 2026
@BradGroux
Copy link
Copy Markdown
Member

Maintainer refresh:

  • Rebasing this PR onto current origin/main completed successfully.
  • Prepared head is now c49f3d56fae0d4d2af9f0b19a60bd49b169317ce.
  • The import-cycle cleanup commit from the older PR branch was already present upstream, so the refreshed branch now keeps only the Windows .cmd/.bat runner fix plus the changelog entry.

Local verification passed:

pnpm install --frozen-lockfile
pnpm exec oxfmt --check --threads=1 scripts/ui.js test/scripts/ui.test.ts CHANGELOG.md
node scripts/test-projects.mjs test/scripts/ui.test.ts
pnpm build
pnpm check

I’ll wait for fresh GitHub checks before merging.

@BradGroux BradGroux merged commit 5adbbaa into openclaw:main May 8, 2026
88 of 90 checks passed
@BradGroux
Copy link
Copy Markdown
Member

Merged with squash after the refreshed head c49f3d56fae0d4d2af9f0b19a60bd49b169317ce passed local maintainer verification and fresh GitHub checks, including Real behavior proof and ClawSweeper-related gates.

Merge commit: 5adbbaa3cbcc20df26d5425318dbb71d2962fa55

Linked issue #62881 was already closed, and this landing keeps the Windows .cmd/.bat UI runner fix in the main branch with contributor attribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

proof: override Maintainer override for the external PR real behavior proof gate. scripts Repository scripts size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Node.js v24] DEP0190 DeprecationWarning: spawn with shell:true + args array on gateway startup

2 participants