- GET /api/graphics-elements no longer side-effects; refresh moved to
POST /api/graphics-elements/refresh (204), closing a CSRF vector on a GET.
- PrepareTroubleshootingPlaybackHandler now returns a typed LockedError from
both atomic lock-acquire failures; ApiResults.ToErrorResult maps it to 409
instead of falling through to 422, so a lock lost in the race between the
controller's pre-check and the handler's atomic acquire still reports 409.
- AuthController.MachineKey sets Cache-Control: no-store + Pragma: no-cache
on the 200 response carrying the master API key.
- Reworded the stale "subtitleId query parameter" endpoint description now
that playback/start takes a JSON body.
- Regenerated openapi/v1.json + docs/endpoint-index.md; docs/api-conventions.md
updated with the LockedError pattern (§3a) and the ToErrorResult table row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix-commit re-review confirmed the 1st-round fixes resolved and caught a 2nd round:
- HIGH — env-seed vs. setup race: an attacker could claim admin in the startup
window before LocalAdminSeedService runs, and the seed's insert would then be
swallowed (attacker credential persists, defeating env recovery). Fixed
structurally: the setup-claim endpoint is CLOSED (409) whenever
Auth:LocalAdmin:Password is configured — the env seed owns the credential, so
there's no claim to race (also strengthens the setup-claim TOFU posture).
Config.setupRequired reflects it.
- LOW — a concurrent setup race-loser now returns 409 (not 422); ClaimLocalAdmin's
DbUpdateException catch re-checks existence and rethrows genuine/transient DB
errors instead of masking them as "already configured".
- MEDIUM (accepted, documented) — two simultaneous authenticated password changes
are a non-serializable lost-update; accepted for a single-admin system
(self-healing via re-login, implausible timing).
+3 AuthController tests (env-seed closes setup / setupRequired gating). Full
ErsatzTV.Tests green (1506); no generated drift. Docs updated.
Refs #295
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>