docs(#197): record Phase-0 hardening decisions (security headers, constant-time compare, playout clamps)
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m35s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m41s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m34s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 6m1s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m28s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m35s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m41s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m34s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 6m1s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m28s
Follow-up to PR #279 — the adversarial diff review flagged that adding baseline security headers to every response is an operational-behavior decision worth a decisions.md entry. Records the SecurityHeadersMiddleware placement + the deliberate CSP/HSTS deferral to the #197 posture design, plus the constant-time key compare and playout paging clamps. Refs #197. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #290.
This commit is contained in:
@@ -914,3 +914,30 @@ whatever previously held its new slot. Contract + rules in **api-conventions §7
|
||||
- **TPT subtype change at a matched id** stays delete+insert (EF can't retype in place); state resets and a
|
||||
new id is returned, so the SPA must re-seed item state from the PUT response (a stale id on a second save
|
||||
now 422s).
|
||||
|
||||
## 2026-07-11 — Baseline security response headers + Phase-0 API hardening (#197, PR #279)
|
||||
|
||||
Phase-0 of the #197 remediation — the posture-**independent** safe subset, shipped ahead of the
|
||||
fail-closed/CORS/versioning posture work tracked in #280–#289.
|
||||
|
||||
- **Baseline security headers on every response.** New `ErsatzTV/Middleware/SecurityHeadersMiddleware`,
|
||||
registered **first** in the pipeline (before the `/iptv` `MapWhen` branch and `UseCors`), so it covers
|
||||
`/api`, `/iptv`, `/artwork`, static, the SPA fallback, and filter-produced 4xx alike — which is why it's
|
||||
middleware, not an MVC filter. It sets `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, and
|
||||
`Referrer-Policy: strict-origin-when-cross-origin`. `nosniff` is the standing backstop for the artwork
|
||||
content-type MIME-sniffing risk (#283). **CSP and HSTS are deliberately NOT included here**: CSP must be
|
||||
validated against the ChicoryTV SPA's inline assets, and HSTS is a proxy/TLS-termination decision — both
|
||||
belong to the #197 posture design (#284/roadmap), not this baseline. Headers are set eagerly (not via
|
||||
`Response.OnStarting`); safe today because the pipeline has no `UseExceptionHandler`/`UseStatusCodePages`
|
||||
that would `Response.Clear()` — switch to `OnStarting` if one is ever added.
|
||||
- **Constant-time API-key comparison.** `ApiKeyAuthorizationFilter` compares `X-Api-Key` with
|
||||
`CryptographicOperations.FixedTimeEquals` (over UTF-8 bytes) instead of ordinal `string.Equals`, removing
|
||||
the response-timing oracle on the write key. Accept/reject behavior is otherwise identical.
|
||||
- **Playout pagination clamped.** `GET /api/playouts` and `GET /api/playouts/{id}/items` now clamp
|
||||
`Math.Clamp(pageSize, 1, 100)` + `Math.Max(0, pageNum)` before the query — applying the api-conventions §1
|
||||
clamp convention the other paged endpoints already follow (these two were passing the raw client value
|
||||
straight to EF `Take()`).
|
||||
|
||||
The larger #197 posture (fail-closed writes, sensitive-read auth tier, CORS lockdown, `/api/v1` versioning,
|
||||
the OpenAPI security scheme) is decomposed into #280–#289 with the phased roadmap on #197; those PRs will
|
||||
append their own decisions here as they land.
|
||||
|
||||
Reference in New Issue
Block a user