-- Das RLS-Sicherheitsnetz gehört ins Repository, nicht nur in die Datenbank. -- -- `rls_auto_enable()` und der Ereignis-Trigger `ensure_rls` schalten Row Level -- Security bei jeder neu angelegten Tabelle in `public` sofort ein. Sie sind -- der Grund, warum eine vergessene Policy nichts preisgibt: ohne RLS wäre eine -- neue Tabelle für die Anwendungsrolle offen, mit RLS und ohne Policy ist sie -- leer. Ein Fehler wird so zu einer fehlenden Anzeige statt zu einem Leck. -- -- **Gefunden beim Umzug von Supabase auf einen eigenen Container.** Beide -- Objekte existierten nur in der laufenden Datenbank — angelegt von Hand, in -- keiner Migration. Ein Nachbau aus den Migrationen (die CI tut das bei jedem -- Lauf, und ein neuer Server sowieso) hätte das Netz stillschweigend nicht -- gehabt: alles funktioniert, nur die nächste neue Tabelle wäre ungeschützt. -- -- Der Text ist der aus der Produktion, unverändert übernommen. Auf einer -- Datenbank, die ihn schon hat, ändert diese Migration nichts. create or replace function public.rls_auto_enable() returns event_trigger language plpgsql security definer set search_path to 'public', 'pg_temp' as $function$ declare cmd record; begin for cmd in select * from pg_event_trigger_ddl_commands() where command_tag in ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO') and object_type in ('table', 'partitioned table') loop if cmd.schema_name is not null and cmd.schema_name in ('public') then begin execute format('alter table if exists %s enable row level security', cmd.object_identity); raise log 'rls_auto_enable: enabled RLS on %', cmd.object_identity; exception -- Bewusst geschluckt: ein Ereignis-Trigger, der wirft, lässt die -- ganze DDL scheitern. Eine Tabelle, an der das Einschalten nicht -- klappt, ist ein Fall fürs Protokoll — kein Grund, die Migration -- abzubrechen, die sie gerade anlegt. when others then raise log 'rls_auto_enable: failed to enable RLS on %', cmd.object_identity; end; else raise log 'rls_auto_enable: skip % (Schema %)', cmd.object_identity, cmd.schema_name; end if; end loop; end; $function$; -- `create event trigger` kennt kein `if not exists`; deshalb erst weg, dann neu. -- Auf einer Datenbank ohne den Trigger ist das `drop` folgenlos. drop event trigger if exists ensure_rls; create event trigger ensure_rls on ddl_command_end when tag in ('CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO') execute function public.rls_auto_enable();