Commit Graph
21 Commits
Author SHA1 Message Date
whit3rabbitandClaude Opus 4.8 a108c35ff1 feat(admin-ui): default-open provider options, route curl snippet, live proxy status
Admin UI UX fixes plus the route-dispatch feature set:

- Providers: selecting a provider shows the full key/options form immediately
  instead of hiding it behind a "+ Add key" button; "Cancel" becomes "Reset".
- Routes: enabled routes show a ready-to-run curl snippet (endpoint URL from the
  new proxy_port on /admin/api/status, route name as the model) with a copy button.
- Settings: live proxy status badge (running/unreachable) backed by a proxy_running
  TCP liveness check on /admin/api/status, plus a per-save "applied live" toast.
- Backend: plumb proxy listen_port into SharedState; expose proxy_port + proxy_running.
- Also includes the RouteRouter dispatch layer, per-route option overrides, local-LLM
  backend support, favorites, and model discovery (see CHANGELOG [Unreleased]).

Ignore .gate/ security-scanner scratch artifacts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 07:48:13 -05:00
whit3rabbitandClaude Sonnet 4.6 20ac4022c1 feat(admin-ui): scaffold Vite + React + TypeScript frontend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 14:27:12 -05:00
whit3rabbitandClaude Sonnet 4.6 0593d1ae1b feat: add has_more to pagination responses, disable Next when no more results
Fetch limit+1 rows in get_requests and get_audit_log; if the extra row
exists set has_more=true and truncate back to limit. Admin UI disables
the Next button when has_more is false. Two new integration tests verify
the field is present and false on an empty DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:30:13 -05:00
whit3rabbitandClaude Sonnet 4.6 01e04fa6b3 feat: expose period_reset_at in list_keys and show in budget bar
Add period_reset_at_from_row() to keys.rs for DB rows (budget_duration
as string), wire it into list_keys response, render reset date below
the budget bar in admin UI. Also fix with_http_client missing max_retries
field after retry.rs signature change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:30:13 -05:00
whit3rabbit ab34b32816 fix: show empty-state message on all pages, not just page 0 2026-04-04 20:30:13 -05:00
whit3rabbit e0084d6630 fix: WebSocket reconnect uses exponential backoff, max 10 retries 2026-04-04 20:30:13 -05:00
whit3rabbitandClaude Sonnet 4.6 c27a7be80a fix: redirect to login on 401 in admin UI
Adds handleUnauthorized() to clear the session and show the login
overlay when any apiFetch or fetchCsrfToken call returns 401.
Also adds auth headers to the CSRF token request so the server can
validate the session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:30:13 -05:00
whit3rabbitandClaude Sonnet 4.6 5f1bc056b0 fix: re-fetch CSRF token before each admin mutation
The server issues one-time-use CSRF tokens (invalidated after first use).
The UI was fetching a single token on page load and reusing it, causing
all mutations after the first to fail with 403. Replace the six mutation
call sites with a new mutatingFetch() helper that fetches a fresh token
before each request, and remove the upfront fetchCsrfToken() at startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 20:30:13 -05:00
whit3rabbitandClaude Opus 4.6 0fe011d718 fix(security): harden 4 medium findings from security audit
1. CSRF token store: replace unbounded DashMap with moka::sync::Cache
   (max 1,000 entries, 24h TTL) to prevent memory exhaustion.
2. Cloud metadata SSRF: warn at startup if QDRANT_URL/REDIS_URL points
   at 169.254.169.254 or metadata.google.internal.
3. TLS P12 password: wrap in zeroize::Zeroizing<String> so it is zeroed
   from heap on drop, preventing extraction from core dumps.
4. CSP nonce: replace unsafe-inline with per-request 128-bit nonce on
   admin SPA script/style tags.

