Skip to main content

Module company_scope

Module company_scope 

Source
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 None when no scope is set (unscoped code path).
execute_scoped
execute for a write/DDL query (INSERT/UPDATE/DELETE), company-scoped.
fetch_all_rows_scoped
fetch_all for an untyped row query (sqlx::query(..) → Vec<PgRow>), company-scoped.
fetch_all_scoped
fetch_all for a typed row query, company-scoped.
fetch_one_row_scoped
fetch_one for an untyped row query (sqlx::query(..) → PgRow), company-scoped.
fetch_one_scalar_scoped
fetch_one for a scalar query (e.g. COUNT(*)), company-scoped.
fetch_one_scoped
fetch_one for a typed row query, company-scoped.
fetch_optional_row_scoped
fetch_optional for an untyped row query (sqlx::query(..) → PgRow), company-scoped.
fetch_optional_scalar_scoped
fetch_optional for a scalar query (e.g. SELECT 1 … LIMIT 1), company-scoped.
fetch_optional_scoped
fetch_optional for a typed row query, company-scoped.
with_company_scope
Run f with the request’s company scope bound to the current async task.
with_request_scope
Run f with a request-dedicated connection whose app.company_id is set to company.