diff --git a/extensions/browser/src/browser/cdp.test.ts b/extensions/browser/src/browser/cdp.test.ts index a846bab80b3..64b291db72a 100644 --- a/extensions/browser/src/browser/cdp.test.ts +++ b/extensions/browser/src/browser/cdp.test.ts @@ -1,5 +1,5 @@ import { createServer } from "node:http"; -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { type WebSocket, WebSocketServer } from "ws"; import { SsrFBlockedError } from "../infra/net/ssrf.js"; import { rawDataToString } from "../infra/ws.js"; @@ -9,6 +9,21 @@ import { parseHttpUrl } from "./config.js"; import { BrowserCdpEndpointBlockedError } from "./errors.js"; import { InvalidBrowserNavigationUrlError } from "./navigation-guard.js"; +vi.mock("openclaw/plugin-sdk/browser-security-runtime", async () => { + const actual = await vi.importActual< + typeof import("openclaw/plugin-sdk/browser-security-runtime") + >("openclaw/plugin-sdk/browser-security-runtime"); + const lookupFn = async (_hostname: string, options?: { all?: boolean }) => { + const result = { address: "93.184.216.34", family: 4 }; + return options?.all === true ? [result] : result; + }; + return { + ...actual, + resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) => + actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }), + }; +}); + describe("cdp", () => { let httpServer: ReturnType | null = null; let wsServer: WebSocketServer | null = null; @@ -57,6 +72,7 @@ describe("cdp", () => { }; afterEach(async () => { + vi.unstubAllEnvs(); await new Promise((resolve) => { if (!httpServer) { return resolve(); @@ -487,3 +503,17 @@ describe("parseHttpUrl with WebSocket protocols", () => { expect(() => parseHttpUrl("file:///etc/passwd", "test")).toThrow("must be http(s) or ws(s)"); }); }); +const proxyEnvKeys = [ + "ALL_PROXY", + "all_proxy", + "HTTP_PROXY", + "http_proxy", + "HTTPS_PROXY", + "https_proxy", +] as const; + +beforeEach(() => { + for (const key of proxyEnvKeys) { + vi.stubEnv(key, ""); + } +}); diff --git a/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts b/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts index d7658eb0c8e..c9dac3ddf65 100644 --- a/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts +++ b/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts @@ -1,6 +1,42 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { BrowserDispatchResponse } from "./routes/dispatcher.js"; +vi.mock("openclaw/plugin-sdk/browser-security-runtime", async () => { + const actual = await vi.importActual< + typeof import("openclaw/plugin-sdk/browser-security-runtime") + >("openclaw/plugin-sdk/browser-security-runtime"); + const lookupFn = async (_hostname: string, options?: { all?: boolean }) => { + const result = { address: "93.184.216.34", family: 4 }; + return options?.all === true ? [result] : result; + }; + return { + ...actual, + resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) => + actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }), + }; +}); + +vi.mock("openclaw/plugin-sdk/ssrf-runtime", async () => { + const actual = await vi.importActual( + "openclaw/plugin-sdk/ssrf-runtime", + ); + return { + ...actual, + fetchWithSsrFGuard: async (params: { + url: string; + init?: RequestInit; + signal?: AbortSignal; + }) => ({ + response: await fetch(params.url, { + ...params.init, + signal: params.signal, + }), + finalUrl: params.url, + release: async () => {}, + }), + }; +}); + function okDispatchResponse(): BrowserDispatchResponse { return { status: 200, body: { ok: true } }; } @@ -87,6 +123,16 @@ async function expectThrownBrowserFetchError( describe("fetchBrowserJson loopback auth", () => { beforeEach(() => { vi.restoreAllMocks(); + for (const key of [ + "ALL_PROXY", + "all_proxy", + "HTTP_PROXY", + "http_proxy", + "HTTPS_PROXY", + "https_proxy", + ]) { + vi.stubEnv(key, ""); + } vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "loopback-token"); mocks.loadConfig.mockClear(); mocks.loadConfig.mockReturnValue({ diff --git a/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts b/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts index d8b003a9975..947c02af9ed 100644 --- a/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts +++ b/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts @@ -1,5 +1,5 @@ import { chromium } from "playwright-core"; -import { afterEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { SsrFBlockedError } from "../infra/net/ssrf.js"; import * as chromeModule from "./chrome.js"; import { BrowserTabNotFoundError } from "./errors.js"; @@ -15,9 +15,33 @@ import { listPagesViaPlaywright, } from "./pw-session.js"; +vi.mock("openclaw/plugin-sdk/browser-security-runtime", async () => { + const actual = await vi.importActual< + typeof import("openclaw/plugin-sdk/browser-security-runtime") + >("openclaw/plugin-sdk/browser-security-runtime"); + const lookupFn = async (_hostname: string, options?: { all?: boolean }) => { + const result = { address: "93.184.216.34", family: 4 }; + return options?.all === true ? [result] : result; + }; + return { + ...actual, + resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) => + actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }), + }; +}); + const connectOverCdpSpy = vi.spyOn(chromium, "connectOverCDP"); const getChromeWebSocketUrlSpy = vi.spyOn(chromeModule, "getChromeWebSocketUrl"); +const PROXY_ENV_KEYS = [ + "ALL_PROXY", + "all_proxy", + "HTTP_PROXY", + "http_proxy", + "HTTPS_PROXY", + "https_proxy", +] as const; + type MockRoute = { continue: () => Promise; abort: () => Promise }; type MockRequest = { isNavigationRequest: () => boolean; @@ -170,7 +194,14 @@ function mockBlockedRedirectNavigation(params: { }); } +beforeEach(() => { + for (const key of PROXY_ENV_KEYS) { + vi.stubEnv(key, ""); + } +}); + afterEach(async () => { + vi.unstubAllEnvs(); connectOverCdpSpy.mockClear(); getChromeWebSocketUrlSpy.mockClear(); await closePlaywrightBrowserConnection().catch(() => {}); diff --git a/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts b/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts index 6ba53aad084..8fcc8542519 100644 --- a/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts +++ b/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts @@ -7,6 +7,21 @@ import { setPwToolsCoreCurrentPage, } from "./pw-tools-core.test-harness.js"; +vi.mock("openclaw/plugin-sdk/browser-security-runtime", async () => { + const actual = await vi.importActual< + typeof import("openclaw/plugin-sdk/browser-security-runtime") + >("openclaw/plugin-sdk/browser-security-runtime"); + const lookupFn = async (_hostname: string, options?: { all?: boolean }) => { + const result = { address: "93.184.216.34", family: 4 }; + return options?.all === true ? [result] : result; + }; + return { + ...actual, + resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) => + actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }), + }; +}); + installPwToolsCoreTestHooks(); const mod = await import("./pw-tools-core.snapshot.js"); diff --git a/extensions/browser/src/browser/server-context.existing-session.test.ts b/extensions/browser/src/browser/server-context.existing-session.test.ts index 74c95c4815a..2ebe0265b31 100644 --- a/extensions/browser/src/browser/server-context.existing-session.test.ts +++ b/extensions/browser/src/browser/server-context.existing-session.test.ts @@ -1,7 +1,22 @@ import fs from "node:fs"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { BrowserServerState } from "./server-context.js"; +vi.mock("openclaw/plugin-sdk/browser-security-runtime", async () => { + const actual = await vi.importActual< + typeof import("openclaw/plugin-sdk/browser-security-runtime") + >("openclaw/plugin-sdk/browser-security-runtime"); + const lookupFn = async (_hostname: string, options?: { all?: boolean }) => { + const result = { address: "93.184.216.34", family: 4 }; + return options?.all === true ? [result] : result; + }; + return { + ...actual, + resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) => + actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }), + }; +}); + vi.mock("./chrome-mcp.js", () => ({ closeChromeMcpSession: vi.fn(async () => true), ensureChromeMcpAvailable: vi.fn(async () => {}), @@ -59,9 +74,23 @@ function makeState(): BrowserServerState { } beforeEach(() => { + for (const key of [ + "ALL_PROXY", + "all_proxy", + "HTTP_PROXY", + "http_proxy", + "HTTPS_PROXY", + "https_proxy", + ]) { + vi.stubEnv(key, ""); + } vi.clearAllMocks(); }); +afterEach(() => { + vi.unstubAllEnvs(); +}); + describe("browser server-context existing-session profile", () => { it("routes tab operations through the Chrome MCP backend", async () => { fs.mkdirSync("/tmp/brave-profile", { recursive: true });