Also includes: batch/bedrock model allowlist enforcement, litellm
master_key extraction moved to single-threaded fn main().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 20:31:11 -05:00
whit3rabbitandClaude Opus 4.6 9e1e769c4b fix: harden builtin tools and remove redundant error classification
BashTool: add 30s subprocess timeout and 256KB output truncation.
ReadFileTool: require absolute paths, canonicalize to block traversal,
enforce 1MB size limit. ToolRegistry::get returns &dyn Tool instead of
&Box<dyn Tool>. Remove wasted infer_error_kind call from log_entry()
since every error path overwrites via set_backend_error_kind(). Cancel
pending observability refresh timer in loadDashboard to prevent
duplicate concurrent fetches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:38:54 -05:00
whit3rabbitandClaude Opus 4.6 b6277a8b86 feat: operator observability dashboard with error classification
- Admin UI: operator view with request volume, token usage, latency,
  cost charts, failure table, and request timeline
- Backend: add error_kind() method and infer_error_kind() for stable
  error classification (rate_limit, timeout, backend_error, client_error)
- Admin DB: error_kind column in request_log, observability aggregate
  queries (bucketed timeseries, failure breakdown, timeline)
- Gemini: improved streaming translation, thinking block support,
  grounding metadata passthrough
- Request timeout: configurable REQUEST_TIMEOUT_SECS with streaming
  watchdog
- Model pricing: MODEL_PRICING_FILE for external pricing overrides
- Degradation header: ANYLLM_DEGRADATION_WARNINGS env var control

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 19:12:03 -05:00
whit3rabbitandClaude Opus 4.6 5c73adfaea feat(admin): team-focused UI overhaul with key editing and audit log
Backend:
- PUT /admin/api/keys/{id}: update virtual key fields (role immutable),
  refreshes DashMap, emits key_updated audit entry
- update_virtual_key(): resets spend period when budget_duration changes
- query_audit_log(): action, target_type, since, until filter params
- query_request_log(): add until filter param; wire through RequestsQuery
- GET /admin/api/metrics: include streaming counters (started/completed/failed/disconnected)
- GET /admin/api/env: include RATE_LIMIT_FAIL_POLICY

UI:
- Dashboard: streaming metrics stat row
- Request Log: key filter dropdown, since/until date pickers, Key column
- Access Control tab: allowed_models tag input, edit modal, budget progress
  bars, key prefix link navigates to filtered request log
- Settings: override badges from overridden_keys, Security section
  (IP allowlist, rate limit fail policy)
- Audit tab: action/target/date filters, paginated table

Tests:
- 7 unit tests for update_virtual_key and query_audit_log filters
- 4 integration tests for PUT /admin/api/keys/{id} lifecycle

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 18:08:34 -05:00
whit3rabbit 78def09d43 feat(admin-ui): send CSRF token in all state-mutating requests
- fetchCsrfToken(): fetches from GET /admin/csrf-token on load, stores in _csrfToken
- mutatingHeaders(): returns authHeaders merged with X-CSRF-Token header
- All POST/PUT/DELETE fetch calls now use mutatingHeaders() instead of authHeaders
- fetchCsrfToken() called before loadDashboard() so token is ready at startup
2026-03-27 23:49:51 -05:00
whit3rabbitandClaude Sonnet 4.6 845cc567d5 fix: use nextElementSibling for detail toggle, fix models double-render
- nextSibling could return text nodes causing duplicate detail panels
- loadModels showed data.note twice when no router active

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:30:45 -05:00
whit3rabbitandClaude Sonnet 4.6 12217186ec feat: robust metrics rendering and add missing env groups to admin UI and backend
- loadDashboard: apply error_rate coloring (red >5%, green otherwise) matching the
  WebSocket handler; derive requests_per_second into RPM stat on initial load
- Backend cards now show error count alongside request count
- ENV_GROUPS: add Azure OpenAI, AWS Bedrock, Network groups; add PROXY_OPEN_RELAY to
  Auth & TLS; add AZURE_OPENAI_API_KEY, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN to
  ENV_SECRET_KEYS
