fix: spawn launcher services without implicit shell (#16093)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 19deb2d0-75af-4fcf-ac1d-a6933c00769f
This commit is contained in:
Christopher Haugen
2026-08-11 10:50:54 -04:00
committed by GitHub
co-authored by Copilot
parent c4593b8154
commit 2e1502f39d
2 changed files with 31 additions and 1 deletions
@@ -1,3 +1,6 @@
import { spawn } from "node:child_process";
import { once } from "node:events";
import { describe, expect, it } from "vitest";
import {
@@ -30,6 +33,28 @@ describe("dev process utils", () => {
detached: process.platform !== "win32",
});
});
it("passes shell metacharacters to services as literal arguments", async () => {
const constraint = "agent-client-protocol<0.11";
const child = spawn(
process.execPath,
["-e", "process.stdout.write(process.argv[1])", constraint],
getProcessTreeSpawnOptions({
shell: true,
stdio: ["ignore", "pipe", "pipe"],
}),
);
let stdout = "";
child.stdout.setEncoding("utf8");
child.stdout.on("data", (chunk) => {
stdout += chunk;
});
const [exitCode] = await once(child, "exit");
expect(exitCode).toBe(0);
expect(stdout).toBe(constraint);
});
});
describe("resolveWindowsCommand", () => {
+6 -1
View File
@@ -15,7 +15,11 @@ export function isProcessRunning(proc) {
}
/**
* Add spawn options needed for process-tree cleanup.
* Add spawn options needed for safe service launches and process-tree cleanup.
*
* Arguments must bypass shell parsing so values such as version constraints
* containing `<` are forwarded literally. Callers that need shell behavior
* must invoke the shell explicitly as the command.
*
* On POSIX, `detached: true` makes the spawned service the leader of a new
* process group. Later we can signal `-pid` to terminate that whole group,
@@ -30,6 +34,7 @@ export function isProcessRunning(proc) {
export function getProcessTreeSpawnOptions(options = {}) {
return {
...options,
shell: false,
detached: process.platform !== "win32",
};
}