diff --git a/extensions/whatsapp/src/auto-reply.test-harness.ts b/extensions/whatsapp/src/auto-reply.test-harness.ts index 0597dd27bd8..085a1d79e63 100644 --- a/extensions/whatsapp/src/auto-reply.test-harness.ts +++ b/extensions/whatsapp/src/auto-reply.test-harness.ts @@ -4,8 +4,8 @@ import os from "node:os"; import path from "node:path"; import { resetInboundDedupe } from "openclaw/plugin-sdk/reply-runtime"; import { resetLogger, setLoggerOverride } from "openclaw/plugin-sdk/runtime-env"; -import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/text-runtime"; import { afterAll, afterEach, beforeAll, beforeEach, vi, type Mock } from "vitest"; +import { mockPinnedHostnameResolution } from "../../../src/test-helpers/ssrf.js"; import type { WebInboundMessage, WebListenerCloseReason } from "./inbound.js"; import { resetBaileysMocks as _resetBaileysMocks, @@ -38,7 +38,7 @@ type WebAutoReplyMonitorHarness = { run: Promise; }; -export const TEST_NET_IP = "203.0.113.10"; +export const TEST_NET_IP = "93.184.216.34"; vi.mock("openclaw/plugin-sdk/agent-runtime", () => ({ abortEmbeddedPiRun: vi.fn().mockReturnValue(false), @@ -148,19 +148,7 @@ export function installWebAutoReplyUnitTestHooks(opts?: { pinDns?: boolean }) { _resetBaileysMocks(); _resetLoadConfigMock(); if (opts?.pinDns) { - const ssrf = await import("../../../src/infra/net/ssrf.js"); - resolvePinnedHostnameSpy = vi - .spyOn(ssrf, "resolvePinnedHostname") - .mockImplementation(async (hostname) => { - // SSRF guard pins DNS; stub resolution to avoid live lookups in unit tests. - const normalized = normalizeLowercaseStringOrEmpty(hostname).replace(/\.$/, ""); - const addresses = [TEST_NET_IP]; - return { - hostname: normalized, - addresses, - lookup: ssrf.createPinnedLookup({ hostname: normalized, addresses }), - }; - }); + resolvePinnedHostnameSpy = mockPinnedHostnameResolution([TEST_NET_IP]); } }); diff --git a/extensions/whatsapp/src/session.test.ts b/extensions/whatsapp/src/session.test.ts index 2d32bd49f2f..a9145de3bca 100644 --- a/extensions/whatsapp/src/session.test.ts +++ b/extensions/whatsapp/src/session.test.ts @@ -110,6 +110,17 @@ describe("web session", () => { }); it("does not create a proxy agent when no env proxy is configured", async () => { + for (const key of [ + "ALL_PROXY", + "all_proxy", + "HTTP_PROXY", + "http_proxy", + "HTTPS_PROXY", + "https_proxy", + ]) { + vi.stubEnv(key, ""); + } + await createWaSocket(false, false); const passed = (baileys.makeWASocket as ReturnType).mock.calls[0]?.[0] as { diff --git a/src/test-helpers/ssrf.ts b/src/test-helpers/ssrf.ts index df3e340fddb..9e6d85f5ee0 100644 --- a/src/test-helpers/ssrf.ts +++ b/src/test-helpers/ssrf.ts @@ -1,21 +1,28 @@ import { vi } from "vitest"; import * as ssrf from "../infra/net/ssrf.js"; +import type { LookupFn } from "../infra/net/ssrf.js"; import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js"; export function mockPinnedHostnameResolution(addresses: string[] = ["93.184.216.34"]) { - const resolve = async (hostname: string) => { + const resolvePinnedHostname = ssrf.resolvePinnedHostname; + const resolvePinnedHostnameWithPolicy = ssrf.resolvePinnedHostnameWithPolicy; + const lookupFn = (async (hostname: string, options?: { all?: boolean }) => { const normalized = normalizeLowercaseStringOrEmpty(hostname).replace(/\.$/, ""); - const pinnedAddresses = [...addresses]; - return { + const resolved = addresses.map((address) => ({ + address, + family: address.includes(":") ? 6 : 4, hostname: normalized, - addresses: pinnedAddresses, - lookup: ssrf.createPinnedLookup({ hostname: normalized, addresses: pinnedAddresses }), - }; - }; - const pinned = vi.spyOn(ssrf, "resolvePinnedHostname").mockImplementation(resolve); + })); + return options?.all === true ? resolved : resolved[0]; + }) as LookupFn; + const pinned = vi + .spyOn(ssrf, "resolvePinnedHostname") + .mockImplementation((hostname) => resolvePinnedHostname(hostname, lookupFn)); const pinnedWithPolicy = vi .spyOn(ssrf, "resolvePinnedHostnameWithPolicy") - .mockImplementation(async (hostname) => resolve(hostname)); + .mockImplementation((hostname, params) => + resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn }), + ); return { mockRestore: () => { pinned.mockRestore();