fix(qa): kill telegram credential trees on windows

This commit is contained in:
Vincent Koc
2026-06-21 06:42:35 +02:00
parent 34806b39cd
commit 0030a192c8
2 changed files with 57 additions and 4 deletions
+27 -3
View File
@@ -1,5 +1,5 @@
// Telegram User Credential Io script supports OpenClaw repository automation.
import { spawn } from "node:child_process";
import { spawn, spawnSync } from "node:child_process";
import { readBoundedResponseText } from "../lib/bounded-response.ts";
export type JsonObject = Record<string, unknown>;
@@ -244,8 +244,22 @@ async function finishTimedOutChildProcessTree(
}
}
function signalChildProcessTree(child: ReturnType<typeof spawn>, signal: NodeJS.Signals) {
if (process.platform !== "win32" && child.pid) {
type ChildProcessTreeTarget = Pick<ReturnType<typeof spawn>, "kill" | "pid">;
export function signalChildProcessTree(
child: ChildProcessTreeTarget,
signal: NodeJS.Signals,
{
platform = process.platform,
runTaskkill = spawnSync,
useProcessGroup = platform !== "win32",
}: {
platform?: NodeJS.Platform;
runTaskkill?: typeof spawnSync;
useProcessGroup?: boolean;
} = {},
) {
if (useProcessGroup && child.pid) {
try {
process.kill(-child.pid, signal);
return;
@@ -253,6 +267,16 @@ function signalChildProcessTree(child: ReturnType<typeof spawn>, signal: NodeJS.
// The process group can disappear between timeout and cleanup.
}
}
if (platform === "win32" && typeof child.pid === "number") {
const args = ["/PID", String(child.pid), "/T"];
if (signal === "SIGKILL") {
args.push("/F");
}
const result = runTaskkill("taskkill", args, { stdio: "ignore" });
if (!result.error && result.status === 0) {
return;
}
}
child.kill(signal);
}
+30 -1
View File
@@ -5,7 +5,11 @@ import { readFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path, { win32 } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { fetchJsonWithTimeout, runCommand } from "../../scripts/e2e/telegram-user-credential-io.ts";
import {
fetchJsonWithTimeout,
runCommand,
signalChildProcessTree,
} from "../../scripts/e2e/telegram-user-credential-io.ts";
import {
expandHome,
resolvePrivateJsonDirectory,
@@ -403,6 +407,31 @@ setInterval(() => {}, 1000);
}
});
it("signals Windows credential helper process trees with taskkill", () => {
const child = {
kill: vi.fn(),
pid: 12345,
};
const runTaskkill = vi.fn(() => ({ error: undefined, status: 0 }));
signalChildProcessTree(child, "SIGTERM", {
platform: "win32",
runTaskkill,
});
expect(runTaskkill).toHaveBeenNthCalledWith(1, "taskkill", ["/PID", "12345", "/T"], {
stdio: "ignore",
});
signalChildProcessTree(child, "SIGKILL", {
platform: "win32",
runTaskkill,
});
expect(runTaskkill).toHaveBeenNthCalledWith(2, "taskkill", ["/PID", "12345", "/T", "/F"], {
stdio: "ignore",
});
expect(child.kill).not.toHaveBeenCalled();
});
it.runIf(process.platform !== "win32")(
"exits promptly after forwarded SIGTERM children exit cleanly",
async () => {