fix(scripts): clamp package candidate timers

This commit is contained in:
Vincent Koc
2026-06-22 02:51:05 +02:00
parent 851b65c060
commit dd89898133
2 changed files with 78 additions and 7 deletions

View File

@@ -5,6 +5,7 @@ import { access, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promise
import { tmpdir } from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
import { afterEach, describe, expect, it, vi } from "vitest";
import { resolveWindowsTaskkillPath } from "../../scripts/lib/windows-taskkill.mjs";
import {
@@ -409,6 +410,15 @@ describe("resolve-openclaw-package-candidate", () => {
).rejects.toThrow(/produced more than \d+ captured stdout chars/u);
});
it("clamps oversized package runner command timers before scheduling", async () => {
await expect(
runCommandForTest(process.execPath, ["-e", "setTimeout(() => process.exit(0), 25);"], {
killAfterMs: MAX_TIMER_TIMEOUT_MS + 1,
timeoutMs: MAX_TIMER_TIMEOUT_MS + 1,
}),
).resolves.toBe("");
});
it("kills timed-out package runner process groups", async () => {
if (process.platform === "win32") {
return;
@@ -448,6 +458,45 @@ describe("resolve-openclaw-package-candidate", () => {
}
});
it("clamps oversized package runner kill grace before scheduling", async () => {
if (process.platform === "win32") {
return;
}
const dir = await mkdtemp(path.join(tmpdir(), "openclaw-package-runner-grace-"));
tempDirs.push(dir);
const childPidPath = path.join(dir, "child.pid");
const cleanupPath = path.join(dir, "child.cleanup");
let childPid: number | undefined;
try {
const childScript = [
"const fs = require('node:fs');",
`fs.writeFileSync(${JSON.stringify(childPidPath)}, String(process.pid));`,
"process.on('SIGTERM', () => {",
` setTimeout(() => { fs.writeFileSync(${JSON.stringify(cleanupPath)}, 'clean'); process.exit(0); }, 75);`,
"});",
"setInterval(() => {}, 1000);",
].join("\n");
const timeoutAssertion = expect(
runCommandForTest(process.execPath, ["-e", childScript], {
killAfterMs: MAX_TIMER_TIMEOUT_MS + 1,
timeoutMs: 500,
}),
).rejects.toThrow(/timed out after 500ms/u);
await waitForFile(childPidPath, 2_000);
childPid = Number.parseInt(readFileSync(childPidPath, "utf8"), 10);
await timeoutAssertion;
expect(readFileSync(cleanupPath, "utf8")).toBe("clean");
} finally {
if (childPid !== undefined && isProcessAlive(childPid)) {
process.kill(childPid, "SIGKILL");
}
}
});
it("rejects timed-out package runner commands when descendants exit cleanly", async () => {
if (process.platform === "win32") {
return;