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>
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>
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>
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>
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>
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>
- 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
- 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>
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>
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>
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>