Enforced in the database

Who may read or change a row in Fóir is decided by Postgres. The rules are written once, in one spec, and compiled into row-level security policies, so the check sits with the data, beneath the application code.

One spec, compiled

The access model lives in a single spec file. Demesne, our open-source compiler, turns it into the policies and the database functions they call. The generated SQL ships exactly as the compiler wrote it, and nobody edits it by hand. At the time of writing it governs about a hundred tables.

Forced, and checked against the live schema

Row-level security is forced on every governed table as well as enabled, which closes the route by which a table's owner reads past a policy. A test reads both settings from the database catalogue and fails if either is off.

A second test lists every table in the schema and fails on any that was added without a recorded decision about how it is protected.

What a request can reach

A request to the API is served under those policies, carrying the caller's workspace, project and organisation as claims the database reads. The policy on each table compares them with the row before any other rule is considered. A row the caller may not see reads as though it does not exist.

Where the application decides

The database cannot tell some actions apart: publishing a record is an update, as far as Postgres is concerned. Those permissions are checked when the request arrives, against a map generated from the same spec, and the row rules still bound what the action can touch.

Read how it works

The documentation covers ownership, visibility, grants and how a request is resolved for each kind of credential.