Repository navigation
proxy-v2.0.0 — hardened, auth-required gateway
Production-hardening release. Turns the demo-grade cm-llm-proxy into a hardened gateway that
holds the Anthropic key server-side and authenticates every caller by their Qlik session
(specs P01–P07). Breaking: the proxy now requires Qlik-session auth and env-based
credentials — a client can no longer just reach it and spend the key.
⚠️ Breaking
- Caller authentication is now mandatory. Every
/api/*request must present a valid Qlik
session; unauthenticated requests are rejected401before any upstream call. Requires
QLIK_SESSION_URL,QLIK_CERT,QLIK_KEY(and CORSQLIK_ORIGINS) — the proxy fails fast at
boot without them. - The Anthropic key must be server-side (
ANTHROPIC_API_KEYenv); any client-supplied key
header is stripped. There is no pass-through of a browser key anymore.
Added
- Credential custody (P01): key from env, injected per request, client key headers stripped;
bounded retry/backoff on transient upstream 429/5xx. - Caller authentication (P02): validates the Qlik session against QPS over mutual-TLS and
resolves the real user id. Session carrier is the same-siteX-Qlik-Sessioncookie (a named
virtual proxy usesX-Qlik-Session-<prefix>viaQLIK_SESSION_COOKIE); thex-qlik-session
header is an explicit ticket override. Positive-only TTL cache. - Concurrency & resilience (P03): global + per-user in-flight ceilings, bounded FIFO queue
(503+Retry-Afteron overflow/timeout), streaming backpressure, keep-alive upstream pools,
graceful drain on shutdown. - Input validation & model allowlist (P04): per-route body-schema validation, request-size
caps, server-side model allowlist. - Transport & CORS hardening (P05): strict origin allowlist, security headers, TLS floor,
per-IP rate limiting. - Observability & service (P06): structured JSON logs with level gating (
LOG_LEVEL), a
separate audit log (no bodies/secrets),/health·/ready·/metrics, boot-time config
validation, and a Windows-service wrapper (auto-start/restart, log rotation).setup.ps1
automates install. - Streaming on both routes (
stream: true), piped through untouched astext/event-stream. - Client-cancel propagation: when the client disconnects (closed tab / the extension's Stop
button), the upstream call is cancelled so the model stops generating — streaming destroys the
piped stream, and the buffered path aborts the in-flight upstream call via anAbortSignal
wired to the responseclose. - Tests & CI (P07): 102
node:testcases (integration over the real/apisurface, load,
drain), ESLint, GitHub Actions.
Fixed
- QPS xrfkey (P02). Verified end-to-end against a live QSEoW node: QPS rejects any API call
without an XSRF key (403 "XSRF prevention check failed"), which was mapped toAuthErrorand
would have rejected every session, valid or not. The session-validation call now sends a
16-char xrfkey in both the query string and theX-Qlik-Xrfkeyheader. Note:QLIK_SESSION_URL's
host must match a SAN of the QPS certificate (QSEoW uses the short hostname, not the FQDN).