forked from bai/curriculum-project-hub
1f48c5b707
This reverts commit ebf870249f.
184 lines
7.0 KiB
TypeScript
184 lines
7.0 KiB
TypeScript
import { createServer } from "node:http";
|
|
import { once } from "node:events";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import { openProviderProxyLease, type AgentProviderLease } from "../../src/connections/providerProxy.js";
|
|
|
|
const leases: AgentProviderLease[] = [];
|
|
const upstreamServers: ReturnType<typeof createServer>[] = [];
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(leases.splice(0).map((lease) => lease.close()));
|
|
await Promise.all(upstreamServers.splice(0).map(async (server) => {
|
|
server.closeAllConnections();
|
|
if (server.listening) {
|
|
server.close();
|
|
await once(server, "close");
|
|
}
|
|
}));
|
|
});
|
|
|
|
describe("run-scoped provider proxy", () => {
|
|
it("keeps the Organization provider credential out of the Agent environment", async () => {
|
|
const observed: Array<{ authorization: string | undefined; apiKey: string | undefined; body: string }> = [];
|
|
const upstream = createServer((request, response) => {
|
|
const chunks: Buffer[] = [];
|
|
request.on("data", (chunk: Buffer) => chunks.push(chunk));
|
|
request.on("end", () => {
|
|
observed.push({
|
|
authorization: request.headers.authorization,
|
|
apiKey: header(request.headers["x-api-key"]),
|
|
body: Buffer.concat(chunks).toString("utf8"),
|
|
});
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ ok: true }));
|
|
});
|
|
});
|
|
upstreamServers.push(upstream);
|
|
upstream.listen(0, "127.0.0.1");
|
|
await once(upstream, "listening");
|
|
const address = upstream.address();
|
|
if (address === null || typeof address === "string") throw new Error("expected upstream TCP address");
|
|
|
|
const lease = await openProviderProxyLease({
|
|
baseUrl: `http://127.0.0.1:${address.port}/api`,
|
|
authToken: "customer-provider-auth-token",
|
|
anthropicApiKey: "customer-provider-api-key",
|
|
});
|
|
leases.push(lease);
|
|
|
|
const serializedAgentEnv = JSON.stringify(lease.sdkEnv);
|
|
expect(serializedAgentEnv).not.toContain("customer-provider-auth-token");
|
|
expect(serializedAgentEnv).not.toContain("customer-provider-api-key");
|
|
expect(serializedAgentEnv).not.toContain(String(address.port));
|
|
expect(lease.sdkEnv).toMatchObject({
|
|
ANTHROPIC_BASE_URL: expect.stringMatching(/^http:\/\/127\.0\.0\.1:\d+$/),
|
|
ANTHROPIC_AUTH_TOKEN: "",
|
|
ANTHROPIC_API_KEY: expect.any(String),
|
|
});
|
|
|
|
const response = await fetch(`${lease.sdkEnv.ANTHROPIC_BASE_URL}/v1/messages`, {
|
|
method: "POST",
|
|
headers: {
|
|
"x-api-key": lease.sdkEnv.ANTHROPIC_API_KEY ?? "",
|
|
"content-type": "application/json",
|
|
"anthropic-version": "2023-06-01",
|
|
},
|
|
body: JSON.stringify({ model: "test" }),
|
|
});
|
|
|
|
expect(response.status).toBe(200);
|
|
await expect(response.json()).resolves.toEqual({ ok: true });
|
|
expect(observed).toEqual([{
|
|
authorization: "Bearer customer-provider-auth-token",
|
|
apiKey: "customer-provider-api-key",
|
|
body: JSON.stringify({ model: "test" }),
|
|
}]);
|
|
});
|
|
|
|
it("rejects requests without the run capability before contacting upstream", async () => {
|
|
let upstreamRequests = 0;
|
|
const diagnostics: unknown[] = [];
|
|
const upstream = createServer((_request, response) => {
|
|
upstreamRequests += 1;
|
|
response.end("unexpected");
|
|
});
|
|
upstreamServers.push(upstream);
|
|
upstream.listen(0, "127.0.0.1");
|
|
await once(upstream, "listening");
|
|
const address = upstream.address();
|
|
if (address === null || typeof address === "string") throw new Error("expected upstream TCP address");
|
|
const lease = await openProviderProxyLease(
|
|
{
|
|
baseUrl: `http://127.0.0.1:${address.port}`,
|
|
authToken: "customer-secret",
|
|
anthropicApiKey: "",
|
|
},
|
|
{ onDiagnostic: (diagnostic) => diagnostics.push(diagnostic) },
|
|
);
|
|
leases.push(lease);
|
|
|
|
const response = await fetch(`${lease.sdkEnv.ANTHROPIC_BASE_URL}/v1/messages`, {
|
|
method: "POST",
|
|
body: "{}",
|
|
});
|
|
|
|
expect(response.status).toBe(401);
|
|
expect(upstreamRequests).toBe(0);
|
|
expect(diagnostics).toEqual([{ code: "provider_proxy_unauthorized", category: "authorization" }]);
|
|
});
|
|
|
|
it("accepts the run capability in the Anthropic x-api-key header", async () => {
|
|
let upstreamRequests = 0;
|
|
const upstream = createServer((_request, response) => {
|
|
upstreamRequests += 1;
|
|
response.writeHead(200, { "content-type": "application/json" });
|
|
response.end(JSON.stringify({ ok: true }));
|
|
});
|
|
upstreamServers.push(upstream);
|
|
upstream.listen(0, "127.0.0.1");
|
|
await once(upstream, "listening");
|
|
const address = upstream.address();
|
|
if (address === null || typeof address === "string") throw new Error("expected upstream TCP address");
|
|
const lease = await openProviderProxyLease({
|
|
baseUrl: `http://127.0.0.1:${address.port}`,
|
|
authToken: "customer-secret",
|
|
anthropicApiKey: "",
|
|
});
|
|
leases.push(lease);
|
|
|
|
const response = await fetch(`${lease.sdkEnv.ANTHROPIC_BASE_URL}/v1/messages`, {
|
|
headers: { "x-api-key": lease.sdkEnv.ANTHROPIC_API_KEY ?? "" },
|
|
});
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(upstreamRequests).toBe(1);
|
|
});
|
|
|
|
it("does not forward provider credentials across an upstream redirect", async () => {
|
|
let redirectedRequests = 0;
|
|
const diagnostics: unknown[] = [];
|
|
const redirectTarget = createServer((_request, response) => {
|
|
redirectedRequests += 1;
|
|
response.end("leaked");
|
|
});
|
|
upstreamServers.push(redirectTarget);
|
|
redirectTarget.listen(0, "127.0.0.1");
|
|
await once(redirectTarget, "listening");
|
|
const targetAddress = redirectTarget.address();
|
|
if (targetAddress === null || typeof targetAddress === "string") throw new Error("expected redirect target address");
|
|
|
|
const upstream = createServer((_request, response) => {
|
|
response.writeHead(307, { location: `http://127.0.0.1:${targetAddress.port}/capture` });
|
|
response.end();
|
|
});
|
|
upstreamServers.push(upstream);
|
|
upstream.listen(0, "127.0.0.1");
|
|
await once(upstream, "listening");
|
|
const upstreamAddress = upstream.address();
|
|
if (upstreamAddress === null || typeof upstreamAddress === "string") throw new Error("expected upstream address");
|
|
const lease = await openProviderProxyLease(
|
|
{
|
|
baseUrl: `http://127.0.0.1:${upstreamAddress.port}`,
|
|
authToken: "customer-secret",
|
|
anthropicApiKey: "",
|
|
},
|
|
{ onDiagnostic: (diagnostic) => diagnostics.push(diagnostic) },
|
|
);
|
|
leases.push(lease);
|
|
|
|
const response = await fetch(`${lease.sdkEnv.ANTHROPIC_BASE_URL}/v1/messages`, {
|
|
headers: { "x-api-key": lease.sdkEnv.ANTHROPIC_API_KEY ?? "" },
|
|
redirect: "manual",
|
|
});
|
|
|
|
expect(response.status).toBe(502);
|
|
await expect(response.text()).resolves.toBe("provider redirect refused");
|
|
expect(redirectedRequests).toBe(0);
|
|
expect(diagnostics).toEqual([{ code: "provider_proxy_redirect_refused", category: "redirect" }]);
|
|
});
|
|
});
|
|
|
|
function header(value: string | string[] | undefined): string | undefined {
|
|
return Array.isArray(value) ? value[0] : value;
|
|
}
|