feat(#1419): P2 Supabase Auth Hooks capture dark login/MFA failures#1473
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Phase 1 (#1420) counts API 401/403 in security_audit_logs, but wrong-password and failed-MFA attempts run inside Supabase GoTrue, never hit our API, and auth.audit_log_entries is empty in prod. This adds two non-blocking, fail-open Postgres Auth Hook functions that record a security_audit_logs row on failure at the GoTrue source, plus the Phase-1 alert coverage for them. - Migration 20260705120000_1419_auth_verification_hooks.sql (idx 343): hook_password_verification_attempt + hook_mfa_verification_attempt. Both ALWAYS return {"decision":"continue"} (monitoring-only, never block a login) and wrap the INSERT in an exception-swallowing block (fail-open). Idempotent create-or-replace + role-guarded grants to supabase_auth_admin (INVOKER rights: usage/execute/insert), execute revoked from anon/authenticated/public. - prod-health-monitor Check-4: adds a scalar sub-count of security.password_failed + security.mfa_failed (no ip → total-only, kept out of the per-IP CTE), factored into the combined total threshold, surfaced in the detail line; degrade-safe (malformed count → 0, never fails the step). - security-audit.types.ts: KNOWN_SECURITY_AUDIT_EVENTS documents the two new hook-sourced events (written by the Postgres functions, not the Nest service). - docs/MONITORING.md section + new runbook enable-supabase-auth-verification-hooks.md (STAGING-FIRST, Al-gated Dashboard enablement; plan-tier caveat flagged). - Foreground SQL assertion test (__tests__/1419_auth_verification_hooks.test.sql): valid=false→continue+1 row; valid=true→continue+0 rows; missing valid→0 rows; fail-open (bad uuid)→continue+no throw+0 rows. 5/5 pass on Dev. Ships the CODE only; the Supabase Dashboard hook enablement is NOT touched (staging-first, Al-gated). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d86f86b to
d33f6fd
Compare
#1419 Phase 2 — capture DARK login/MFA failures at the GoTrue source
Gate: Codex gpt-5.5 xhigh: APPROVE on
d86f86b7(R1 BLOCK → cast-free fix → R2 APPROVE).Do NOT self-merge — coordinator (1.0) is sole merger.
Problem
Phase 1 (#1420) counts API 401/403 (
security.login_failed/security.access_denied) insecurity_audit_logs. But wrong-password and failed-MFA attempts run entirely inside Supabase GoTrue — they never reach our API, andauth.audit_log_entriesis empty in prod. Those failures were dark.What ships (CODE only — no Supabase config touched)
20260705120000_1419_auth_verification_hooks.sql(journal idx 343): two Postgres Auth Hook functionshook_password_verification_attempt/hook_mfa_verification_attempt. Both are monitoring-only: they record asecurity_audit_logsrow (security.password_failed/security.mfa_failed) only on failure, wrap the INSERT inbegin/exception when others then null(fail-open), and ALWAYS return{"decision":"continue"}on both paths — they never reject / rate-limit / block a login. Failure detection is cast-free (event->'valid' = 'false'::jsonb) so a malformed non-booleanvalidcannot throw before the always-continue return. Idempotent create-or-replace + role-guarded grants tosupabase_auth_admin(INVOKER: usage/execute/insert), execute revoked from anon/authenticated/public.prod-health-monitor.ymlCheck-4: folds the two hook-sourced events (noip) into the total brute-force count only — deliberately kept out of the per-IP CTE — surfaced in the detail line; degrade-safe (malformed count → 0, never fails the step).security-audit.types.ts:KNOWN_SECURITY_AUDIT_EVENTSdocuments the two hook-sourced events (written by the Postgres functions, not the Nest service).MONITORING.mdsection + new runbookdocs/runbooks/enable-supabase-auth-verification-hooks.md(staging-first, Al-gated Dashboard enablement; plan-tier caveat flagged).Tests
Foreground SQL assertion test
__tests__/1419_auth_verification_hooks.test.sql— 6/6 pass on Dev: valid=false→continue+1 row; valid=true→continue+0; missing valid→0; fail-open bad-uuid→continue+no throw+0; malformed non-boolean valid→continue+no throw+0 (the R1 fix).Shipping the migration creates the functions but does nothing until the hooks are enabled in the Supabase Dashboard (Authentication > Hooks). Follow the runbook: Staging first, verify a deliberate wrong-password + wrong-MFA each land a row AND login still works, confirm the
supabase_auth_adminINSERT grant, then Prod with Al's go-ahead. Confirm Auth Hooks are available on our plan tier (may need Pro).🤖 Generated with Claude Code