docs: hierarchy contract revision 5 — raw-execution prong closes dynamic-identifier evasion (terra r4 F7)
ci/woodpecker/pr/ci Pipeline is pending

This commit is contained in:
fred
2026-08-26 18:55:08 -05:00
parent dcf4220823
commit e32d77e5a1
+24 -7
View File
@@ -35,6 +35,13 @@ extended to raw SQL — it now also fails on class-table name literals
inside SQL strings or tagged SQL templates outside the allowlist, so a inside SQL strings or tagged SQL templates outside the allowlist, so a
raw-SQL writer that touches no schema symbol is still caught. raw-SQL writer that touches no schema symbol is still caught.
Revision 5 (terra r4 residual F7): §6.3(b) gains a third prong — any
raw-SQL execution primitive outside the allowlist fails the assertion
regardless of its SQL content, closing the evasion where a
dynamically constructed table name carries neither a schema symbol nor
a class-table literal. The detection claim is now coextensive with
what the three prongs statically see.
Scope: the tenancy/authorization structure record class — companies, Scope: the tenancy/authorization structure record class — companies,
estates, platform-projects, workspaces, hierarchy grants, their parentage, estates, platform-projects, workspaces, hierarchy grants, their parentage,
and constraints. Out of scope: the RBAC grant vocabulary and evaluation and constraints. Out of scope: the RBAC grant vocabulary and evaluation
@@ -243,13 +250,23 @@ Binding on the implementing PRs (extends A1 §8.3):
occur only in allowlisted modules. (ii) Literal prong: a class-table occur only in allowlisted modules. (ii) Literal prong: a class-table
name appearing inside a SQL string or tagged SQL template outside the name appearing inside a SQL string or tagged SQL template outside the
allowlist fails the assertion — this is what catches a raw-SQL writer allowlist fails the assertion — this is what catches a raw-SQL writer
that references no schema symbol. Schema definitions and generated that references no schema symbol. (iii) Raw-execution prong: any call
migrations are excluded from the literal prong; a false positive to a raw-SQL execution primitive (the ORM's raw/unsafe constructors,
(e.g. a table name in a non-write query string) is resolved by driver-level query/execute) outside the allowlist fails the
extending the allowlist in the same PR, never by weakening the assertion, regardless of what the SQL string contains or how it is
assertion. The allowlist is closed: any new writer, ORM or raw, constructed — the call site is statically detectable even when a
fails CI until the allowlist names it, so the write path is surfaced dynamically assembled table name is not, so a raw writer with a
in review rather than passing unnoticed. runtime-built identifier is caught by its primitive, not its
payload. Schema definitions and generated migrations are excluded
from the literal prong; a false positive (e.g. a table name in a
non-write query string, or a legitimate raw query elsewhere in the
codebase) is resolved by extending the allowlist in the same PR,
never by weakening the assertion. The allowlist is closed: a symbol
writer fails prong (i), a raw writer naming a class table fails
prong (ii), and any raw execution at all outside the allowlist fails
prong (iii), so every new writer — ORM, raw-literal, or
dynamically constructed — fails CI until the allowlist names it and
the write path is surfaced in review rather than passing unnoticed.
4. Audit witnesses: for each mutation class (create, rename, transfer, 4. Audit witnesses: for each mutation class (create, rename, transfer,
grant create/change/revoke, delete) — the event exists after commit grant create/change/revoke, delete) — the event exists after commit
with actor/verb/target and same-transaction atomicity; a rolled-back with actor/verb/target and same-transaction atomicity; a rolled-back