test: share Windows platform spy helpers

This commit is contained in:
Vincent Koc
2026-05-17 03:26:19 +08:00
parent 2416de1421
commit e0c3c80ebc
7 changed files with 133 additions and 182 deletions

View File

@@ -1,4 +1,5 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { withMockedWindowsPlatform } from "../test-utils/vitest-spies.js";
import { defaultLoadOverrideModule, startLazyPluginServiceModule } from "./lazy-service-module.js";
type LazyPluginServiceHandle = NonNullable<
@@ -103,34 +104,28 @@ describe("startLazyPluginServiceModule", () => {
});
it("normalizes Windows absolute paths in the default override loader", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const start = createAsyncHookMock();
const importModule = vi.fn(async () => ({ startOverride: start }));
try {
await withMockedWindowsPlatform(async () => {
await defaultLoadOverrideModule("C:\\Users\\alice\\plugin folder\\x#y.mjs", importModule);
} finally {
platformSpy.mockRestore();
}
});
expect(importModule).toHaveBeenCalledWith("file:///C:/Users/alice/plugin%20folder/x%23y.mjs");
});
it("leaves caller-supplied override loaders responsible for their own specifiers", async () => {
process.env.OPENCLAW_LAZY_SERVICE_OVERRIDE = "C:\\Users\\alice\\browser-service.mjs";
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const start = createAsyncHookMock();
const loadOverrideModule = vi.fn(async () => ({ startOverride: start }));
try {
await withMockedWindowsPlatform(async () => {
await expectLifecycleStarted({
overrideEnvVar: "OPENCLAW_LAZY_SERVICE_OVERRIDE",
loadOverrideModule,
startExportNames: ["startOverride"],
});
} finally {
platformSpy.mockRestore();
}
});
expect(loadOverrideModule).toHaveBeenCalledWith("C:\\Users\\alice\\browser-service.mjs");
expect(start).toHaveBeenCalledTimes(1);

View File

@@ -3,6 +3,7 @@ import os from "node:os";
import path from "node:path";
import { importFreshModule } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it, vi } from "vitest";
import { withMockedWindowsPlatform } from "../test-utils/vitest-spies.js";
const tempDirs: string[] = [];
const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
@@ -47,9 +48,8 @@ describe("bundled plugin public surface loader", () => {
moduleExport: { marker: "windows-dist-ok" },
}),
}));
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
try {
await withMockedWindowsPlatform(async () => {
const publicSurfaceLoader = await importFreshModule<
typeof import("./public-surface-loader.js")
>(import.meta.url, "./public-surface-loader.js?scope=windows-dist-jiti");
@@ -68,9 +68,7 @@ describe("bundled plugin public surface loader", () => {
}).marker,
).toBe("windows-dist-ok");
expect(createJiti).not.toHaveBeenCalled();
} finally {
platformSpy.mockRestore();
}
});
});
it("prefers source require for bundled source public artifacts when a ts require hook exists", async () => {

View File

@@ -2,6 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { withMockedWindowsPlatform } from "../test-utils/vitest-spies.js";
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
import {
getRegistryJitiMocks,
@@ -227,17 +228,17 @@ describe("setup-registry module loader", () => {
plugins: [{ id: "test-plugin", rootDir: pluginRoot }],
diagnostics: [],
});
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const restoreVersions = forceNodeRuntimeVersionsForTest();
try {
resolvePluginSetupRegistry({
workspaceDir: pluginRoot,
env: {},
withMockedWindowsPlatform(() => {
resolvePluginSetupRegistry({
workspaceDir: pluginRoot,
env: {},
});
});
} finally {
restoreVersions();
platformSpy.mockRestore();
}
expect(mocks.createJiti).toHaveBeenCalledTimes(1);

View File

@@ -4,6 +4,7 @@ import { pathToFileURL } from "node:url";
import { bundledDistPluginFile } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it, vi } from "vitest";
import { stageBundledPluginRuntime } from "../../scripts/stage-bundled-plugin-runtime.mjs";
import { withMockedWindowsPlatform, withRestoredMocks } from "../test-utils/vitest-spies.js";
import { discoverOpenClawPlugins } from "./discovery.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
@@ -547,7 +548,6 @@ describe("stageBundledPluginRuntime", () => {
[bundledDistPluginFile("feishu", "assets/fixture.txt")]: "# Feishu Doc\n",
});
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const realSymlinkSync = fs.symlinkSync.bind(fs);
const symlinkSpy = vi.spyOn(fs, "symlinkSync").mockImplementation(((target, link, type) => {
const linkPath = String(link);
@@ -557,7 +557,11 @@ describe("stageBundledPluginRuntime", () => {
return realSymlinkSync(String(target), linkPath, type);
}) as typeof fs.symlinkSync);
stageBundledPluginRuntime({ repoRoot });
withRestoredMocks([symlinkSpy], () => {
withMockedWindowsPlatform(() => {
stageBundledPluginRuntime({ repoRoot });
});
});
const runtimeAssetPath = path.join(
repoRoot,
@@ -569,9 +573,6 @@ describe("stageBundledPluginRuntime", () => {
);
expect(fs.lstatSync(runtimeAssetPath).isSymbolicLink()).toBe(false);
expect(fs.readFileSync(runtimeAssetPath, "utf8")).toBe("# Feishu Doc\n");
symlinkSpy.mockRestore();
platformSpy.mockRestore();
},
);
});

View File

@@ -7,6 +7,7 @@ import {
_resetWindowsInstallRootsForTests,
getWindowsInstallRoots,
} from "../infra/windows-install-roots.js";
import { withMockedWindowsPlatform, withRestoredMocks } from "../test-utils/vitest-spies.js";
const { spawnMock, spawnSyncMock, execFileMock, execFilePromisifyMock } = vi.hoisted(() => {
const execFilePromisifyMock = vi.fn();
@@ -123,7 +124,6 @@ function expectedTrustedCmdExe(): string {
}
async function expectShimmedWindowsCommandWithoutExitCodeSucceeds(params?: { killed?: boolean }) {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const child = createMockChild({
closeCode: null,
exitCode: null,
@@ -132,14 +132,12 @@ async function expectShimmedWindowsCommandWithoutExitCodeSucceeds(params?: { kil
spawnMock.mockImplementation(() => child);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
expect(result.signal).toBeNull();
expect(result.termination).toBe("exit");
} finally {
platformSpy.mockRestore();
}
});
}
describe("windows command wrapper behavior", () => {
@@ -181,25 +179,21 @@ describe("windows command wrapper behavior", () => {
});
it("wraps .cmd commands via cmd.exe in runCommandWithTimeout", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const expectedComSpec = expectedTrustedCmdExe();
spawnMock.mockImplementation(
(_command: string, _args: string[], _options: Record<string, unknown>) => createMockChild(),
);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["pnpm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expectCmdWrappedInvocation({ captured, expectedComSpec });
} finally {
platformSpy.mockRestore();
}
});
});
it("ignores ComSpec when selecting the Windows command wrapper", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const previousComSpec = process.env.ComSpec;
const previousSystemRoot = process.env.SystemRoot;
process.env.ComSpec = "C:\\workspace\\evil\\cmd.exe";
@@ -210,12 +204,14 @@ describe("windows command wrapper behavior", () => {
);
try {
const result = await runCommandWithTimeout(["pnpm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expectCmdWrappedInvocation({
captured,
expectedComSpec: path.win32.join("C:\\Windows", "System32", "cmd.exe"),
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["pnpm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expectCmdWrappedInvocation({
captured,
expectedComSpec: path.win32.join("C:\\Windows", "System32", "cmd.exe"),
});
});
} finally {
if (previousComSpec === undefined) {
@@ -228,12 +224,10 @@ describe("windows command wrapper behavior", () => {
} else {
process.env.SystemRoot = previousSystemRoot;
}
platformSpy.mockRestore();
}
});
it("rejects unsafe Windows root values when selecting the command wrapper", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const previousSystemRoot = process.env.SystemRoot;
const previousWindir = process.env.WINDIR;
@@ -242,29 +236,31 @@ describe("windows command wrapper behavior", () => {
);
try {
for (const unsafeRoot of [
"\\\\evil\\share",
"C:\\Windows;C:\\evil",
"\\Windows",
"relative\\path",
]) {
_resetWindowsInstallRootsForTests({ queryRegistryValue: () => null });
// Set every install-root env source to the unsafe value so the
// resolver rejects each one and falls through to the safe default.
// Deleting WINDIR here is unreliable on real Windows runners, so
// overwrite it with the same rejected payload.
process.env.SystemRoot = unsafeRoot;
process.env.WINDIR = unsafeRoot;
spawnMock.mockClear();
await withMockedWindowsPlatform(async () => {
for (const unsafeRoot of [
"\\\\evil\\share",
"C:\\Windows;C:\\evil",
"\\Windows",
"relative\\path",
]) {
_resetWindowsInstallRootsForTests({ queryRegistryValue: () => null });
// Set every install-root env source to the unsafe value so the
// resolver rejects each one and falls through to the safe default.
// Deleting WINDIR here is unreliable on real Windows runners, so
// overwrite it with the same rejected payload.
process.env.SystemRoot = unsafeRoot;
process.env.WINDIR = unsafeRoot;
spawnMock.mockClear();
const result = await runCommandWithTimeout(["pnpm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expectCmdWrappedInvocation({
captured,
expectedComSpec: path.win32.join("C:\\Windows", "System32", "cmd.exe"),
});
}
const result = await runCommandWithTimeout(["pnpm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expectCmdWrappedInvocation({
captured,
expectedComSpec: path.win32.join("C:\\Windows", "System32", "cmd.exe"),
});
}
});
} finally {
if (previousSystemRoot === undefined) {
delete process.env.SystemRoot;
@@ -276,19 +272,17 @@ describe("windows command wrapper behavior", () => {
} else {
process.env.WINDIR = previousWindir;
}
platformSpy.mockRestore();
}
});
it("wraps corepack.cmd via cmd.exe in runCommandWithTimeout", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const expectedComSpec = expectedTrustedCmdExe();
spawnMock.mockImplementation(
(_command: string, _args: string[], _options: Record<string, unknown>) => createMockChild(),
);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["corepack", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
@@ -297,52 +291,44 @@ describe("windows command wrapper behavior", () => {
expect(captured[1][3]).toContain("corepack.cmd --version");
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBe(true);
} finally {
platformSpy.mockRestore();
}
});
});
it("keeps child exitCode when close reports null on Windows npm shims", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const child = createMockChild({ closeCode: null, exitCode: 0 });
spawnMock.mockImplementation(() => child);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
} finally {
platformSpy.mockRestore();
}
});
});
it("spawns node + npm-cli.js for npm argv to avoid direct .cmd execution", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const existsSpy = vi.spyOn(fs, "existsSync").mockReturnValue(true);
const child = createMockChild({ closeCode: 0, exitCode: 0 });
spawnMock.mockImplementation(() => child);
try {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expect(captured[0]).toBe(process.execPath);
expect(captured[1][0]).toBe(
path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"),
);
expect(captured[1][1]).toBe("--version");
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBeUndefined();
expect(captured[2].stdio).toEqual(["inherit", "pipe", "pipe"]);
} finally {
existsSpy.mockRestore();
platformSpy.mockRestore();
}
await withRestoredMocks([existsSpy], async () => {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expect(captured[0]).toBe(process.execPath);
expect(captured[1][0]).toBe(
path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js"),
);
expect(captured[1][1]).toBe("--version");
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBeUndefined();
expect(captured[2].stdio).toEqual(["inherit", "pipe", "pipe"]);
});
});
});
it("falls back to npm.cmd when npm-cli.js is unavailable", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const existsSpy = vi.spyOn(fs, "existsSync").mockReturnValue(false);
const expectedComSpec = expectedTrustedCmdExe();
@@ -350,24 +336,22 @@ describe("windows command wrapper behavior", () => {
(_command: string, _args: string[], _options: Record<string, unknown>) => createMockChild(),
);
try {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expect(captured[0]).toBe(expectedComSpec);
expect(captured[1].slice(0, 3)).toEqual(["/d", "/s", "/c"]);
expect(captured[1][3]).toContain("npm.cmd --version");
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBe(true);
expect(captured[2].stdio).toEqual(["inherit", "pipe", "pipe"]);
} finally {
existsSpy.mockRestore();
platformSpy.mockRestore();
}
await withRestoredMocks([existsSpy], async () => {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
expect(captured[0]).toBe(expectedComSpec);
expect(captured[1].slice(0, 3)).toEqual(["/d", "/s", "/c"]);
expect(captured[1][3]).toContain("npm.cmd --version");
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBe(true);
expect(captured[2].stdio).toEqual(["inherit", "pipe", "pipe"]);
});
});
});
it("waits for Windows exitCode settlement after close reports null", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const child = createMockChild({
closeCode: null,
exitCode: null,
@@ -377,12 +361,10 @@ describe("windows command wrapper behavior", () => {
spawnMock.mockImplementation(() => child);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["npm", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
} finally {
platformSpy.mockRestore();
}
});
});
it("treats shimmed Windows commands without a reported exit code as success when they close cleanly", async () => {
@@ -394,7 +376,6 @@ describe("windows command wrapper behavior", () => {
});
it("uses cmd.exe wrapper with windowsVerbatimArguments in runExec for .cmd shims", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const expectedComSpec = expectedTrustedCmdExe();
execFileMock.mockImplementation(
@@ -408,18 +389,14 @@ describe("windows command wrapper behavior", () => {
},
);
try {
await withMockedWindowsPlatform(async () => {
await runExec("pnpm", ["--version"], 1000);
const captured = requireExecFileCall(0);
expectCmdWrappedInvocation({ captured, expectedComSpec });
} finally {
platformSpy.mockRestore();
}
});
});
it("sets windowsHide on direct runExec invocations too", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
execFileMock.mockImplementation(
(
_command: string,
@@ -431,25 +408,21 @@ describe("windows command wrapper behavior", () => {
},
);
try {
await withMockedWindowsPlatform(async () => {
await runExec("node", ["--version"], 1000);
const captured = requireExecFileCall(0);
expect(captured[0]).toBe("node");
expect(captured[1]).toEqual(["--version"]);
expect(captured[2].windowsHide).toBe(true);
} finally {
platformSpy.mockRestore();
}
});
});
it("sets windowsHide on direct runCommandWithTimeout invocations too", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
spawnMock.mockImplementation(
(_command: string, _args: string[], _options: Record<string, unknown>) => createMockChild(),
);
try {
await withMockedWindowsPlatform(async () => {
const result = await runCommandWithTimeout(["node", "--version"], { timeoutMs: 1000 });
expect(result.code).toBe(0);
const captured = requireSpawnCall(0);
@@ -457,45 +430,42 @@ describe("windows command wrapper behavior", () => {
expect(captured[1]).toEqual(["--version"]);
expect(captured[2].windowsHide).toBe(true);
expect(captured[2].windowsVerbatimArguments).toBeUndefined();
} finally {
platformSpy.mockRestore();
}
});
});
it("kills the Windows process tree when the overall timeout elapses", async () => {
vi.useFakeTimers();
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const child = createMockChild({ autoClose: false });
const taskkillChild = createMockChild();
spawnMock.mockImplementationOnce(() => child).mockImplementationOnce(() => taskkillChild);
try {
const resultPromise = runCommandWithTimeout(["node", "idle.js"], { timeoutMs: 80 });
await withMockedWindowsPlatform(async () => {
const resultPromise = runCommandWithTimeout(["node", "idle.js"], { timeoutMs: 80 });
await vi.advanceTimersByTimeAsync(81);
expect(child.kill).not.toHaveBeenCalled();
expect(spawnMock).toHaveBeenCalledTimes(2);
const taskkillCall = requireSpawnCall(1);
expect(taskkillCall[0]).toBe("taskkill");
expect(taskkillCall[1]).toEqual(["/PID", "1234", "/T", "/F"]);
expect(taskkillCall[2]).toEqual({
stdio: "ignore",
windowsHide: true,
await vi.advanceTimersByTimeAsync(81);
expect(child.kill).not.toHaveBeenCalled();
expect(spawnMock).toHaveBeenCalledTimes(2);
const taskkillCall = requireSpawnCall(1);
expect(taskkillCall[0]).toBe("taskkill");
expect(taskkillCall[1]).toEqual(["/PID", "1234", "/T", "/F"]);
expect(taskkillCall[2]).toEqual({
stdio: "ignore",
windowsHide: true,
});
child.emit("close", null, "SIGKILL");
const result = await resultPromise;
expect(result.termination).toBe("timeout");
expect(result.code).not.toBe(0);
});
child.emit("close", null, "SIGKILL");
const result = await resultPromise;
expect(result.termination).toBe("timeout");
expect(result.code).not.toBe(0);
} finally {
platformSpy.mockRestore();
vi.useRealTimers();
}
});
it("decodes GBK stdout and stderr from runExec on Windows", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const stdout = Buffer.from([0xb2, 0xe2, 0xca, 0xd4]);
const stderr = Buffer.from([0xa3, 0xbb]);
@@ -510,20 +480,16 @@ describe("windows command wrapper behavior", () => {
},
);
try {
await withMockedWindowsPlatform(async () => {
const result = await runExec("node", ["gbk-output.js"], 1000);
expect(result.stdout).toBe("测试");
expect(result.stderr).toBe("");
const captured = requireExecFileCall(0);
expect(captured[2].encoding).toBe("buffer");
} finally {
platformSpy.mockRestore();
}
});
});
it("prefers valid UTF-8 stdout from runExec on Windows", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
execFileMock.mockImplementation(
(
_command: string,
@@ -535,18 +501,15 @@ describe("windows command wrapper behavior", () => {
},
);
try {
await withMockedWindowsPlatform(async () => {
await expect(runExec("node", ["utf8-output.js"], 1000)).resolves.toEqual({
stdout: "测试",
stderr: "",
});
} finally {
platformSpy.mockRestore();
}
});
});
it("decodes spawn stdout once so GBK characters split across chunks survive", async () => {
const platformSpy = vi.spyOn(process, "platform", "get").mockReturnValue("win32");
const child = createMockChild({ autoClose: false });
spawnMock.mockImplementation(() => {
queueMicrotask(() => {
@@ -558,7 +521,7 @@ describe("windows command wrapper behavior", () => {
return child;
});
try {
await withMockedWindowsPlatform(async () => {
await expect(
runCommandWithTimeout(["node", "gbk-output.js"], { timeoutMs: 1000 }),
).resolves.toEqual({
@@ -571,8 +534,6 @@ describe("windows command wrapper behavior", () => {
termination: "exit",
noOutputTimedOut: false,
});
} finally {
platformSpy.mockRestore();
}
});
});
});

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { INVALID_EXEC_SECRET_REF_IDS } from "../test-utils/secret-ref-test-vectors.js";
import { withMockedWindowsPlatform } from "../test-utils/vitest-spies.js";
import {
resolveSecretRefString,
resolveSecretRefValue,
@@ -503,9 +504,7 @@ describe("secret ref resolver", () => {
});
it("fails closed on Windows when file provider ACL source is unknown", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32" as unknown as NodeJS.Platform);
try {
await withMockedWindowsPlatform(async () => {
const dir = await createCaseDir("win-acl");
const filePath = path.join(dir, "secrets.json");
await writeSecureFile(filePath, '{"token":"abc123"}');
@@ -524,15 +523,11 @@ describe("secret ref resolver", () => {
},
),
).rejects.toThrow(/ACL verification unavailable on Windows/);
} finally {
vi.restoreAllMocks();
}
});
});
it("allows trusted file provider opt-out when Windows ACL source is unknown", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32" as unknown as NodeJS.Platform);
try {
await withMockedWindowsPlatform(async () => {
const dir = await createCaseDir("win-acl-opt-out");
const filePath = path.join(dir, "secrets.json");
await writeSecureFile(filePath, '{"token":"abc123"}');
@@ -550,20 +545,14 @@ describe("secret ref resolver", () => {
},
);
expect(value).toBe("abc123");
} finally {
vi.restoreAllMocks();
}
});
});
it("fails closed on Windows when exec provider ACL source is unknown", async () => {
vi.spyOn(process, "platform", "get").mockReturnValue("win32" as unknown as NodeJS.Platform);
try {
await withMockedWindowsPlatform(async () => {
await expect(resolveExecSecret(execProtocolV1ScriptPath)).rejects.toThrow(
/ACL verification unavailable on Windows/,
);
} finally {
vi.restoreAllMocks();
}
});
});
});

View File

@@ -48,3 +48,9 @@ export function withMockedPlatform<T>(
): T | Promise<T> {
return withRestoredMocks([vi.spyOn(process, "platform", "get").mockReturnValue(platform)], run);
}
export function withMockedWindowsPlatform<T>(run: () => Promise<T>): Promise<T>;
export function withMockedWindowsPlatform<T>(run: () => T): T;
export function withMockedWindowsPlatform<T>(run: () => T | Promise<T>): T | Promise<T> {
return withMockedPlatform("win32", run);
}