chat-ui-agent-demo / src /lib /server /agent /gitProxy.spec.ts
Mike0021's picture
deploy: production agent journey fixes (part 2)
77374bd verified
Raw History Blame Contribute Delete
12.9 kB
import { beforeEach, describe, expect, it, vi } from "vitest";
import { ObjectId } from "mongodb";
import type { Workspace } from "$lib/types/Workspace";
const mocks = vi.hoisted(() => ({
workspaceFindOne: vi.fn(),
sessionFindOne: vi.fn(),
findUser: vi.fn(),
config: {
USE_USER_TOKEN: "false",
OPENAI_API_KEY: "hf_inference_service_must_not_clone",
HF_TOKEN: "hf_jobs_service_must_not_clone",
},
}));
vi.mock("$lib/server/database", () => ({
collections: {
workspaces: { findOne: mocks.workspaceFindOne },
sessions: { findOne: mocks.sessionFindOne },
},
}));
vi.mock("$lib/server/config", () => ({ config: mocks.config }));
vi.mock("$lib/server/auth", () => ({ findUser: mocks.findUser }));
import { AGENT_PROXY_MAX_BODY_BYTES, issueAgentProxyCredential } from "./llmProxy";
import { GET, HEAD, POST } from "../../../routes/api/agent/git/[...path]/+server";
const NOW = new Date("2026-08-20T00:00:00.000Z");
const OWNER_HF_TOKEN = "hf_owner_oauth_server_side_only";
function workspace(
tokenHash: string,
repo: Workspace["repo"] = { kind: "hf", repoType: "space", ref: "owner/private-app" }
): Workspace {
return {
_id: new ObjectId(),
conversationId: new ObjectId(),
userId: new ObjectId(),
sessionId: "owner-session",
repo,
branch: "main",
flavor: "cpu-basic",
model: "moonshotai/Kimi-K2.7-Code",
thinkingLevel: "medium",
policy: "auto",
sandbox: {
status: "provisioning",
id: "job-agent-git-proxy",
namespace: "service-owner",
baseUrl: "https://job-agent-git-proxy--49983.hf.jobs",
nonce: "nonce-git-proxy",
image: "hf.co/spaces/example/runtime",
flavor: "cpu-basic",
},
llmProxy: {
tokenHash,
createdAt: NOW,
expiresAt: new Date("2100-01-01T00:00:00Z"),
allowedModels: ["moonshotai/Kimi-K2.7-Code"],
},
spend: { accruedUsd: 0 },
createdAt: NOW,
updatedAt: NOW,
};
}
async function arrange(repo?: Workspace["repo"]) {
const credential = await issueAgentProxyCredential(["moonshotai/Kimi-K2.7-Code"]);
const value = workspace(credential.tokenHash, repo);
mocks.workspaceFindOne.mockResolvedValue(value);
mocks.sessionFindOne.mockResolvedValue({ sessionId: "owner-session" });
mocks.findUser.mockResolvedValue({
user: null,
invalidateSession: false,
oauth: { token: { value: OWNER_HF_TOKEN, expiresAt: new Date(Date.now() + 60_000) } },
});
return { credential, workspace: value };
}
function infoRequest(token: string, method = "GET", suffix = "") {
return new Request(
`https://chat.example/api/agent/git/repository.git/info/refs?service=git-upload-pack${suffix}`,
{
method,
headers: {
accept: "application/x-git-upload-pack-advertisement",
authorization: "Bearer attacker-controlled",
cookie: "browser=session",
"git-protocol": "version=2",
"x-agent-session": token,
},
}
);
}
function uploadRequest(token: string, body: BodyInit, headers: Record<string, string> = {}) {
return new Request("https://chat.example/api/agent/git/repository.git/git-upload-pack", {
method: "POST",
headers: {
"content-type": "application/x-git-upload-pack-request",
"x-agent-session": token,
...headers,
},
body,
});
}
beforeEach(() => {
vi.restoreAllMocks();
mocks.workspaceFindOne.mockReset();
mocks.sessionFindOne.mockReset();
mocks.findUser.mockReset();
vi.stubGlobal("fetch", vi.fn());
});
describe("agent Hugging Face Git smart-HTTP proxy", () => {
it("derives the exact Space repo and attaches owner OAuth server-side even when inference user tokens are disabled", async () => {
const { credential } = await arrange();
vi.mocked(fetch).mockResolvedValue(
new Response("001e# service=git-upload-pack\n0000", {
status: 200,
headers: {
"content-type": "application/x-git-upload-pack-advertisement",
"set-cookie": "hub=secret",
location: "https://evil.example/",
"x-reflected-auth": OWNER_HF_TOKEN,
},
})
);
const response = await GET({
request: infoRequest(credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(200);
expect(fetch).toHaveBeenCalledOnce();
const [url, init] = vi.mocked(fetch).mock.calls[0];
expect(String(url)).toBe(
"https://huggingface.co/spaces/owner/private-app.git/info/refs?service=git-upload-pack"
);
const upstreamHeaders = new Headers(init?.headers);
expect(upstreamHeaders.get("authorization")).toBe(`Bearer ${OWNER_HF_TOKEN}`);
expect(upstreamHeaders.get("git-protocol")).toBe("version=2");
expect(upstreamHeaders.get("x-agent-session")).toBeNull();
expect(upstreamHeaders.get("cookie")).toBeNull();
expect(init?.redirect).toBe("manual");
expect(response.headers.get("set-cookie")).toBeNull();
expect(response.headers.get("location")).toBeNull();
expect(response.headers.get("x-reflected-auth")).toBeNull();
expect(response.headers.get("cache-control")).toBe("no-store");
expect(await response.text()).not.toContain(OWNER_HF_TOKEN);
expect(mocks.config.USE_USER_TOKEN).toBe("false");
});
it.each([
[
"model",
"owner/source",
"https://huggingface.co/owner/source.git/info/refs?service=git-upload-pack",
],
[
"dataset",
"owner/source",
"https://huggingface.co/datasets/owner/source.git/info/refs?service=git-upload-pack",
],
] as const)(
"confines a %s checkout to its persisted repo type and ref",
async (repoType, ref, expected) => {
const { credential } = await arrange({ kind: "hf", repoType, ref });
vi.mocked(fetch).mockResolvedValue(
new Response("advertisement", {
headers: { "content-type": "application/x-git-upload-pack-advertisement" },
})
);
const response = await GET({
request: infoRequest(credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(200);
expect(String(vi.mocked(fetch).mock.calls[0][0])).toBe(expected);
}
);
it("uses anonymous Hub access for a public repo instead of falling back to service credentials", async () => {
const { credential } = await arrange();
mocks.sessionFindOne.mockResolvedValue(null);
vi.mocked(fetch).mockResolvedValue(
new Response("advertisement", {
headers: { "content-type": "application/x-git-upload-pack-advertisement" },
})
);
const response = await GET({
request: infoRequest(credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(200);
const headers = new Headers(vi.mocked(fetch).mock.calls[0][1]?.headers);
expect(headers.get("authorization")).toBeNull();
expect(JSON.stringify([...headers])).not.toContain(mocks.config.OPENAI_API_KEY);
expect(JSON.stringify([...headers])).not.toContain(mocks.config.HF_TOKEN);
});
it("streams upload-pack bytes while forwarding only the allowlisted request headers", async () => {
const { credential } = await arrange({ kind: "hf", repoType: "dataset", ref: "owner/data" });
const result = Uint8Array.from([0, 1, 2, 3, 255]);
vi.mocked(fetch).mockResolvedValue(
new Response(result, {
headers: { "content-type": "application/x-git-upload-pack-result" },
})
);
const requestBody = Buffer.from("000eversion 2\n0000");
const response = await POST({
request: uploadRequest(credential.token, requestBody),
params: { path: "repository.git/git-upload-pack" },
} as never);
expect(response.status).toBe(200);
expect(new Uint8Array(await response.arrayBuffer())).toEqual(result);
const [url, init] = vi.mocked(fetch).mock.calls[0];
expect(String(url)).toBe("https://huggingface.co/datasets/owner/data.git/git-upload-pack");
expect(new Uint8Array(init?.body as ArrayBuffer)).toEqual(new Uint8Array(requestBody));
expect(new Headers(init?.headers).get("authorization")).toBe(`Bearer ${OWNER_HF_TOKEN}`);
});
it("supports HEAD only for the exact upload-pack advertisement", async () => {
const { credential } = await arrange();
vi.mocked(fetch).mockResolvedValue(
new Response(null, {
headers: { "content-type": "application/x-git-upload-pack-advertisement" },
})
);
const response = await HEAD({
request: infoRequest(credential.token, "HEAD"),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(200);
expect(vi.mocked(fetch).mock.calls[0][1]?.method).toBe("HEAD");
expect(await response.text()).toBe("");
});
it.each([
"other.git/info/refs",
"repository.git/git-receive-pack",
"repository.git/info/lfs/objects/batch",
"repository.git/../../owner/other.git/info/refs",
"models/expensive-model",
])(
"rejects cross-repo or operation escalation path %s before any upstream request",
async (path) => {
const { credential } = await arrange();
const response = await GET({
request: infoRequest(credential.token),
params: { path },
} as never);
expect(response.status).toBe(404);
expect(fetch).not.toHaveBeenCalled();
}
);
it("rejects extra query controls, non-HF workspaces, and invalid persisted refs", async () => {
let arranged = await arrange();
let response = await GET({
request: infoRequest(arranged.credential.token, "GET", "&repo=attacker/other"),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(404);
arranged = await arrange({ kind: "git", ref: "https://example.com/public.git" });
response = await GET({
request: infoRequest(arranged.credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(403);
arranged = await arrange({
kind: "hf",
repoType: "space",
ref: "owner/valid" as string,
});
arranged.workspace.repo = {
kind: "hf",
repoType: "space",
ref: "owner/../../other",
};
response = await GET({
request: infoRequest(arranged.credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(403);
expect(fetch).not.toHaveBeenCalled();
});
it("rejects unsupported methods and upload-pack media types", async () => {
const { credential } = await arrange();
let response = await GET({
request: infoRequest(credential.token, "DELETE"),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(405);
response = await POST({
request: uploadRequest(credential.token, "payload", { "content-type": "application/json" }),
params: { path: "repository.git/git-upload-pack" },
} as never);
expect(response.status).toBe(415);
expect(fetch).not.toHaveBeenCalled();
});
it("enforces both declared and streamed 8 MiB upload-pack request limits", async () => {
const { credential } = await arrange();
let response = await POST({
request: uploadRequest(credential.token, "x", {
"content-length": String(AGENT_PROXY_MAX_BODY_BYTES + 1),
}),
params: { path: "repository.git/git-upload-pack" },
} as never);
expect(response.status).toBe(413);
response = await POST({
request: uploadRequest(credential.token, Buffer.alloc(AGENT_PROXY_MAX_BODY_BYTES + 1)),
params: { path: "repository.git/git-upload-pack" },
} as never);
expect(response.status).toBe(413);
expect(fetch).not.toHaveBeenCalled();
});
it("never reflects upstream errors, redirects, cookies, or the raw owner credential", async () => {
const { credential } = await arrange();
vi.mocked(fetch).mockResolvedValue(
new Response(`denied: ${OWNER_HF_TOKEN}`, {
status: 401,
headers: {
location: `https://example.com/?token=${OWNER_HF_TOKEN}`,
"set-cookie": `token=${OWNER_HF_TOKEN}`,
"www-authenticate": `Bearer token=${OWNER_HF_TOKEN}`,
},
})
);
const response = await GET({
request: infoRequest(credential.token),
params: { path: "repository.git/info/refs" },
} as never);
const serialized = `${JSON.stringify([...response.headers])}\n${await response.text()}`;
expect(response.status).toBe(403);
expect(serialized).toContain("Reconnect Hugging Face");
expect(serialized).not.toContain(OWNER_HF_TOKEN);
expect(response.headers.get("location")).toBeNull();
expect(response.headers.get("set-cookie")).toBeNull();
expect(response.headers.get("www-authenticate")).toBeNull();
});
it("returns an actionable non-challenge error when a private repo has no owner OAuth", async () => {
const { credential } = await arrange();
mocks.sessionFindOne.mockResolvedValue(null);
vi.mocked(fetch).mockResolvedValue(
new Response("private upstream detail", {
status: 401,
headers: { "www-authenticate": "Basic realm=private" },
})
);
const response = await GET({
request: infoRequest(credential.token),
params: { path: "repository.git/info/refs" },
} as never);
expect(response.status).toBe(403);
expect(await response.text()).toBe("Sign in with Hugging Face to access this repository\n");
expect(response.headers.get("www-authenticate")).toBeNull();
});
});