Changeset 0.28.8 (#194)
This commit is contained in:
99
CHANGELOG.md
99
CHANGELOG.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user