Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ bun run gate:security

| Piece | Requirement and current reality | Status | Evidence |
| --- | --- | --- | --- |
| L1 Proxy | Four metrics ≥95%, plus baseline line floor ≥97.5%, ≤0.1pp regression and no untested files | planned | `gate:coverage` enforces stronger line baseline in hooks/CI; Vitest branch threshold still 89% |
| L1 Dashboard/scripts | Four metrics ≥95% | planned | Dashboard config only statements 90%; script config branches 89% |
| L1 Proxy | Four metrics ≥95%, plus baseline line floor ≥97.5%, ≤0.1pp regression and no untested files | enforced | `gate:coverage` retains the stronger line/directory baseline, regression and untested-file rules; Vitest enforces all four 95% thresholds |
| L1 Dashboard | Four metrics ≥95% | enforced | Dashboard tests and CI enforce all four 95% thresholds on the declared scope |
| L1 scripts | Four metrics ≥95% | enforced | The baseline gate explicitly runs the dedicated Bun/Istanbul config for the declared `scripts/lib` scope; reports are isolated in `coverage/scripts` |
| L2 | Every API endpoint/method through real isolated HTTP/SQLite | planned | CI `test:l2` is in-process route/handler tests with mocked upstream; legacy live E2E uses real state |
| L3 | Real isolated dashboard/auth/provider workflows | planned | Playwright manual runner uses real auth and fixed test DB |
| G1 | Strict types, zero-warning/error Biome and architecture boundaries | planned | Checks enforced; pre-commit lint-staged mutation/worktree concurrency violates check-only target |
Expand Down
11 changes: 7 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"devDependencies": {
"@biomejs/biome": "2.5.14",
"@types/bun": "1.4.2",
"@vitest/coverage-istanbul": "5.0.1",
"dependency-cruiser": "18.3.1",
"husky": "^9.1.7",
"lint-staged": "17.5.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"dependencies": {
"@nocoo/basalt": "2.1.8",
"clsx": "^2.1.1",
"lucide-react": "1.46.0",
"lucide-react": "1.47.0",
"next": "16.3.5",
"next-auth": "^5.0.0-beta.32",
"react": "19.3.0",
Expand All @@ -30,7 +30,7 @@
"@testing-library/jest-dom": "7.0.1",
"@testing-library/react": "^16.3.3",
"@testing-library/user-event": "14.6.7",
"@types/node": "26.5.1",
"@types/node": "26.6.2",
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0",
"@typescript/native-preview": "7.0.0-dev.20260707.2",
Expand Down
64 changes: 64 additions & 0 deletions packages/dashboard/test/api/proxy-error-contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { beforeEach, describe, expect, it, vi } from "vitest";

const proxyFetch = vi.fn();
vi.mock("@/lib/proxy", () => {
class ProxyError extends Error {
constructor(message: string, public readonly statusCode?: number) { super(message); }
}
return { proxyFetch, ProxyError };
});

const { ProxyError } = await import("@/lib/proxy");
const upstreams = await import("@/app/api/upstreams/route");
const upstream = await import("@/app/api/upstreams/[id]/route");
const upstreamModels = await import("@/app/api/upstreams/[id]/models/route");
const keys = await import("@/app/api/keys/route");
const key = await import("@/app/api/keys/[id]/route");
const revoke = await import("@/app/api/keys/[id]/revoke/route");
const settings = await import("@/app/api/settings/route");
const setting = await import("@/app/api/settings/[key]/route");
const requests = await import("@/app/api/requests/route");
const stats = await import("@/app/api/stats/[...path]/route");
const copilot = await import("@/app/api/copilot/[...path]/route");
const connection = await import("@/app/api/connection-info/route");

const request = () => new Request("http://dashboard.test/api/fixture", { method: "POST", body: "{}" });
const context = () => ({ params: Promise.resolve({ id: "fixture-id" }) });
const routes: [string, () => Promise<Response>][] = [
["list providers", () => upstreams.GET()],
["create provider", () => upstreams.POST(request())],
["read provider", () => upstream.GET(request(), context())],
["update provider", () => upstream.PUT(request(), context())],
["delete provider", () => upstream.DELETE(request(), context())],
["provider models", () => upstreamModels.GET(request(), context())],
["list keys", () => keys.GET()],
["create key", () => keys.POST(request())],
["delete key", () => key.DELETE(request(), context())],
["revoke key", () => revoke.POST(request(), context())],
["read settings", () => settings.GET()],
["write settings", () => settings.PUT(request())],
["delete setting", () => setting.DELETE(request(), { params: Promise.resolve({ key: "fixture" }) })],
["requests", () => requests.GET(request())],
["statistics", () => stats.GET(request(), { params: Promise.resolve({ path: ["summary"] }) })],
["copilot metadata", () => copilot.GET(request(), { params: Promise.resolve({ path: ["user"] }) })],
["connection metadata", () => connection.GET()],
];

beforeEach(() => proxyFetch.mockReset());

describe.each(routes)("Dashboard proxy failure contract: %s", (_label, invoke) => {
it.each([
[new ProxyError("fixture failure"), 502, "fixture failure"],
[new ProxyError("fixture failure", 429), 429, "fixture failure"],
[new Error("fixture failure"), 502, "fixture failure"],
["untrusted non-Error rejection", 502, "Failed to reach proxy"],
])("normalizes rejection %# without returning success or raw unknown data", async (error, status, message) => {
proxyFetch.mockRejectedValueOnce(error);
const response = await invoke();
expect(response.status).toBe(status);
const body = await response.json();
expect(JSON.stringify(body)).toContain(message);
expect(JSON.stringify(body)).not.toContain("untrusted non-Error rejection");
expect(proxyFetch).toHaveBeenCalledOnce();
});
});
25 changes: 25 additions & 0 deletions packages/dashboard/test/components/chart-primitives.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// @vitest-environment jsdom
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { ChartTooltip, ChartTooltipRow, ChartTooltipSummary } from "@/components/dashboard/chart-primitives";
import { CodeBlock } from "@/components/code-block";

describe("dashboard display atoms", () => {
it.each([undefined, null, "", "Requests"])("keeps tooltip content with optional title %j", (title) => {
const { container } = render(<ChartTooltip title={title}>
<ChartTooltipRow color="rgb(12, 34, 56)" label="Success" value={3} />
<ChartTooltipRow label="Failure" value={0} />
<ChartTooltipSummary label="Total" value={3} />
</ChartTooltip>);
expect(screen.getByText("Success")).toBeDefined();
expect(screen.getByText("Failure")).toBeDefined();
expect(screen.getByText("Total")).toBeDefined();
expect(container.querySelector('[aria-hidden="true"]')).toHaveStyle({ background: "rgb(12, 34, 56)" });
expect(container.querySelectorAll("p")).toHaveLength(title ? 1 : 0);
});

it.each([undefined, "custom-code"])("preserves literal code with optional class %j", (className) => {
render(<CodeBlock code="echo fixture" {...(className === undefined ? {} : { className })} />);
expect(screen.getByText("echo fixture").tagName).toBe("CODE");
});
});
58 changes: 58 additions & 0 deletions packages/dashboard/test/components/filter-bar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,64 @@ describe("FilterChip", () => {
// ---------------------------------------------------------------------------

describe("FilterBar", () => {
it("shows every deep-linked dimension, including zero latency and synchronous mode", () => {
mockSearchParams = new URLSearchParams({
model: "m", resolved_model: "resolved", strategy: "native", upstream: "fixture-provider",
account: "fixture-account", client: "fixture-client", client_version: "1.2.3",
session: "fixture-session", path: "/v1/messages", status: "error", status_code: "429",
stream: "false", has_error: "true", min_latency: "0", max_latency: "1000",
stop_reason: "length", routing_path: "fallback",
});
render(<FilterBar upstreams={["fixture-provider"]} />);
expect(screen.getByText("17 active")).toBeDefined();
expect(screen.getAllByRole("button", { name: /^Remove .* filter$/ })).toHaveLength(17);
expect(screen.getByText("0ms")).toBeDefined();
expect(screen.getByText("Version:")).toBeDefined();
});

it.each([
[1, "fixture-model", "model"], [2, "fixture-strategy", "strategy"],
[3, "fixture-provider", "upstream"], [4, "error", "status"],
])("updates dimension %s through the actual dropdown", async (index, value, key) => {
render(<FilterBar models={["fixture-model"]} strategies={["fixture-strategy"]} upstreams={["fixture-provider"]} />);
const user = userEvent.setup();
await user.click(screen.getAllByRole("combobox")[index]!);
await user.click(screen.getByRole("option", { name: value }));
const params = new URLSearchParams(String(mockPush.mock.calls[0]![0]).split("?")[1]);
expect(params.get(key)).toBe(value);
});

it("clears the last upstream selection without retaining an empty query string", async () => {
mockSearchParams = new URLSearchParams("upstream=fixture-provider");
render(<FilterBar upstreams={["fixture-provider"]} />);
const user = userEvent.setup();
await user.click(screen.getAllByRole("combobox")[1]!);
await user.click(screen.getByRole("option", { name: "All upstreams" }));
expect(mockPush).toHaveBeenCalledWith("/");
});

it.each([
["stream=false", "Streaming", "/?stream=true"],
["stream=true", "Synchronous", "/?stream=false"],
["stream=true", "All modes", "/"],
])("changes request mode from %s to %s", async (query, label, expected) => {
mockSearchParams = new URLSearchParams(query);
render(<FilterBar />);
const user = userEvent.setup();
await user.click(screen.getAllByRole("combobox")[2]!);
await user.click(screen.getByRole("option", { name: label }));
expect(mockPush).toHaveBeenCalledWith(expected);
});

it("clears old custom bounds when selecting the default time range", async () => {
mockSearchParams = new URLSearchParams("range=custom&from=1000&to=2000");
render(<FilterBar />);
const user = userEvent.setup();
await user.click(screen.getAllByRole("combobox")[0]!);
await user.click(screen.getByRole("option", { name: "Last 24 hours" }));
expect(mockPush).toHaveBeenCalledWith("/");
});

it("renders time range picker with default 24h", () => {
render(<FilterBar />);
expect(screen.getByText("Last 24 hours")).toBeDefined();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { fireEvent, render, screen } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -103,6 +103,49 @@ function makeExtendedRecord(overrides: Partial<ExtendedRequestRecord> = {}): Ext
// ===========================================================================

describe("RequestDetailDrawer", () => {
it("renders sparse non-streaming requests without fabricated token or routing details", () => {
const request = makeExtendedRecord({
latency_ms: 0, ttft_ms: 0, processing_ms: 0, stream: 0,
input_tokens: null, output_tokens: null, cache_read_tokens: null, cache_write_tokens: null,
translated_model: "", strategy: "", upstream: "", upstream_format: "", routing_path: "",
copilot_model: "", account_name: "", client_name: "", stop_reason: "", tool_call_count: 0,
});
render(<RequestDetailDrawer request={request} open onOpenChange={() => {}} />);
expect(screen.getByText("No")).toBeDefined();
expect(screen.getAllByText("—")).toHaveLength(5);
expect(screen.queryByText("Strategy")).toBeNull();
expect(screen.queryByText("Tool Calls")).toBeNull();
expect(screen.getAllByText("0ms").length).toBeGreaterThan(0);
});

it.each([null, {}])("leaves the drawer usable when clipboard support is %j", (clipboard) => {
const previous = Object.getOwnPropertyDescriptor(navigator, "clipboard");
Object.defineProperty(navigator, "clipboard", { configurable: true, value: clipboard });
try {
render(<RequestDetailDrawer request={makeExtendedRecord()} open onOpenChange={() => {}} />);
fireEvent.click(screen.getByLabelText("Copy request ID"));
expect(screen.getByText("req-test-001")).toBeDefined();
} finally {
if (previous) Object.defineProperty(navigator, "clipboard", previous);
else Reflect.deleteProperty(navigator, "clipboard");
}
});

it("handles denied clipboard writes without an unhandled rejection", async () => {
const previous = Object.getOwnPropertyDescriptor(navigator, "clipboard");
const writeText = vi.fn().mockRejectedValue(new Error("Permission denied"));
Object.defineProperty(navigator, "clipboard", { configurable: true, value: { writeText } });
try {
render(<RequestDetailDrawer request={makeExtendedRecord()} open onOpenChange={() => {}} />);
fireEvent.click(screen.getByLabelText("Copy request ID"));
await Promise.resolve();
expect(writeText).toHaveBeenCalledWith("req-test-001");
} finally {
if (previous) Object.defineProperty(navigator, "clipboard", previous);
else Reflect.deleteProperty(navigator, "clipboard");
}
});

it("renders nothing when request is null", () => {
const { container } = render(
<RequestDetailDrawer request={null} open={false} onOpenChange={() => {}} />,
Expand Down
Loading
Loading