From 678b01946709d73c51f2b0bae8793846a0f8a757 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 16 Apr 2026 22:08:19 +0100 Subject: [PATCH] test: stabilize config and plugin scanner tests --- src/config/config.web-search-provider.test.ts | 14 ++++---------- src/security/skill-scanner.test.ts | 11 +++++++++++ src/security/skill-scanner.ts | 5 +++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/config/config.web-search-provider.test.ts b/src/config/config.web-search-provider.test.ts index bdde2828947..f749200e436 100644 --- a/src/config/config.web-search-provider.test.ts +++ b/src/config/config.web-search-provider.test.ts @@ -1,5 +1,7 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { __testing as webSearchTesting } from "../agents/tools/web-search.js"; import { buildWebSearchProviderConfig } from "./test-helpers.js"; +import { validateConfigObjectWithPlugins } from "./validation.js"; vi.mock("../runtime.js", () => ({ defaultRuntime: { log: vi.fn(), error: vi.fn() }, @@ -225,15 +227,7 @@ vi.mock("../plugins/manifest-registry.js", () => { }; }); -let validateConfigObjectWithPlugins: typeof import("./validation.js").validateConfigObjectWithPlugins; -let resolveSearchProvider: typeof import("../agents/tools/web-search.js").__testing.resolveSearchProvider; - -beforeAll(async () => { - ({ validateConfigObjectWithPlugins } = await import("./validation.js")); - ({ - __testing: { resolveSearchProvider }, - } = await import("../agents/tools/web-search.js")); -}); +const { resolveSearchProvider } = webSearchTesting; describe("web search provider config", () => { it("does not warn for brave plugin config when bundled web search allowlist compat applies", () => { diff --git a/src/security/skill-scanner.test.ts b/src/security/skill-scanner.test.ts index 00ba458801a..30397cd8084 100644 --- a/src/security/skill-scanner.test.ts +++ b/src/security/skill-scanner.test.ts @@ -195,6 +195,17 @@ console.log(json); const findings = scanSource(source, "plugin.ts"); expect(findings).toEqual([]); }); + + it("does not treat fetch in names or comments as network send context", () => { + const source = ` +const inheritedOutputPath = process.env.OPENCLAW_RUN_NODE_OUTPUT_LOG?.trim(); +async function closeFetchHandles() { + // Best-effort cleanup for stale fetch keep-alive handles. +} +`; + const findings = scanSource(source, "plugin.ts"); + expect(findings.some((f) => f.ruleId === "env-harvesting")).toBe(false); + }); }); // --------------------------------------------------------------------------- diff --git a/src/security/skill-scanner.ts b/src/security/skill-scanner.ts index 18f87726f36..45a57c2711c 100644 --- a/src/security/skill-scanner.ts +++ b/src/security/skill-scanner.ts @@ -173,6 +173,7 @@ const LINE_RULES: LineRule[] = [ ]; const STANDARD_PORTS = new Set([80, 443, 8080, 8443, 3000]); +const NETWORK_SEND_CONTEXT_PATTERN = /\bfetch\s*\(|\bpost\s*\(|\.\s*post\s*\(|http\.request\s*\(/i; const SOURCE_RULES: SourceRule[] = [ { @@ -180,7 +181,7 @@ const SOURCE_RULES: SourceRule[] = [ severity: "warn", message: "File read combined with network send — possible data exfiltration", pattern: /readFileSync|readFile/, - requiresContext: /\bfetch\b|\bpost\b|http\.request/i, + requiresContext: NETWORK_SEND_CONTEXT_PATTERN, }, { ruleId: "obfuscated-code", @@ -200,7 +201,7 @@ const SOURCE_RULES: SourceRule[] = [ message: "Environment variable access combined with network send — possible credential harvesting", pattern: /process\.env/, - requiresContext: /\bfetch\b|\bpost\b|http\.request/i, + requiresContext: NETWORK_SEND_CONTEXT_PATTERN, }, ];