fix(scripts): reject loose run env kill delay

This commit is contained in:
Vincent Koc
2026-06-07 02:35:08 +02:00
parent e28dd6dd6e
commit 8516f37563
2 changed files with 61 additions and 4 deletions
+27 -4
View File
@@ -61,6 +61,25 @@ export function resolveSpawnCommand(command, args, execPath = process.execPath)
};
}
/**
* Reads the signal-forwarding force-kill grace period.
*/
export function resolveForceKillDelayMs(env = process.env) {
const raw = env.OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS;
if (raw === undefined || raw === "") {
return 5_000;
}
const text = raw.trim();
if (!/^\d+$/u.test(text)) {
throw new Error("OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS must be a positive integer");
}
const parsed = Number(text);
if (!Number.isSafeInteger(parsed) || parsed < 1) {
throw new Error("OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS must be a positive integer");
}
return parsed;
}
function main(argv = process.argv.slice(2)) {
if (isRunWithEnvHelpRequest(argv)) {
console.log(USAGE);
@@ -75,6 +94,14 @@ function main(argv = process.argv.slice(2)) {
process.exit(2);
}
let forceKillDelayMs;
try {
forceKillDelayMs = resolveForceKillDelayMs();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exit(2);
}
const spawnCommand = resolveSpawnCommand(parsed.command, parsed.args);
const useChildProcessGroup = process.platform !== "win32" && !process.stdin.isTTY;
const child = spawn(spawnCommand.command, spawnCommand.args, {
@@ -85,10 +112,6 @@ function main(argv = process.argv.slice(2)) {
},
stdio: "inherit",
});
const forceKillDelayMs = Math.max(
1,
Number.parseInt(process.env.OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS ?? "5000", 10) || 5_000,
);
let forwardedSignal = null;
let forceKillTimer = null;
// Keep the child in the foreground process group so TTY signals such as
+34
View File
@@ -7,6 +7,7 @@ import { describe, expect, it } from "vitest";
import {
isRunWithEnvHelpRequest,
parseRunWithEnvArgs,
resolveForceKillDelayMs,
resolveSpawnCommand,
} from "../../scripts/run-with-env.mjs";
@@ -124,6 +125,39 @@ describe("run-with-env", () => {
});
});
it("rejects malformed force-kill grace configuration before spawning", () => {
expect(resolveForceKillDelayMs({})).toBe(5_000);
expect(resolveForceKillDelayMs({ OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS: "250" })).toBe(250);
for (const value of ["0", "-1", "1e3", "100ms"]) {
expect(() => resolveForceKillDelayMs({ OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS: value })).toThrow(
"OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS must be a positive integer",
);
}
const result = spawnSync(
process.execPath,
[
"scripts/run-with-env.mjs",
"OPENCLAW_RUN_WITH_ENV_SIGNAL_TEST=1",
"--",
"node",
"-e",
"process.stdout.write('spawned')",
],
{
cwd: process.cwd(),
encoding: "utf8",
env: { ...process.env, OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS: "100ms" },
},
);
expect(result.status).toBe(2);
expect(result.stdout).toBe("");
expect(result.stderr).toContain(
"OPENCLAW_RUN_WITH_ENV_FORCE_KILL_MS must be a positive integer",
);
});
it.runIf(process.platform !== "win32").each(["SIGTERM", "SIGHUP", "SIGINT"] as const)(
"forwards parent %s to the wrapped command",
async (signal) => {