Expand description
Request company scope for the Postgres RLS read/write fence (ADR-0008).
The security boundary is the database: every company-scoped table carries a Row-Level-Security
policy USING (company_id = NULLIF(current_setting('app.company_id', true), '')::uuid). This
module is the application half — it carries the caller’s company for the duration of a request
and sets app.company_id on the connection each statement runs on.
Why a task-local and not a signature parameter: the ORM executes connection-per-statement
against a shared pool (fetch_all(&self.pool)), so there is no request-held connection to bind,
and threading a scope argument through CrudService::list would be a breaking change across ~40
modules that still would not reach raw sqlx::query callers. The task-local rides the async
task instead, and the scoped execute helpers below set app.company_id transaction-locally so a
value never leaks onto a pooled connection reused by the next request.
The task-local is not the fence. RLS is. A statement that runs without the task-local set
(a missed call site, a raw query, a spawned job) sees app.company_id unset → the policy matches
zero rows. That is fail-closed: such a path breaks (returns empty), it never leaks. These
helpers exist so the ORM read path returns the caller’s rows instead of empty — correctness, not
safety.
Functions§
- bind_
company_ on - Bind an EXPLICIT company onto an already-open transaction/connection.
- bind_
current_ company - Bind the current task’s company onto an already-open transaction/connection.
- current_
company - The company bound to the current task, or
Nonewhen no scope is set (unscoped code path). - execute_
scoped executefor a write/DDL query (INSERT/UPDATE/DELETE), company-scoped.- fetch_
all_ rows_ scoped fetch_allfor an untyped row query (sqlx::query(..)→Vec<PgRow>), company-scoped.- fetch_
all_ scoped fetch_allfor a typed row query, company-scoped.- fetch_
one_ row_ scoped fetch_onefor an untyped row query (sqlx::query(..)→PgRow), company-scoped.- fetch_
one_ scalar_ scoped fetch_onefor a scalar query (e.g.COUNT(*)), company-scoped.- fetch_
one_ scoped fetch_onefor a typed row query, company-scoped.- fetch_
optional_ row_ scoped fetch_optionalfor an untyped row query (sqlx::query(..)→PgRow), company-scoped.- fetch_
optional_ scalar_ scoped fetch_optionalfor a scalar query (e.g.SELECT 1 … LIMIT 1), company-scoped.- fetch_
optional_ scoped fetch_optionalfor a typed row query, company-scoped.- with_
company_ scope - Run
fwith the request’s company scope bound to the current async task. - with_
request_ scope - Run
fwith a request-dedicated connection whoseapp.company_idis set tocompany.