Changeset 0.28.8 (#194)

This commit is contained in:
2026-03-15 23:43:36 +00:00
parent 3237d55e0c
commit 128cbb8174
25 changed files with 1157 additions and 863 deletions

View File

@@ -1,5 +1,104 @@
# Changelog
## [0.28.8] — 2026-03-15
### Summary
ICD Green Board. Close out all pre-existing ICD test failures before
v0.29.0 feature work. Gate: 543/543 (100%) on the ICD runner.
Three changesets: provider sync + infrastructure resilience (cs0),
CORS lockdown + WebSocket origin validation (cs1), WebSocket ticket
exchange (cs2).
### Fixed
- **Batched `UpsertFromSync`** — catalog sync rewritten as a single
transaction: one SELECT to identify existing models, N prepared
`INSERT ON CONFLICT DO UPDATE` statements, one COMMIT. Previously
each model was N×2 auto-committed queries (SELECT + INSERT/UPDATE),
producing ~300 round-trips and WAL flushes on a typical Venice sync.
Both PG and SQLite stores rewritten. Root cause of cascading 502s:
the write burst starved the connection pool and caused Traefik to
see stale keepalive connections on subsequent requests.
- **DB connection lifecycle** — `SetConnMaxLifetime(5m)` and
`SetConnMaxIdleTime(1m)` added to the Postgres pool. Previously
connections lived forever — stale TCP after PG restart or network
blip would fail silently until a query hit the dead connection.
- **HTTP transport pool** — `ProviderConfig.Client()` now returns a
shared `*http.Client` from a `sync.Map` keyed by `(ProxyMode,
ProxyURL)`. Previously every outbound provider call allocated a
fresh `http.Transport`, leaking idle connections until GC.
- **Traefik retry middleware** — new `Middleware` CRD (2 attempts,
100ms initial interval) applied via ingress annotation. Retries on
502 and connection reset. Both `k8s/` CI manifests and Helm chart
templates updated. CI pipeline renders and applies the middleware
before the ingress resource.
- **Provider sync timeout** — `syncProviderModels` now wraps the
outbound provider HTTP call with a configurable timeout (default 30s,
`PROVIDER_SYNC_TIMEOUT` env var). Previously used no timeout, causing
Gin handler timeouts and cascading 502s from the reverse proxy when
upstream providers (especially Venice) were slow.
- **504 on upstream timeout** — `POST /admin/models/fetch` and
`POST /api-configs/:id/models/fetch` now return 504 with structured
`{"error": "upstream timeout: <provider>"}` instead of letting the
reverse proxy manufacture a 502 from a broken connection.
- **ICD runner provider tier resilience** — `models/fetch` calls retry
once on 502/504 with 2-second backoff. Eliminates cascading test
failures caused by transient upstream timeouts.
- **WebSocket CheckOrigin** — `upgrader.CheckOrigin` now validates the
`Origin` header against `CORS_ALLOWED_ORIGINS` instead of
unconditionally returning `true`. Connections from unlisted origins
are rejected at upgrade time.
- **CORS startup warning** — if `CORS_ALLOWED_ORIGINS` is explicitly
set to `*`, a warning is logged at startup recommending restriction
for production deployments.
### New
- **WebSocket ticket exchange** — `POST /api/v1/ws/ticket` returns a
single-use opaque ticket (128-bit random hex, 30s TTL). Client
connects with `?ticket=<opaque>` instead of `?token=<jwt>`. Ticket
is validated and deleted atomically (single-use). Background reaper
removes expired unclaimed tickets every 15 seconds. This eliminates
JWT exposure in server logs, proxy logs, and browser history.
- **`WsAuth` middleware** — dedicated WebSocket auth middleware with
three-path priority: `?ticket=` (preferred), `?token=` (legacy,
logs deprecation warning), `Authorization` header (non-browser).
- **`TicketStore`** — in-memory ticket store with `Issue()`,
`Validate()`, `Stop()`, and automatic TTL reaping.
- **`GetAllowedOrigins()`** — exported CORS origin resolver for use
by WebSocket hub and other subsystems.
- **Traefik retry Middleware CRD** — `k8s/middleware-retry.yaml` and
`chart/templates/middleware-retry.yaml`. Configurable via
`ingress.retry.attempts` and `ingress.retry.initialInterval` in
Helm values.
### Changed
- **`events.NewHub(bus, allowedOrigins)`** — Hub constructor now takes
the resolved CORS origin string. The upgrader's `CheckOrigin` is
configured once at construction time.
- **`events.js` `_doConnect()`** — now async. Fetches a ticket via
`POST /api/v1/ws/ticket` before building the WebSocket URL. Falls
back to legacy `?token=` if ticket exchange fails (pre-v0.28.8
server compatibility).
- **WebSocket route** — `GET /ws` now uses `WsAuth` middleware instead
of generic `Auth`. Legacy `?token=` still works but logs deprecation.
- **`ProviderConfig.Client()`** — returns shared client from pool
instead of allocating per call.
### Docs
- **`docs/ICD/websocket.md`** — ticket exchange protocol documented
(preferred auth, legacy deprecation, origin validation).
- **`docs/ARCHITECTURE.md`** — expanded CORS configuration section
(environment behavior, production guidance, WebSocket interaction).
- **`docs/ROADMAP.md`** — v0.28.x Tier 2 bucket eliminated (items
relocated to pinned versions: v0.29.1, v0.30.0, v0.30.1). Pre-1.0
Code Quality Sweeps section deleted (relocated to v0.29.0 Phase 0
with CI-enforced gate). Zero unscheduled items remain outside TBD.
## [0.28.7] — 2026-03-15
### Summary