feat(audit): expose GET /api/v1/audit + dashboard page (closes #246)#248
Merged
Conversation
Adds an admin-only audit query endpoint that returns events recorded for the caller's tenant. The tenant is derived from AuthContext so operators cannot inspect events from another tenant. Query supports event_type, time range, limit (default 100, capped at 1000), and offset. Registered in the router and OpenAPI spec.
Adds an Audit nav entry (between Security and Costs) that surfaces the tenant's audit log: timestamp, event type, actor, resource, and a collapsible JSON payload. Includes a free-text event-type filter, prev/next pagination at the default 100 page size, and loading / empty / error states. Mirrors the locked Rust response shape (flat JSON array of AuditEvent) — see crates/llmtrace-proxy/src/audit_api.rs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #246.
Summary
The proxy already records audit events (tenant CRUD, API-key mint/revoke, config changes, etc.) but neither exposed them via HTTP nor surfaced them in the dashboard. This PR adds both halves.
Per-file changes
Rust (proxy)
crates/llmtrace-proxy/src/audit_api.rs(new) —GET /api/v1/audithandler. Admin-only viaApiKeyRole::Admin. Tenant is derived fromAuthContextonly — there is notenant_idURL/query parameter, so operators cannot inspect another tenant's events. Acceptsevent_type,start_time,end_time(RFC3339),limit(default 100, clamped to 1000 with a warn log),offset. Returns a flat JSON array ofAuditEvent.#[utoipa::path(...)]annotated.crates/llmtrace-proxy/src/lib.rs— registeraudit_apimodule.crates/llmtrace-proxy/src/main.rs— register/api/v1/auditroute.crates/llmtrace-proxy/src/openapi.rs— include handler in the OpenAPI document so Swagger picks it up.clamp_limit(default / explicit / over-max / zero), 200 happy path with full response-shape assertions, 401 unauthenticated, 403 operator-role rejection,event_typefilter, explicitlimithonoured, and tenant A vs tenant B isolation.Dashboard
dashboard/src/lib/types.ts(new) —AuditEventinterface mirroring the Rust shape.dashboard/src/lib/api.ts— re-exportsAuditEventand addslistAuditEvents()(returns a flatAuditEvent[], matching the locked Rust shape).dashboard/src/app/audit/page.tsx(new) — table with columns Timestamp / Event type / Actor / Resource / Data (collapsible JSON). Free-text event-type filter, prev/next pagination at 100/page, plus loading / empty / error states.dashboard/src/components/sidebar.tsx— addsAuditentry between Security and Costs with theScrollTextlucide icon. Grouping rationale: Audit is observability-adjacent like Security, so it sits next to it.Validation evidence
cargo fmt --all— clean.cargo build -p llmtrace— succeeded.cargo test -p llmtrace --tests—607 passed; 0 failed(unit) +21 passed(main) +19 passed(integration). The 10 newaudit_api::tests::*all pass.cd dashboard && npm run lint— only pre-existing warnings on unrelated files (compliance/page.tsx,guide/page.tsx,traces/page.tsx). No new warnings or errors from this PR.cd dashboard && npm run build— succeeded;/auditroute emitted (4.67 kB / 117 kB First Load JS).Not validated
/auditpage was performed from this worktree (no live proxy running). The page is exercised only by the Next.js build typecheck.Out of scope (per the issue)