- get_env endpoint: expose all Azure OpenAI, AWS Bedrock, PROXY_OPEN_RELAY, and Network
  (IP_ALLOWLIST, TRUST_PROXY_HEADERS, WEBHOOK_URLS) env vars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:25:09 -05:00
whit3rabbitandClaude Sonnet 4.6 85423b115d feat: split token columns and add feed pause/filter controls
Split the single Tokens column into In/Out columns (7-column grid).
Add pause button and status filter (2xx/4xx/5xx) to the live feed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:22:35 -05:00
whit3rabbitandClaude Sonnet 4.6 e561ae7fd8 feat(admin-ui): replace localStorage+prompt with sessionStorage+login form
Stops the admin token from persisting across browser sessions (XSS
exfiltration window reduced) and replaces the phishable window.prompt
with a proper password-masked login form. Token is validated against
GET /admin/api/metrics before being stored; invalid tokens show an
inline error message. URL query param token cleanup removed since that
path no longer exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 15:11:17 -05:00
whit3rabbitandClaude Opus 4.6 c84c2c0a68 chore: cargo fmt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 06:51:18 -05:00
whit3rabbitandClaude Opus 4.6 abb5b90e1d feat: add Bedrock backend, OpenTelemetry export, integration tests
- AWS Bedrock backend: SigV4 signing, InvokeModel + InvokeModelWithResponseStream
  with binary event stream decoding, passthrough handler for /v1/messages
- OpenTelemetry export: feature-gated (--features otel), OTLP/HTTP with
  reqwest transport, OtelGuard for graceful shutdown flush
- Chat completions integration tests: 6 tests covering non-streaming,
  error handling, degradation headers, system messages
- Updated COMPARISON_LITELLM.md to reflect all closed gaps
- Fixed Bedrock match arms across all handler files

549 tests passing, 0 failures, clippy clean.
Both `cargo build` and `cargo build --features otel` compile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 20:21:24 -05:00
whit3rabbitandClaude Opus 4.6 9b00345746 fix: harden proxy with security, correctness, and reliability improvements
Security: strip admin token from browser URL, add cross-origin rejection
middleware for admin API, skip tool calls with empty names instead of
substituting "unknown".

Correctness: use BytesMut for SSE buffering to prevent UTF-8 corruption
at TCP chunk boundaries, use saturating_sub for epoch arithmetic, handle
CRLF SSE frame delimiters.

Runtime: switch runtime_config to std::sync::RwLock (guard is !Send),
use block_in_place for SQLite IO, spawn_blocking for tokenization,
add tracing reload layer so admin log_level changes apply immediately.

Reliability: retry failed log buffer flushes with capped retry queue,
add MAX_SSE_BUFFER_SIZE guard in middleware handler, cap tool call and
part indices to prevent unbounded vec growth.

Observability: defer streaming request logging until stream completes
so entries capture actual status, latency, and token counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 21:22:42 -05:00
whit3rabbitandClaude Opus 4.6 6148b44e46 feat: add admin dashboard with request logging and observability
Localhost-only admin server (default port 3001) with:
- Web UI dashboard with live request feed via WebSocket
- SQLite-backed request log with pagination and filtering
- Hot-reload config (model mappings, log level, log bodies) persisted
  to SQLite across restarts
- Per-backend metrics with error rate tracking
- Token-based auth (random UUID printed to stderr, or set ADMIN_TOKEN)
- Automatic log retention purge (ADMIN_LOG_RETENTION_DAYS, default 7)

Supporting changes:
- Backend error types gain status_code() for request log entries
- Metrics gains Clone, Default, error_rate() for admin aggregation
- Routes track per-request context (RequestCtx) and log to admin
- Error responses sanitized: internal details logged server-side only,
  clients receive generic messages (prevents infrastructure leaks)
- SSE buffer guard (10 MB max) prevents unbounded memory from
  misbehaving backends
- New deps: rusqlite (bundled), toml, indexmap, bytes, axum ws feature

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:34:48 -05:00