polroles obsahuje OID 0 jako sentinel PUBLIC — INNER JOIN na pg_roles ho tiše zahodí
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Otisk RLS policies počítal role přes unnest(polroles) JOIN pg_roles. U policies TO PUBLIC
join nic nenašel, string_agg vrátil NULL a vnější COALESCE dodal náhradní hodnotu — takže
výsledek vypadal správně a nikdo si nevšiml, že se role ve skutečnosti zahazují. Odhalilo se to
až po zavedení tvrdé chyby pro neznámé OID: vystřelila na PRVNÍ produkční policy.
Root cause
Sekce “Root cause”pg_policy.polroles ukládá TO PUBLIC jako pole {0}. OID 0 v pg_roles neexistuje — je to
sentinel. Stejný vzor má aclexplode().grantee (0 = PUBLIC). INNER JOIN sentinel tiše eliminuje.
Fix
Sekce “Fix”CASE WHEN rr = 0 THEN 'PUBLIC' -- legitimní sentinel WHEN pr.rolname IS NULL THEN (1/(rr::bigint-rr::bigint))::text -- neznámé OID = tvrdá chyba ELSE pr.rolname ENDFROM unnest(p.polroles) rr LEFT JOIN pg_roles pr ON pr.oid = rrJak se tomu vyvarovat v jiných systémech
Sekce “Jak se tomu vyvarovat v jiných systémech”- Detection:
grep -n "unnest(.*polroles.*) .*JOIN pg_roles"bez CASE na 0. - Anti-pattern: INNER JOIN na katalogové sentinel hodnoty + COALESCE, který ztrátu maskuje.
- Lepší přístup: LEFT JOIN + explicitní sentinel větev + fail-closed větev pro neznámé.