Mediate.Postgres (mediate_postgres v0.1.0)

Copy Markdown View Source

Row-level security as the adapter: the rules are Postgres policies on the tables themselves.

Migrations write the policies. The database enforces them on every statement, with the statements this library never sees among them. The configuration entry is the bare module, because the adapter takes no options (Mediate.Config). The adapter finds the repo and the schemas through the binding that Mediate.Postgres.Binding.bind/1 makes at boot.

Three mechanisms.

Session settings. around_query/3 runs set_config(name, value, true) for the length of the call. It sets mediate.subject_id, mediate.subject_kind, mediate.operation, mediate.now, and one name per fact the caller supplied. A call outside a transaction opens one, so the settings leave with the call. Two subjects in one transaction each set their own. A policy reads a setting with current_setting(name, true).

Answers. decide runs one statement under those settings. A row the operation's SELECT policy does not admit is a denial. Where the operation has an UPDATE gate, the same statement reads the gate's USING expression. So an answer given before a write agrees with what WITH CHECK does to the write.

scope runs no statement and answers the rule true, because the policy narrows the query when the repo runs it. Its reason names the policy and the SHA-256 of the settings the database reads, which together are what it enforced. The scope cap is :none.

Policy versions. The version is the migration number. Mediate.Postgres.Migration.publish!/2 reads the policies back from pg_policy and emits the version in the same transaction as the DDL. the events document under "Policy version" has the event.

The database does not report which policy admitted a row, so an answer names the policy of the operation and nothing further. The adapter reports the replica-lag component of revocation latency as "not measured", because every statement goes to the primary.

The application's role must carry NOBYPASSRLS, because a role with BYPASSRLS is not subject to the policies. The package carries no driver: ecto_sql and postgrex serve its tests alone, and Boundary holds lib to that.

Summary

Functions

Read the policies and the version once, so no call on the request path pays for the read. An application calls this at boot, after the binding.

Read the policies and the version again, for an application that ran a migration after boot. Every call after this one reads what the database now holds.

The component of revocation latency this adapter cannot measure.

Functions

load!()

@spec load!() :: Mediate.Postgres.Catalog.t()

Read the policies and the version once, so no call on the request path pays for the read. An application calls this at boot, after the binding.

reload!()

@spec reload!() :: Mediate.Postgres.Catalog.t()

Read the policies and the version again, for an application that ran a migration after boot. Every call after this one reads what the database now holds.

replica_lag()

@spec replica_lag() :: String.t()

The component of revocation latency this adapter cannot measure.