openclaw/src/agents/tools/web-search.redirect.test.ts
2026-03-02 15:54:46 +00:00

49 lines
1.6 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const { fetchWithSsrFGuardMock } = vi.hoisted(() => ({
fetchWithSsrFGuardMock: vi.fn(),
}));
vi.mock("../../infra/net/fetch-guard.js", () => ({
fetchWithSsrFGuard: fetchWithSsrFGuardMock,
}));
import { __testing } from "./web-search.js";
describe("web_search redirect resolution hardening", () => {
const { resolveRedirectUrl } = __testing;
beforeEach(() => {
fetchWithSsrFGuardMock.mockReset();
});
it("resolves redirects via SSRF-guarded HEAD requests", async () => {
const release = vi.fn(async () => {});
fetchWithSsrFGuardMock.mockResolvedValue({
response: new Response(null, { status: 200 }),
finalUrl: "https://example.com/final",
release,
});
const resolved = await resolveRedirectUrl("https://example.com/start");
expect(resolved).toBe("https://example.com/final");
expect(fetchWithSsrFGuardMock).toHaveBeenCalledWith(
expect.objectContaining({
url: "https://example.com/start",
timeoutMs: 5000,
init: { method: "HEAD" },
}),
);
expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]?.proxy).toBeUndefined();
expect(fetchWithSsrFGuardMock.mock.calls[0]?.[0]?.policy).toBeUndefined();
expect(release).toHaveBeenCalledTimes(1);
});
it("falls back to the original URL when guarded resolution fails", async () => {
fetchWithSsrFGuardMock.mockRejectedValue(new Error("blocked"));
await expect(resolveRedirectUrl("https://example.com/start")).resolves.toBe(
"https://example.com/start",
);
});
});