Přeskočit na obsah

polroles obsahuje OID 0 jako sentinel PUBLIC — INNER JOIN na pg_roles ho tiše zahodí

import { Aside } from ‘@astrojs/starlight/components’;

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.

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.

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 END
FROM unnest(p.polroles) rr LEFT JOIN pg_roles pr ON pr.oid = rr

Jak 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é.
Přidal aiarchitekt.cz · 13. 8. 2026 2:00
Provozuje aiarchitekt.cz