mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-09 03:22:40 +00:00
fix(qa-matrix): resolve Windows taskkill path
This commit is contained in:
@@ -77,11 +77,12 @@ describe("Matrix QA CLI runtime", () => {
|
||||
|
||||
testing.killMatrixQaCliChild(child, "SIGTERM", runTaskkill);
|
||||
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(1, "taskkill", ["/PID", "12345", "/T"], {
|
||||
const taskkillPath = path.win32.join("C:\\Windows", "System32", "taskkill.exe");
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(1, taskkillPath, ["/PID", "12345", "/T"], {
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(2, "taskkill", ["/PID", "12345", "/T", "/F"], {
|
||||
expect(runTaskkill).toHaveBeenNthCalledWith(2, taskkillPath, ["/PID", "12345", "/T", "/F"], {
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { setTimeout as sleep } from "node:timers/promises";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { redactSensitiveText } from "openclaw/plugin-sdk/logging-core";
|
||||
import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
|
||||
import { resolveMatrixQaWindowsSystem32ExePath } from "../../windows-system-tools.js";
|
||||
|
||||
export type MatrixQaCliRunResult = {
|
||||
args: string[];
|
||||
@@ -111,16 +112,17 @@ function killMatrixQaCliChild(
|
||||
): void {
|
||||
if (process.platform === "win32") {
|
||||
if (child.pid) {
|
||||
const taskkillPath = resolveMatrixQaWindowsSystem32ExePath("taskkill.exe");
|
||||
const args = ["/PID", String(child.pid), "/T"];
|
||||
if (signal === "SIGKILL") {
|
||||
args.push("/F");
|
||||
}
|
||||
const result = runTaskkill("taskkill", args, { stdio: "ignore", windowsHide: true });
|
||||
const result = runTaskkill(taskkillPath, args, { stdio: "ignore", windowsHide: true });
|
||||
if (!result.error && result.status === 0) {
|
||||
return;
|
||||
}
|
||||
if (signal !== "SIGKILL") {
|
||||
const forceResult = runTaskkill("taskkill", [...args, "/F"], {
|
||||
const forceResult = runTaskkill(taskkillPath, [...args, "/F"], {
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
32
extensions/qa-matrix/src/windows-system-tools.test.ts
Normal file
32
extensions/qa-matrix/src/windows-system-tools.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// Qa Matrix tests cover Windows system tool path resolution.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
resolveMatrixQaWindowsSystem32ExePath,
|
||||
resolveMatrixQaWindowsSystemRoot,
|
||||
} from "./windows-system-tools.js";
|
||||
|
||||
describe("qa-matrix windows system tools", () => {
|
||||
it("resolves System32 executables from a trusted SystemRoot", () => {
|
||||
expect(resolveMatrixQaWindowsSystemRoot({ SystemRoot: "D:\\Windows\\" })).toBe("D:\\Windows");
|
||||
expect(
|
||||
resolveMatrixQaWindowsSystem32ExePath("taskkill.exe", { SystemRoot: "D:\\Windows\\" }),
|
||||
).toBe("D:\\Windows\\System32\\taskkill.exe");
|
||||
});
|
||||
|
||||
it("falls back to the default Windows root when env roots are unsafe", () => {
|
||||
expect(
|
||||
resolveMatrixQaWindowsSystem32ExePath("taskkill.exe", {
|
||||
WINDIR: "\\\\attacker\\share",
|
||||
}),
|
||||
).toBe("C:\\Windows\\System32\\taskkill.exe");
|
||||
});
|
||||
|
||||
it("rejects non-basename System32 executable names", () => {
|
||||
expect(() => resolveMatrixQaWindowsSystem32ExePath("..\\taskkill.exe")).toThrow(
|
||||
"Invalid Windows System32 executable name",
|
||||
);
|
||||
expect(() => resolveMatrixQaWindowsSystem32ExePath("taskkill")).toThrow(
|
||||
"Invalid Windows System32 executable name",
|
||||
);
|
||||
});
|
||||
});
|
||||
62
extensions/qa-matrix/src/windows-system-tools.ts
Normal file
62
extensions/qa-matrix/src/windows-system-tools.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// Qa Matrix resolves Windows system tools without trusting PATH.
|
||||
import path from "node:path";
|
||||
|
||||
const DEFAULT_WINDOWS_SYSTEM_ROOT = "C:\\Windows";
|
||||
|
||||
function getEnvValueCaseInsensitive(
|
||||
env: Record<string, string | undefined>,
|
||||
expectedKey: string,
|
||||
): string | undefined {
|
||||
const direct = env[expectedKey];
|
||||
if (direct !== undefined) {
|
||||
return direct;
|
||||
}
|
||||
const expected = expectedKey.toUpperCase();
|
||||
const actualKey = Object.keys(env).find((key) => key.toUpperCase() === expected);
|
||||
return actualKey ? env[actualKey] : undefined;
|
||||
}
|
||||
|
||||
function normalizeWindowsSystemRoot(raw: string | undefined): string | null {
|
||||
const trimmed = raw?.trim();
|
||||
if (
|
||||
!trimmed ||
|
||||
trimmed.includes("\0") ||
|
||||
trimmed.includes("\r") ||
|
||||
trimmed.includes("\n") ||
|
||||
trimmed.includes(";")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const normalized = path.win32.normalize(trimmed);
|
||||
if (!path.win32.isAbsolute(normalized) || normalized.startsWith("\\\\")) {
|
||||
return null;
|
||||
}
|
||||
const parsed = path.win32.parse(normalized);
|
||||
if (!/^[A-Za-z]:\\$/u.test(parsed.root) || normalized.length <= parsed.root.length) {
|
||||
return null;
|
||||
}
|
||||
return normalized.replace(/[\\/]+$/u, "");
|
||||
}
|
||||
|
||||
export function resolveMatrixQaWindowsSystemRoot(
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): string {
|
||||
return (
|
||||
normalizeWindowsSystemRoot(getEnvValueCaseInsensitive(env, "SystemRoot")) ??
|
||||
normalizeWindowsSystemRoot(getEnvValueCaseInsensitive(env, "WINDIR")) ??
|
||||
DEFAULT_WINDOWS_SYSTEM_ROOT
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveMatrixQaWindowsSystem32ExePath(
|
||||
executableName: string,
|
||||
env: Record<string, string | undefined> = process.env,
|
||||
): string {
|
||||
if (
|
||||
path.win32.basename(executableName) !== executableName ||
|
||||
!/^[A-Za-z0-9_.-]+\.exe$/u.test(executableName)
|
||||
) {
|
||||
throw new Error(`Invalid Windows System32 executable name: ${executableName}`);
|
||||
}
|
||||
return path.win32.join(resolveMatrixQaWindowsSystemRoot(env), "System32", executableName);
|
||||
}
|
||||
Reference in New Issue
Block a user