import { afterEach, describe, expect, it, vi } from "vitest"; import { createAgentApiClient } from "./client"; afterEach(() => { vi.restoreAllMocks(); vi.unstubAllGlobals(); }); describe("authenticated session exports", () => { it("fetches only Agent session files with identity and project headers", async () => { const fetchMock = vi.fn(async () => new Response("ZIP", { headers: { "Content-Type": "application/zip" } })); vi.stubGlobal("fetch", fetchMock); vi.stubGlobal("URL", class extends URL { static createObjectURL = vi.fn(() => "blob:fixture"); static revokeObjectURL = vi.fn(); }); const click = vi.spyOn(HTMLAnchorElement.prototype, "click").mockImplementation(() => {}); const client = createAgentApiClient("https://agent.test", { getAccessToken: async () => "FIXTURE", getProjectId: async () => "project-a" }); const path = "/api/v1/session/session-a/files/mcp-11111111-1111-1111-1111-111111111111.zip"; await client.downloadFile(path); const [url, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]; expect(url).toBe(`https://agent.test${path}`); expect(new Headers(init.headers).get("Authorization")).toBe("Bearer FIXTURE"); expect(new Headers(init.headers).get("X-Project-Id")).toBe("project-a"); expect(init.redirect).toBe("error"); expect(click).toHaveBeenCalledOnce(); }); it("rejects arbitrary URLs and paths before requesting any credential", async () => { const getAccessToken = vi.fn(); const client = createAgentApiClient("https://agent.test", { getAccessToken }); for (const path of ["https://foreign.test/file.zip", "/api/v1/admin/files/a.zip", "/api/v1/session/s/files/secret.env", "/api/v1/session/s/files/../owner.json"]) { await expect(client.downloadFile(path)).rejects.toThrow("无效"); } expect(getAccessToken).not.toHaveBeenCalled(); }); });