test+docs: tighten H1 assertions, cover secret/XFF edges, document boot & SSE-ban

Re-review follow-ups (non-blocking quality items):

Tests:
- moderation H1 specs now assert exact `→ 403` instead of bare .rejects.toThrow(),
  so a spurious 500 can no longer masquerade as "revocation worked".
- config: added case-insensitivity (upper/mixed-case placeholder) and the
  len==32/31 boundary cases for validate_secrets.
- rate_limiter: added the trailing-comma empty-entry case for client_ip (must
  fall back, not return "").
  (Backend unit tests: 35 pass.)

Docs:
- README: note that with APP_ENV=production a placeholder .env makes the app
  refuse to boot and Caddy wait unhealthy — reason is in `docker compose logs app`.
- SECURITY-BACKLOG + sse.rs comment: document that a mid-session ban does not
  tear down an already-open SSE stream (new tickets are blocked; low blast radius).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fabi
2026-07-02 07:14:33 +02:00
parent a084ba86c5
commit 41ac742af8
6 changed files with 48 additions and 5 deletions

View File

@@ -48,6 +48,10 @@ pub async fn stream(
.consume(&q.ticket)
.ok_or_else(|| AppError::Unauthorized("Ticket ungültig oder abgelaufen.".into()))?;
// NOTE: this authenticates via ticket→session, not the `AuthUser` extractor, so
// it does not re-check `is_banned`. A user banned mid-stream keeps receiving
// events until the connection drops; they cannot reconnect (issue_ticket uses
// AuthUser, which rejects banned users). Documented in docs/SECURITY-BACKLOG.md.
Session::find_by_token_hash(&state.pool, &token_hash)
.await
.map_err(|e| AppError::Internal(e.into()))?