diff --git a/internal/api/authpublic_csrf_guard_test.go b/internal/api/authpublic_csrf_guard_test.go index ede53dc0f..2b6ab47c3 100644 --- a/internal/api/authpublic_csrf_guard_test.go +++ b/internal/api/authpublic_csrf_guard_test.go @@ -67,26 +67,27 @@ const ( // row, keyed by csrfRouteKey. Each entry says why. Add a route here only if it // never acts on the caller's session credential. var authPublicCSRFExempt = map[string]string{ - "GET /api/purchases/revoke/*": "renders the confirmation form only; revokeViaEmailToken returns before reading the session", - "POST /api/ri-exchange/reject/*": "token-only; rejectRIExchange takes no request, so it cannot read a session", - "POST /api/auth/login": "pre-session: issues the session, so there is no session to protect yet", - "GET /api/auth/check-admin": "read-only", - "POST /api/auth/setup-admin": "pre-session: first-admin bootstrap", - "POST /api/auth/forgot-password": "pre-session: sends a reset email", - "POST /api/auth/reset-password": "pre-session: authorized by the reset token", - "GET /api/auth/reset-password/status": "read-only", - "GET /api/notifications/unsubscribe": "HMAC-signed token only; never reads the session and moves no money", - "POST /api/notifications/unsubscribe": "HMAC-signed token only (RFC 8058); never reads the session and moves no money", - "POST /api/register": "public registration; creates a pending request an admin must approve", - "GET /api/register/*": "read-only", - "ANY /health": "read-only health check", - "ANY /api/health": "read-only health check", - "GET /api/info": "read-only", - "GET /version": "read-only", - "GET /api/docs*": "read-only", - "HEAD /api/docs*": "read-only", - "GET /docs*": "read-only", - "HEAD /docs*": "read-only", + "GET /api/purchases/revoke/*": "renders the confirmation form only; revokeViaEmailToken returns before reading the session", + "POST /api/ri-exchange/reject/*": "token-only; rejectRIExchange takes no request, so it cannot read a session", + "POST /api/purchases/approve/*/details": "read-only (moves no money); still runs validateCSRF before the lookup via requireSessionBeforeLookup, pinned by TestHandleRequest_ApprovalDetails_SessionAndCSRFBeforeLookup (#529)", + "POST /api/auth/login": "pre-session: issues the session, so there is no session to protect yet", + "GET /api/auth/check-admin": "read-only", + "POST /api/auth/setup-admin": "pre-session: first-admin bootstrap", + "POST /api/auth/forgot-password": "pre-session: sends a reset email", + "POST /api/auth/reset-password": "pre-session: authorized by the reset token", + "GET /api/auth/reset-password/status": "read-only", + "GET /api/notifications/unsubscribe": "HMAC-signed token only; never reads the session and moves no money", + "POST /api/notifications/unsubscribe": "HMAC-signed token only (RFC 8058); never reads the session and moves no money", + "POST /api/register": "public registration; creates a pending request an admin must approve", + "GET /api/register/*": "read-only", + "ANY /health": "read-only health check", + "ANY /api/health": "read-only health check", + "GET /api/info": "read-only", + "GET /version": "read-only", + "GET /api/docs*": "read-only", + "HEAD /api/docs*": "read-only", + "GET /docs*": "read-only", + "HEAD /docs*": "read-only", } // csrfGuardFixture is one route's handler plus the checks for both