fix(db): lock down audit_events to the backend (revoke + RLS + grant order)
WHY THIS MATTERS
This repo's threat model explicitly includes direct PostgREST access with the
public anon key - which is why schema.sql revokes anon/authenticated on every
backend-owned table. audit_events shipped with neither a revoke nor RLS, so on a
hosted Supabase deployment its default privileges leave the whole table readable
AND writable from the browser: any visitor could dump every user's email, chat
titles and prompt excerpts, or forge/delete audit rows - which defeats the whole
point of an append-only audit trail.
WHAT IS RLS / PostgREST default access
Supabase exposes every table in schema `public` over PostgREST. Whether the
browser `anon`/`authenticated` roles can touch a table is governed by two
things: (1) SQL table GRANTs (managed Supabase's default ACLs grant these roles
broad privileges on new tables), and (2) Row-Level Security. With RLS disabled
and the default grants in place, the table is wide open. The repo's convention
is defense-in-depth: `revoke all ... from anon, authenticated` removes the
grant, and `enable row level security` (with no policies) means even if a grant
slips back the rows are invisible. service_role bypasses RLS, so the backend
path is unaffected.
HOW IT WORKS
- schema.sql: audit_events now has `revoke all ... from anon, authenticated` in
the revoke block and `enable row level security`, matching every sibling
table.
- Grant ordering (F4): `grant ... on all tables in schema public to
service_role` only covers tables that already exist when it runs. The table
was defined *after* that block, so a fresh plain-Postgres install created it
with no service_role privileges and the backend's inserts failed
permission-denied - silently, because recordAudit swallows errors. The DDL is
moved above the grant block so the blanket grant covers it.
- migration 20260728: adds the same revoke + RLS, plus an explicit
`grant select, insert, update, delete ... to service_role` so a fresh apply
works even where service_role has no default ACL for new tables. The old
comment ("no RLS policies needed, like other app tables") inverted the
convention and is corrected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| Repository | open-legal-products/mike |
|---|---|
| Author | Amal <mamalanand3@gmail.com> |
| Authored | |
| Committed | |
| Parents | 2bf6f9f8 |
| Stats | 2 files changed , +48 , -22 |
| Part of | Add workspace audit history |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-ec34667f.md
from inside the repo you want the change in.