import { beforeEach, describe, expect, it, vi } from "vitest"; const runInstallPolicyMock = vi.fn(); const findBlockedManifestDependenciesMock = vi.fn(); const findBlockedNodeModulesDirectoryMock = vi.fn(); const findBlockedNodeModulesFileAliasMock = vi.fn(); const findBlockedPackageDirectoryInPathMock = vi.fn(); const findBlockedPackageFileAliasInPathMock = vi.fn(); const getGlobalHookRunnerMock = vi.fn(); vi.mock("../security/install-policy.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, runInstallPolicy: (...args: unknown[]) => runInstallPolicyMock(...args), }; }); vi.mock("./dependency-denylist.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, findBlockedManifestDependencies: (...args: unknown[]) => findBlockedManifestDependenciesMock(...args), findBlockedNodeModulesDirectory: (...args: unknown[]) => findBlockedNodeModulesDirectoryMock(...args), findBlockedNodeModulesFileAlias: (...args: unknown[]) => findBlockedNodeModulesFileAliasMock(...args), findBlockedPackageDirectoryInPath: (...args: unknown[]) => findBlockedPackageDirectoryInPathMock(...args), findBlockedPackageFileAliasInPath: (...args: unknown[]) => findBlockedPackageFileAliasInPathMock(...args), }; }); vi.mock("./hook-runner-global.js", () => ({ getGlobalHookRunner: () => getGlobalHookRunnerMock(), })); const { evaluateSkillInstallPolicyRuntime, preflightPluginNpmInstallPolicyRuntime, scanBundleInstallSourceRuntime, scanFileInstallSourceRuntime, } = await import("./install-security-scan.runtime.js"); function expectOnlyOperatorPolicyRan() { expect(runInstallPolicyMock).toHaveBeenCalledTimes(1); expect(findBlockedManifestDependenciesMock).not.toHaveBeenCalled(); expect(findBlockedNodeModulesDirectoryMock).not.toHaveBeenCalled(); expect(findBlockedNodeModulesFileAliasMock).not.toHaveBeenCalled(); expect(findBlockedPackageDirectoryInPathMock).not.toHaveBeenCalled(); expect(findBlockedPackageFileAliasInPathMock).not.toHaveBeenCalled(); expect(getGlobalHookRunnerMock).not.toHaveBeenCalled(); } beforeEach(() => { runInstallPolicyMock.mockReset(); findBlockedManifestDependenciesMock.mockReset(); findBlockedNodeModulesDirectoryMock.mockReset(); findBlockedNodeModulesFileAliasMock.mockReset(); findBlockedPackageDirectoryInPathMock.mockReset(); findBlockedPackageFileAliasInPathMock.mockReset(); getGlobalHookRunnerMock.mockReset(); }); describe("install security scan official bypass", () => { it("bypasses plugin install friction for bundled OpenClaw sources", async () => { const result = await scanBundleInstallSourceRuntime({ logger: {}, pluginId: "openclaw/kitchen-sink", sourceDir: "/tmp/openclaw-bundled-plugin", source: { kind: "bundled", authority: "openclaw", mutable: false, network: false }, }); expect(result).toBeUndefined(); expectOnlyOperatorPolicyRan(); }); it("bypasses plugin install friction for official ClawHub sources", async () => { const result = await scanBundleInstallSourceRuntime({ logger: {}, pluginId: "@openclaw/matrix", sourceDir: "/tmp/openclaw-official-clawhub-plugin", source: { kind: "clawhub", authority: "official", mutable: false, network: true }, }); expect(result).toBeUndefined(); expectOnlyOperatorPolicyRan(); }); it("bypasses skill install friction for bundled OpenClaw sources", async () => { const result = await evaluateSkillInstallPolicyRuntime({ installId: "node", logger: {}, origin: { type: "openclaw-bundled", skillName: "peekaboo", installId: "node", }, source: { kind: "bundled", authority: "openclaw", mutable: false, network: false }, skillName: "peekaboo", sourceDir: "/tmp/openclaw-bundled-skill/peekaboo", }); expect(result).toBeUndefined(); expectOnlyOperatorPolicyRan(); }); it("runs only operator policy for official immutable npm sources", async () => { const result = await preflightPluginNpmInstallPolicyRuntime({ logger: {}, packageName: "@openclaw/matrix", requestedSpecifier: "@openclaw/matrix@latest", source: { kind: "npm", authority: "official", mutable: false, network: true }, sourcePath: "/tmp/openclaw-official-npm", sourcePathKind: "directory", }); expect(result).toBeUndefined(); expectOnlyOperatorPolicyRan(); }); it("lets operator policy block official sources", async () => { runInstallPolicyMock.mockResolvedValueOnce({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); const result = await scanBundleInstallSourceRuntime({ logger: {}, pluginId: "@openclaw/matrix", sourceDir: "/tmp/openclaw-official-clawhub-plugin", source: { kind: "clawhub", authority: "official", mutable: false, network: true }, }); expect(result).toEqual({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); expectOnlyOperatorPolicyRan(); }); it("still runs install policy for mutable workspace skill sources", async () => { runInstallPolicyMock.mockResolvedValueOnce({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); const result = await evaluateSkillInstallPolicyRuntime({ installId: "node", logger: {}, origin: { type: "workspace", skillName: "local-skill", installId: "node", }, source: { kind: "workspace", authority: "user", mutable: true, network: false }, skillName: "local-skill", sourceDir: "/tmp/local-skill", }); expect(result).toEqual({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); expect(runInstallPolicyMock).toHaveBeenCalledTimes(1); }); }); describe("legacy file install scan compatibility", () => { it("preserves policy and hook metadata for published lazy install chunks", async () => { const warnings: string[] = []; const hasHooks = vi.fn().mockReturnValue(true); const runBeforeInstall = vi.fn().mockResolvedValue(undefined); getGlobalHookRunnerMock.mockReturnValue({ hasHooks, runBeforeInstall }); runInstallPolicyMock.mockResolvedValueOnce({ findings: [ { ruleId: "registry-review", severity: "warn", message: "Registry requires review.", }, ], }); const result = await scanFileInstallSourceRuntime({ filePath: "/tmp/payload.js", logger: { warn: (message) => warnings.push(message) }, mode: "update", pluginId: "payload", requestedSpecifier: "./payload.js", }); expect(result).toBeUndefined(); expect(warnings).toEqual(["Install policy: Registry requires review."]); expect(runInstallPolicyMock).toHaveBeenCalledWith({ config: undefined, logger: expect.any(Object), request: { targetName: "payload", targetType: "plugin", sourcePath: "/tmp/payload.js", sourcePathKind: "file", source: { kind: "file", authority: "user", mutable: true, network: false }, origin: { type: "plugin-file" }, request: { kind: "plugin-file", mode: "update", requestedSpecifier: "./payload.js", }, plugin: { contentType: "file", pluginId: "payload", extensions: ["payload.js"], }, }, }); expect(hasHooks).toHaveBeenCalledWith("before_install"); expect(runBeforeInstall).toHaveBeenCalledWith( { targetName: "payload", targetType: "plugin", origin: "plugin-file", sourcePath: "/tmp/payload.js", sourcePathKind: "file", request: { kind: "plugin-file", mode: "update", requestedSpecifier: "./payload.js", }, builtinScan: { status: "ok", scannedFiles: 0, critical: 0, warn: 0, info: 0, findings: [], }, plugin: { contentType: "file", pluginId: "payload", extensions: ["payload.js"], }, }, { origin: "plugin-file", targetType: "plugin", requestKind: "plugin-file", }, ); }); it("returns operator policy blocks before invoking hooks", async () => { runInstallPolicyMock.mockResolvedValueOnce({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); const result = await scanFileInstallSourceRuntime({ filePath: "/tmp/payload.js", logger: {}, pluginId: "payload", }); expect(result).toEqual({ blocked: { code: "security_scan_blocked", reason: "blocked by operator policy", }, }); expect(getGlobalHookRunnerMock).not.toHaveBeenCalled(); }); });