KB-3079
dot-iu-cutter v0.3 — Directus / PG RLS Read-Policy Design (conditional; not needed for v0.3) (2026-05-16)
4 min read Revision 1
dot-iu-cutterdieu44v0.3designrlsread-policydesign-only
dot-iu-cutter v0.3 — PG RLS Read-Policy Design (conditional)
document_path: knowledge/dev/laws/dieu44-trien-khai/v0.3-design/dot-iu-cutter-v0.3-directus-rls-read-policy-design-2026-05-16.md
revision: r1
date: 2026-05-16
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.3 — DESIGN ONLY (RLS read-policy — conditional/forward option)
status: design_authored_for_gpt_review
nothing_executed: true
rls_required_for_v0_3: false
⛔ DESIGN ONLY — no
ALTER TABLE … ENABLE ROW LEVEL SECURITY, noCREATE POLICY, no GRANT/REVOKE executed. RLS is NOT required for v0.3 read-only observability; this documents a conditional forward option.
§1 — Verdict
is_PG_RLS_needed_for_v0_3_read_observability: NO
basis:
- requirement = observe ALL rows of governance tables; NO per-row
tenant/owner/confidentiality partition is specified.
- current rows = 0 on all 12 tables; no confidentiality boundary exists yet.
- COLUMN sensitivity (signature material, snapshots, reviewer_identity) is
handled by VIEW projection / Directus field permissions — RLS does NOT do
column hiding (it filters rows, not columns).
- least-change principle: enabling RLS is a table-level behavioural change to
shared infrastructure with FORCE/owner-bypass subtleties; unjustified for a
pure read-all use case.
recommended_v0_3_control: GRANT SELECT on read VIEWS to a least-privilege PG
role (see role/permission-matrix doc) — sufficient and lower-risk than RLS.
§2 — When RLS WOULD Become Necessary (forward triggers, not now)
trigger_R1: observers must NOT see certain rows (e.g. restrict by scenario_ref,
by reviewer_class, by risk_class_assessment, or hide superseded lineage).
trigger_R2: multi-tenant / multi-jurisdiction row partitioning is introduced.
trigger_R3: a write path is later added and defense-in-depth requires the same
table to be readable by some roles but row-limited for observers.
note: none of R1–R3 is requested for v0.3. If raised, RLS design re-opens under
its own authorization.
§3 — Conditional RLS Read-Policy Specification (ONLY if a trigger fires)
Illustrative SELECT-only policy shape (NOT to be executed in v0.3):
-- CONDITIONAL — do NOT execute under v0.3 scope
-- ALTER TABLE cutter_governance.<t> ENABLE ROW LEVEL SECURITY;
-- ALTER TABLE cutter_governance.<t> FORCE ROW LEVEL SECURITY; -- so table owner is also constrained
-- CREATE POLICY <t>_ro_select ON cutter_governance.<t>
-- FOR SELECT TO cutter_ro
-- USING ( <row predicate, e.g. scenario_ref <> 'restricted'
-- OR has_role('cutter_ro_full')> );
policy_shape_rules (if ever used):
- SELECT-only (FOR SELECT); never FOR ALL/INSERT/UPDATE/DELETE for observers
- TO cutter_ro (never PUBLIC)
- USING only; no WITH CHECK (no writes)
- FORCE RLS so the table owner does not silently bypass
- the migration/exec role must NOT have BYPASSRLS for the policy to mean
anything for it
- one policy per table; named <table>_ro_select; reversible by DROP POLICY +
DISABLE RLS
interaction_with_views: if VIEW projection is the chosen column-control, RLS (if
later needed) should be applied on BASE tables and the views run with
security_invoker=on so RLS is honoured through the view (PG15+; prod is PG16).
§4 — RLS Rollback (if ever enabled — forward note)
rollback: DROP POLICY <t>_ro_select ON cutter_governance.<t>;
ALTER TABLE cutter_governance.<t> NO FORCE ROW LEVEL SECURITY;
ALTER TABLE cutter_governance.<t> DISABLE ROW LEVEL SECURITY;
safety: tables empty ⇒ enabling/disabling RLS has no data effect; fully
reversible; baseline = RLS disabled (current true state).
§5 — Non-Scope
executed: NONE. No RLS enable/policy/force/grant. Conditional design only.
rls_in_v0_3: NOT recommended, NOT designed for execution.
self_advance: PROHIBITED
End of v0.3 PG RLS read-policy design (conditional; not needed for v0.3).