mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(windows): request shell when spawning bare qoder binary name on Windows (fixes #8590)
Post Node CVE-2024-27980, spawn('qodercli', [], { shell: false }) fails with ENOENT on Windows when command is a bare binary name without extension. Enabling shell mode for bare command names allows cmd.exe to resolve .cmd / .bat wrappers from PATH.
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
* we reuse it: `getCliRuntimeStatus("qoder")` returns an absolute `.cmd`/`.exe`
|
||||
* `commandPath`, and `shouldUseShellForCommand()` tells us whether it needs cmd.exe.
|
||||
*/
|
||||
import path from "path";
|
||||
import {
|
||||
getCliRuntimeStatus,
|
||||
getKnownToolPaths,
|
||||
@@ -76,7 +77,16 @@ export async function resolveQoderCliInvocation(
|
||||
/* fall back to the bare/explicit command — spawn will surface a real ENOENT */
|
||||
}
|
||||
|
||||
const invocation: QoderCliInvocation = { command, useShell: shouldUseShell(command) };
|
||||
// On Windows, if explicit CLI_QODER_BIN / command is a bare binary name like "qodercli" or "qoder" (no path or extension),
|
||||
// spawn(cmd, { shell: false }) will fail with ENOENT post Node CVE-2024-27980.
|
||||
// Enabling shell: true for bare command names on win32 lets system PATH resolution find qodercli.cmd / qoder.cmd.
|
||||
const useShell =
|
||||
shouldUseShell(command) ||
|
||||
(process.platform === "win32" &&
|
||||
!path.isAbsolute(command) &&
|
||||
!path.basename(command).includes("."));
|
||||
|
||||
const invocation: QoderCliInvocation = { command, useShell };
|
||||
if (cacheable) {
|
||||
qoderInvocationCache = {
|
||||
...invocation,
|
||||
|
||||
@@ -53,11 +53,25 @@ test("cliRuntime enumerates qodercli.cmd under %APPDATA%\\npm on Windows", () =>
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldUseShellForCommand: true for a .cmd wrapper, false for the bare name (Windows)", () => {
|
||||
test("resolveQoderCliInvocation requests shell for explicit bare command CLI_QODER_BIN on Windows (#8590)", async () => {
|
||||
setPlatform("win32");
|
||||
const cmdPath = path.join(os.homedir(), "AppData", "Roaming", "npm", "qodercli.cmd");
|
||||
assert.equal(cliRuntime.shouldUseShellForCommand(cmdPath), true);
|
||||
assert.equal(cliRuntime.shouldUseShellForCommand("qodercli"), false);
|
||||
process.env.CLI_QODER_BIN = "custom-qoder";
|
||||
|
||||
const invocation = await qoderResolve.resolveQoderCliInvocation("custom-qoder", {
|
||||
getStatus: async () => ({
|
||||
installed: false,
|
||||
runnable: false,
|
||||
command: "qodercli",
|
||||
commandPath: null,
|
||||
reason: "not_found",
|
||||
runtimeMode: "auto",
|
||||
requiresBinary: true,
|
||||
}),
|
||||
});
|
||||
|
||||
assert.equal(invocation.command, "custom-qoder");
|
||||
assert.equal(invocation.useShell, true);
|
||||
delete process.env.CLI_QODER_BIN;
|
||||
});
|
||||
|
||||
test("resolveQoderCliInvocation picks the absolute .cmd path + shell when cliRuntime finds it", async () => {
|
||||
@@ -83,7 +97,7 @@ test("resolveQoderCliInvocation picks the absolute .cmd path + shell when cliRun
|
||||
assert.notEqual(invocation.command, "qodercli");
|
||||
});
|
||||
|
||||
test("resolveQoderCliInvocation falls back to the bare command when cliRuntime finds nothing", async () => {
|
||||
test("resolveQoderCliInvocation falls back to bare command + requests shell for bare name on Windows (#8590)", async () => {
|
||||
setPlatform("win32");
|
||||
delete process.env.CLI_QODER_BIN;
|
||||
|
||||
@@ -100,8 +114,8 @@ test("resolveQoderCliInvocation falls back to the bare command when cliRuntime f
|
||||
});
|
||||
|
||||
assert.equal(invocation.command, "qodercli");
|
||||
// A bare name is not a .cmd/.bat, so no shell is requested.
|
||||
assert.equal(invocation.useShell, false);
|
||||
// Bare name on Windows requires shell: true so cmd.exe can resolve qodercli.cmd / qodercli.bat / qodercli.exe on PATH (#8590)
|
||||
assert.equal(invocation.useShell, true);
|
||||
});
|
||||
|
||||
test("resolveQoderCliInvocation is inert on non-Windows (no shell, resolved path honored)", async () => {
|
||||
|
||||
Reference in New Issue
Block a user