You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
List view (/admin/keys): id, label, tier, allowed_models, debug_enabled, last_used (NULL until F3.A telemetry rows exist), created_at, revoked status. Paginate at 50/page.
Create form (/admin/keys/new):
Fields: label (required), tier (admin/client), allowed_models (multiselect from config aliases), rate_limit_override (number, blank = use default; cap enforced server-side per F2.B), debug_enabled (admin-only checkbox with confirmation modal — see below)
On submit: insert row, audit-log the action
Render plaintext key once in a flash banner with copy-to-clipboard button + "I have copied this" gate before allowing navigation away
Reload of the page never re-shows the plaintext
Debug toggle confirmation modal (per security S7): when debug_enabled is checked OR toggled on, show explicit text: "Prompts and responses for this key will be persisted in plaintext at ~/.local/share/copilot-api/traces/. Retention: days. Auto-disables in 24h unless renewed. Continue?". Require explicit re-confirmation.
TTL on debug: setting debug_enabled=true automatically schedules an auto-disable 24h later (in-process timer + a debug_expires_at column or check); operator can renew. Audit-log every toggle.
Revoke action: POST /admin/keys/:id/revoke → soft-delete via revoked_at = now. Audit-log.
Edit scope: PATCH /admin/keys/:id/scope. Tier is immutable post-create. Audit-log.
Active debug banner: when ANY key has debug_enabled=true, show a warning banner across all admin pages with the count and a "review" link (per security S7)
CSRF tokens on all mutating forms; defense-in-depth Origin check (handled by F1.D middleware)
Tests: paginated list with 1000 keys < 100 ms, plaintext key non-replayable after page leave, debug toggle requires confirmation, revocation propagates to next request
Acceptance criteria
Creating a key returns a one-time view; reload never shows it again
Revoked key fails next request with 401 (integration test)
Debug toggle without confirmation modal is impossible (test)
Part of #23. Depends on F1.D, F2.B, F2.C, F2.D.
Background
Operators need a UI to create / label / scope / revoke keys without writing SQL.
Goal
/admin/keyspage lets admin-tier users CRUD keys; client-tier users get 403.Tasks
/admin/keys): id, label, tier, allowed_models, debug_enabled, last_used (NULL until F3.A telemetry rows exist), created_at, revoked status. Paginate at 50/page./admin/keys/new):debug_enabledis checked OR toggled on, show explicit text: "Prompts and responses for this key will be persisted in plaintext at~/.local/share/copilot-api/traces/. Retention: days. Auto-disables in 24h unless renewed. Continue?". Require explicit re-confirmation.debug_enabled=trueautomatically schedules an auto-disable 24h later (in-process timer + adebug_expires_atcolumn or check); operator can renew. Audit-log every toggle./admin/keys/:id/revoke→ soft-delete viarevoked_at = now. Audit-log./admin/keys/:id/scope. Tier is immutable post-create. Audit-log.debug_enabled=true, show a warning banner across all admin pages with the count and a "review" link (per security S7)Acceptance criteria
File pointers
src/admin/keys/{list,new,detail}.tsx,src/admin/keys/route.ts,src/services/debug-ttl-sweeper.tssrc/admin/layout.tsx,src/lib/migrations/005_debug_expires.sqlDependencies
Depends on F1.D, F2.B, F2.C, F2.D.