Files
OmniRoute/tests/unit/cli/_helpers/shellArgs.mjs
Diego Rodrigues de Sa e Souza 2904cf849d fix(security): clear new CodeQL code-scanning alerts (round 4) (#11293)
- open-sse/executors/github.ts: replace the Math.random() fallback in
  the Copilot correlation-id generators (x-request-id,
  x-interaction-id, x-client-session-id, x-agent-task-id) with a
  CSPRNG-backed randomIdFallback() (node:crypto randomBytes) — closes
  js/insecure-randomness with no behavior change (crypto.randomUUID
  stays the primary path).
- tests/unit/cli/_helpers/shellArgs.mjs: collapse the two sequential
  global .replace() unescape passes into a single left-to-right regex
  replace with alternation — closes js/double-escaping. The prior
  two-pass form let the first pass's output feed the second, which is
  exactly the double-(un)escaping bug pattern the query flags (e.g. an
  escaped-backslash-then-quote sequence could be misread depending on
  pass order).

Co-authored-by: Markus Hartung <mail@hartmark.se>
2026-08-23 19:06:53 -03:00

45 lines
1.8 KiB
JavaScript

/**
* Reverse the Windows `shell: true` argument escaping so assertions can be
* written against the logical argv on every platform.
*
* `bin/cli/commands/run.mjs` escapes argv before spawning, because on win32 the
* launchers must go through cmd.exe to run npm `.cmd` shims (CVE-2024-27980)
* and Node's `shell: true` joins argv with no escaping at all (DEP0190). That
* escaping is correct and deliberate, but it means `plan.args` holds
* `^^^"--model^^^"` on Windows where it holds `--model` elsewhere.
*
* Tests care about *which* arguments a plan carries, not about how they survive
* cmd.exe, so they normalise first. Keep this in sync with
* `escapeWindowsShellArg` in bin/cli/utils/winShellArgs.mjs.
*/
/**
* @param {unknown} arg
* @returns {string}
*/
export function unescapeWindowsShellArg(arg) {
let s = String(arg);
// 1. undo the two caret passes applied to cmd.exe metacharacters
s = s.replace(/\^(.)/g, "$1").replace(/\^(.)/g, "$1");
// 2. drop the wrapping quotes added by the CRT argv layer
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) s = s.slice(1, -1);
// 3. undo the doubled backslashes and the escaped embedded quotes in a single
// left-to-right pass — two sequential global replaces would let the first
// pass's output feed the second (e.g. an escaped-backslash-then-quote
// sequence could be misread), which is exactly what js/double-escaping flags.
s = s.replace(/\\\\|\\"/g, (m) => (m === "\\\\" ? "\\" : '"'));
return s;
}
/**
* Normalise a plan's argv to its logical form. A no-op off Windows.
*
* @param {unknown[]} args
* @param {NodeJS.Platform|string} [platform]
* @returns {string[]}
*/
export function logicalArgs(args, platform = process.platform) {
const list = [...(args ?? [])].map(String);
return platform === "win32" ? list.map(unescapeWindowsShellArg) : list;
}