/** * The request id, from the header a front door sends to the row support reads. * * The fact being defended: a customer quotes `x-request-id` and an operator must * land on THAT turn. Before the ledger recorded it, the only join available was * "the same member at the same instant", which answers "probably this one" and * answers nothing at all when two of a member's turns overlap. Everything below * is about that answer being exact, and about the id being safe to accept from * outside: it arrives from the public internet through somebody else's proxy. * * SQLite runs always; Postgres runs when AMR_ROUTER_TEST_PG points at one, * following this repo's convention for store tests — and there specifically * because the ledger is partitioned by day there, so the id has to survive * partition routing. */ import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { DEFAULT_CONFIG } from "../src/config/defaults.ts"; import { completeUpstreamEntry } from "../src/config/upstreams.ts"; import type { RouterConfig } from "../src/config/types.ts"; import { createSqlLedger } from "../src/cost/ledger-sql.ts"; import { EMPTY_USAGE, type AsyncLedger, type LedgerEntry } from "../src/cost/types.ts"; import { decisionEntries } from "../src/cost/views.ts"; import { startServer, type StartedServer } from "../src/server/http.ts"; import { acceptRequestId, isMintedRequestId, isRequestId, mintRequestId, requestIdFor, MINTED_REQUEST_ID_PREFIX, REQUEST_ID_MAX_LENGTH, } from "../src/util/requestid.ts"; import { ledgerDayStart, ledgerLayout, ledgerPartitionName, migrateStore } from "../src/util/schema.ts"; import { openSqlDb, type SqlDb } from "../src/util/sql.ts"; import { openDb } from "../src/util/sqlite.ts"; import { parseMessagesRequest } from "../src/wire/anthropic/messages.ts"; import { parseChatRequest } from "../src/wire/openai/request.ts"; import { parseResponsesRequest } from "../src/wire/openai/responses.ts"; const DAY = 86_400_000; const PG = process.env.AMR_ROUTER_TEST_PG; const NUL = String.fromCharCode(0); const engines: { name: string; url: string; partitions: boolean }[] = [ { name: "sqlite", url: `sqlite://${join(tmpdir(), `ledger-reqid-${process.pid}-${Date.now()}.db`)}`, partitions: false }, ...(PG === undefined ? [] : [{ name: "postgres", url: PG, partitions: true }]), ]; function entry(over: Partial & { id: string }): LedgerEntry { return { createdAtMs: Date.now(), conversationKey: `conv-${over.id}`, sessionId: `sess-${over.id}`, turn: 1, requestedModel: "auto", harnessId: "u_ada", ompSessionId: `omp-${over.id}`, slug: "x/model", servedSlug: "x/model", tier: "simple", classificationSource: "heuristic", reasons: ["cheapest"], predictedUsd: 0.001, reportedUsd: 0.002, usage: { ...EMPTY_USAGE, promptTokens: 100, completionTokens: 10 }, attempt: 0, escalationSignal: null, latencyMs: 10, ttftMs: 5, finishReason: "stop", wasted: false, upstreamGenerationId: null, error: null, features: null, score: null, confidence: null, task: null, classifierReasons: null, exploredFrom: null, holdArm: null, promptTokensSaved: 0, ...over, } as unknown as LedgerEntry; } describe("what the router will carry as a request id", () => { test("the ordinary shapes in circulation are accepted verbatim", () => { for (const id of [ "abc123", crypto.randomUUID(), "01JBQ9F6WQ2M8P7VJ5X3K4T0YZ", // a ULID "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01", // a traceparent "req_01HZ.9-x", "c".repeat(REQUEST_ID_MAX_LENGTH), ]) { expect(acceptRequestId(id)).toBe(id); } // Surrounding whitespace is a proxy's formatting, not part of the id. expect(acceptRequestId(" abc123 ")).toBe("abc123"); }); test("a hostile value is refused whole rather than repaired", () => { const hostile: string[] = [ "", // absent " ", "x".repeat(REQUEST_ID_MAX_LENGTH + 1), // unbounded `abc${NUL}def`, // a control character "abc\ndef", // a newline: one log line must stay one log line "abc\r\nX-Injected: 1", "abc\tdef", "id with spaces", '">', "a'; DROP TABLE ledger;--", "../../etc/passwd", "héllo", // outside the ASCII set the rules allow ]; for (const value of hostile) { expect(acceptRequestId(value), value).toBe(""); // Nothing is salvaged from it: a truncated or stripped id would look // valid and match no row, which is worse than having none. expect(requestIdFor(value).startsWith(MINTED_REQUEST_ID_PREFIX), value).toBe(true); } expect(acceptRequestId(null)).toBe(""); expect(acceptRequestId(undefined)).toBe(""); }); test("a caller cannot pass off an id as one this router minted", () => { const forged = `${MINTED_REQUEST_ID_PREFIX}deadbeef`; expect(isRequestId(forged)).toBe(true); // well-shaped... expect(acceptRequestId(forged)).toBe(""); // ...and still refused from outside // The turn is recorded under a minted id of the router's own instead. const minted = requestIdFor(forged); expect(minted).not.toBe(forged); expect(isMintedRequestId(minted)).toBe(true); }); test("a minted id is distinguishable, unique, and short enough for anyone's log", () => { const a = mintRequestId(); const b = mintRequestId(); expect(a).not.toBe(b); expect(isMintedRequestId(a)).toBe(true); expect(isMintedRequestId("abc123")).toBe(false); expect(a.length).toBeLessThanOrEqual(REQUEST_ID_MAX_LENGTH); // It also passes the team edition's own id rule (letters, digits, dots, // dashes, 8-64 characters), so a minted id pastes into support unchanged. expect(/^[A-Za-z0-9._-]{8,64}$/.test(a)).toBe(true); }); }); describe("every turn wire reads the header", () => { const body = { model: "auto", messages: [{ role: "user", content: "hi" }] }; test("the chat, responses and messages wires all carry the caller's id", () => { const h = () => new Headers({ "x-request-id": "abc123" }); expect(parseChatRequest(body, h()).requestId).toBe("abc123"); expect(parseResponsesRequest({ model: "auto", input: "hi" }, h()).requestId).toBe("abc123"); expect(parseMessagesRequest({ model: "claude-sonnet-4-5", max_tokens: 16, messages: [{ role: "user", content: "hi" }] }, h()).requestId).toBe("abc123"); }); test("an older front door that sends no header behaves exactly as before, plus a minted id", () => { const before = parseChatRequest(body, new Headers({ "x-omp-harness": "codex" })); // Nothing else about the request changed: the id is additive. expect(before.harnessId).toBe("codex"); expect(before.requestedModel).toBe("auto"); expect(isMintedRequestId(before.requestId ?? "")).toBe(true); // And two turns are never filed under the same minted id. expect(parseChatRequest(body, new Headers()).requestId).not.toBe(before.requestId); }); test("a header the rules refuse never reaches the request", () => { for (const hostile of ["x".repeat(REQUEST_ID_MAX_LENGTH + 1), "id with spaces", `${MINTED_REQUEST_ID_PREFIX}forged`, '">