























@@ -308,6 +308,35 @@ function expectFailedInstallResult<
308308return params.result;
309309}
310310311+function expectWarningIncludes(warnings: readonly string[], fragment: string) {
312+expect(warnings.some((warning) => warning.includes(fragment))).toBe(true);
313+}
314+315+function expectWarningExcludes(warnings: readonly string[], fragment: string) {
316+expect(warnings.some((warning) => warning.includes(fragment))).toBe(false);
317+}
318+319+function requireRecord(value: unknown, label: string): Record<string, unknown> {
320+if (!value || typeof value !== "object" || Array.isArray(value)) {
321+throw new Error(`expected ${label} to be an object`);
322+}
323+return value as Record<string, unknown>;
324+}
325+326+function requireHookPayload(handler: ReturnType<typeof vi.fn>): Record<string, unknown> {
327+const payload = handler.mock.calls[0]?.[0];
328+return requireRecord(payload, "before_install hook payload");
329+}
330+331+function expectHookRequest(
332+payload: Record<string, unknown>,
333+expected: { kind: string; mode: string },
334+) {
335+const request = requireRecord(payload.request, "before_install hook request");
336+expect(request.kind).toBe(expected.kind);
337+expect(request.mode).toBe(expected.mode);
338+}
339+311340function mockSuccessfulCommandRun(run: ReturnType<typeof vi.mocked<typeof runCommandWithTimeout>>) {
312341run.mockResolvedValue({
313342code: 0,
@@ -635,12 +664,14 @@ describe("installPluginFromArchive", () => {
635664});
636665637666expect(result.ok).toBe(true);
638-expect(vi.mocked(runCommandWithTimeout)).toHaveBeenCalledWith(
639-expect.arrayContaining(["npm", "install"]),
640-expect.objectContaining({
641-cwd: expect.stringContaining(".openclaw-install-stage-"),
642-}),
643-);
667+const commandRun = vi.mocked(runCommandWithTimeout).mock.calls[0];
668+expect(commandRun?.[0]).toContain("npm");
669+expect(commandRun?.[0]).toContain("install");
670+const commandOptions = commandRun?.[1];
671+if (!commandOptions || typeof commandOptions === "number") {
672+throw new Error("expected command options object");
673+}
674+expect(commandOptions.cwd).toContain(".openclaw-install-stage-");
644675});
645676646677it("installs scoped archives, rejects duplicate installs, and allows updates", async () => {
@@ -1142,9 +1173,7 @@ describe("installPluginFromArchive", () => {
11421173expect(result.error).toContain('Plugin "dangerous-plugin" installation blocked');
11431174expect(result.error).toContain("dangerous code patterns detected");
11441175}
1145-expect(warnings).toEqual(
1146-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
1147-);
1176+expectWarningIncludes(warnings, "dangerous code pattern");
11481177});
1149117811501179it("allows package installs when dangerous scanner patterns are only in tests", async () => {
@@ -1168,9 +1197,7 @@ describe("installPluginFromArchive", () => {
11681197const { result, warnings } = await installFromDirWithWarnings({ pluginDir, extensionsDir });
1169119811701199expect(result.ok).toBe(true);
1171-expect(warnings).not.toEqual(
1172-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
1173-);
1200+expectWarningExcludes(warnings, "dangerous code pattern");
11741201});
1175120211761203it("still scans declared package entrypoints when they live under test-looking paths", async () => {
@@ -2072,9 +2099,7 @@ describe("installPluginFromArchive", () => {
20722099expect(result.code).toBe(PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED);
20732100expect(result.error).toContain('Bundle "dangerous-bundle" installation blocked');
20742101}
2075-expect(warnings).toEqual(
2076-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
2077-);
2102+expectWarningIncludes(warnings, "dangerous code pattern");
20782103});
2079210420802105it("allows bundle installs when dangerous scanner patterns are only in tests", async () => {
@@ -2092,9 +2117,7 @@ describe("installPluginFromArchive", () => {
20922117const { result, warnings } = await installFromDirWithWarnings({ pluginDir, extensionsDir });
2093211820942119expect(result.ok).toBe(true);
2095-expect(warnings).not.toEqual(
2096-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
2097-);
2120+expectWarningExcludes(warnings, "dangerous code pattern");
20982121});
2099212221002123it("blocks bundle installs when a vendored manifest declares a blocked dependency", async () => {
@@ -2372,27 +2395,22 @@ describe("installPluginFromArchive", () => {
2372239523732396expect(result.ok).toBe(true);
23742397expect(handler).toHaveBeenCalledTimes(1);
2375-expect(handler.mock.calls[0]?.[0]).toMatchObject({
2376-targetName: "hook-findings-plugin",
2377-targetType: "plugin",
2378-origin: "plugin-package",
2379-sourcePath: pluginDir,
2380-sourcePathKind: "directory",
2381-request: {
2382-kind: "plugin-dir",
2383-mode: "install",
2384-},
2385-builtinScan: {
2386-status: "ok",
2387-findings: [],
2388-},
2389-plugin: {
2390-contentType: "package",
2391-pluginId: "hook-findings-plugin",
2392-packageName: "hook-findings-plugin",
2393-version: "1.0.0",
2394-extensions: ["index.js"],
2395-},
2398+const payload = requireHookPayload(handler);
2399+expect(payload.targetName).toBe("hook-findings-plugin");
2400+expect(payload.targetType).toBe("plugin");
2401+expect(payload.origin).toBe("plugin-package");
2402+expect(payload.sourcePath).toBe(pluginDir);
2403+expect(payload.sourcePathKind).toBe("directory");
2404+expectHookRequest(payload, { kind: "plugin-dir", mode: "install" });
2405+const builtinScan = requireRecord(payload.builtinScan, "builtin scan");
2406+expect(builtinScan.status).toBe("ok");
2407+expect(builtinScan.findings).toEqual([]);
2408+expect(payload.plugin).toEqual({
2409+contentType: "package",
2410+pluginId: "hook-findings-plugin",
2411+packageName: "hook-findings-plugin",
2412+version: "1.0.0",
2413+extensions: ["index.js"],
23962414});
23972415expect(handler.mock.calls[0]?.[1]).toEqual({
23982416origin: "plugin-package",
@@ -2436,33 +2454,23 @@ describe("installPluginFromArchive", () => {
24362454expect(result.code).toBeUndefined();
24372455}
24382456expect(handler).toHaveBeenCalledTimes(1);
2439-expect(handler.mock.calls[0]?.[0]).toMatchObject({
2440-targetName: "dangerous-blocked-plugin",
2441-targetType: "plugin",
2442-origin: "plugin-package",
2443-request: {
2444-kind: "plugin-dir",
2445-mode: "install",
2446-},
2447-builtinScan: {
2448-status: "ok",
2449-findings: [
2450-expect.objectContaining({
2451-severity: "critical",
2452-}),
2453-],
2454-},
2455-plugin: {
2456-contentType: "package",
2457-pluginId: "dangerous-blocked-plugin",
2458-packageName: "dangerous-blocked-plugin",
2459-version: "1.0.0",
2460-extensions: ["index.js"],
2461-},
2457+const payload = requireHookPayload(handler);
2458+expect(payload.targetName).toBe("dangerous-blocked-plugin");
2459+expect(payload.targetType).toBe("plugin");
2460+expect(payload.origin).toBe("plugin-package");
2461+expectHookRequest(payload, { kind: "plugin-dir", mode: "install" });
2462+const builtinScan = requireRecord(payload.builtinScan, "builtin scan");
2463+expect(builtinScan.status).toBe("ok");
2464+const findings = builtinScan.findings as Array<{ severity?: string }>;
2465+expect(findings.some((finding) => finding.severity === "critical")).toBe(true);
2466+expect(payload.plugin).toEqual({
2467+contentType: "package",
2468+pluginId: "dangerous-blocked-plugin",
2469+packageName: "dangerous-blocked-plugin",
2470+version: "1.0.0",
2471+extensions: ["index.js"],
24622472});
2463-expect(warnings).toEqual(
2464-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
2465-);
2473+expectWarningIncludes(warnings, "dangerous code pattern");
24662474expect(
24672475warnings.some((w) => w.includes("blocked by plugin hook: Blocked by enterprise policy")),
24682476).toBe(true);
@@ -2538,12 +2546,7 @@ describe("installPluginFromArchive", () => {
2538254625392547expect(result.ok).toBe(true);
25402548expect(handler).toHaveBeenCalledTimes(1);
2541-expect(handler.mock.calls[0]?.[0]).toMatchObject({
2542-request: {
2543-kind: "plugin-dir",
2544-mode: "install",
2545-},
2546-});
2549+expectHookRequest(requireHookPayload(handler), { kind: "plugin-dir", mode: "install" });
25472550});
2548255125492552it("reports update mode to before_install when replacing an existing target", async () => {
@@ -2576,12 +2579,7 @@ describe("installPluginFromArchive", () => {
2576257925772580expect(result.ok).toBe(true);
25782581expect(handler).toHaveBeenCalledTimes(1);
2579-expect(handler.mock.calls[0]?.[0]).toMatchObject({
2580-request: {
2581-kind: "plugin-dir",
2582-mode: "update",
2583-},
2584-});
2582+expectHookRequest(requireHookPayload(handler), { kind: "plugin-dir", mode: "update" });
25852583});
2586258425872585it("scans extension entry files in hidden directories", async () => {
@@ -2604,12 +2602,8 @@ describe("installPluginFromArchive", () => {
26042602const { result, warnings } = await installFromDirWithWarnings({ pluginDir, extensionsDir });
2605260326062604expect(result.ok).toBe(false);
2607-expect(warnings).toEqual(
2608-expect.arrayContaining([expect.stringContaining("hidden/node_modules path")]),
2609-);
2610-expect(warnings).toEqual(
2611-expect.arrayContaining([expect.stringContaining("dangerous code pattern")]),
2612-);
2605+expectWarningIncludes(warnings, "hidden/node_modules path");
2606+expectWarningIncludes(warnings, "dangerous code pattern");
26132607});
2614260826152609it("blocks install when scanner throws", async () => {
@@ -2823,9 +2817,7 @@ describe("installPluginFromDir", () => {
28232817});
2824281828252819expectInstalledWithPluginId(res, extensionsDir, "matrix");
2826-expect(infoMessages).not.toEqual(
2827-expect.arrayContaining([expect.stringContaining("differs from npm package name")]),
2828-);
2820+expectWarningExcludes(infoMessages, "differs from npm package name");
28292821});
2830282228312823it.each([
@@ -3078,8 +3070,6 @@ describe("linkOpenClawPeerDependencies (via installPluginFromDir)", () => {
30783070const { result, warnings } = await installFromDirWithWarnings({ pluginDir, extensionsDir });
3079307130803072expect(result.ok).toBe(true);
3081-expect(warnings).toEqual(
3082-expect.arrayContaining([expect.stringContaining("Could not locate openclaw package root")]),
3083-);
3073+expectWarningIncludes(warnings, "Could not locate openclaw package root");
30843074});
30853075});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。