Expand description
Org-tree request scope for the entitlement-union RLS fence (ADR-0028/0029).
ADR-0028 replaces the single company_id scoping key with org_unit_id: one org tree per
tenant database (root / company / branch nodes), and a session sees the UNION of the subtrees
under every node it is entitled to — always including the root node, which owns tenant-wide
shared rows. The database half is the policy
org_unit_id = ANY(string_to_array(current_setting('app.scope_unit_ids', true), ',')::uuid[]);
this module is the application half that resolves a session’s entitled ids and carries them
for the duration of a request.
Session variables set by an org request scope, in full:
app.scope_unit_ids— the entitlement-union fence (read by org policies).app.company_id— the legacy equality fence during the re-key transition, resolved from the acting node’s company ancestry.app.acting_unit_id— where new records land: the column DEFAULTnullif(current_setting('app.acting_unit_id', true), '')::uuidon decorated tables (ADR-0029) resolves INSERTs that omitorg_unit_id. Unset/empty → NULL → NOT NULL violation: an insert outside a scope fails loud, never silently unscoped.- the six
app.*audit variables ofcrate::audit_context(actor, correlation id, request facts) when the request carries aRequestAuditContext— set by the audited twinwith_org_request_scope_and_audit, on the same request-dedicated connection, so the auditlog capture function’s triggers read attribution off every write of the request.
During the module-by-module re-key both fences are live at once: some tables still read
app.company_id (ADR-0008 equality fence), org-re-keyed tables read app.scope_unit_ids.
with_org_request_scope therefore sets ALL THREE session variables on one request-dedicated
connection. When the last company-fenced table is re-keyed, the legacy bridge retires with
the old fence.
The scope binds the same REQUEST_CONN task-local as
with_request_scope: every scoped execute helper
in this crate — and therefore every generated repository — runs on that connection and
inherits the fence variables without a single call-site change.
The task-local is not the fence. RLS is. Unscoped statements see the variables unset and match zero rows — fail-closed, identical to the ADR-0008 contract.
Structs§
- OrgScope
- A resolved session scope over the org tree (ADR-0028).
Enums§
- OrgScope
Error - Failures of
resolve_org_scope— all of them mean “do NOT open a scoped session”.
Functions§
- bind_
org_ scope_ on - Bind an explicit org scope onto an already-open transaction/connection, transaction-locally.
- current_
org_ scope - The resolved org scope of the current request, if one is bound.
- execute_
scoped - Tenant-agnostic
executefor hand-written module SQL (ADR-0029): ride the request-dedicated connection when one is bound — carrying whatever fence variables the COMPOSING service’s scope set (with_org_request_scope/with_request_scope) — otherwise execute plainly on the pool. - execute_
unit_ scoped - Statement-level org fence for a write whose row belongs to one org node — the hand-written repository path for callers outside a request scope.
- fetch_
all_ rows_ scoped - Tenant-agnostic
fetch_allfor an untyped row query — the set-returning sibling offetch_optional_row_scoped, same connection discipline: request-dedicated connection when bound, plain pool otherwise, no scope invented. Reads that must ride the request connection (a bare-pool read under a decorated deployment lands on a fresh connection with no fence variables and returns nothing) but owe no company predicate reach for this, not the company-scoped helpers. - fetch_
one_ row_ scoped - Tenant-agnostic
fetch_onefor an untyped row query — the single-row sibling offetch_optional_row_scoped, same connection discipline: request-dedicated connection when bound, plain pool otherwise, no scope invented. - fetch_
optional_ row_ scoped - Tenant-agnostic
fetch_optionalfor an untyped row query — the read twin ofexecute_scoped, same connection discipline: request-dedicated connection when bound, plain pool otherwise, no scope invented. - resolve_
org_ scope - Resolve a session’s scope from the org tree.
- with_
org_ request_ scope - Run
fwith a request-dedicated connection carrying the session’s org scope. - with_
org_ request_ scope_ and_ audit with_org_request_scopeplus the request’s audit attribution (ADR-0025): the sixRequestAuditContextvariables are bound on the same request-dedicated connection, so every write of the request — including the ones that fire the auditlog capture function’s triggers — reads the same actor and request facts off the connection it rides.