|
| 1 | +# safegres |
| 2 | + |
| 3 | +Pure-PostgreSQL Row-Level-Security auditor. Zero application dependencies — drop it on any Postgres database and get a structured report of grants, RLS flags, policy coverage, and AST-level anti-patterns. |
| 4 | + |
| 5 | +```bash |
| 6 | +npm install -g safegres |
| 7 | +safegres pg --connection postgresql://localhost/mydb |
| 8 | +``` |
| 9 | + |
| 10 | +## What it checks |
| 11 | + |
| 12 | +| Code | Severity | Category | Check | |
| 13 | +| --- | --- | --- | --- | |
| 14 | +| A1 | critical | flags | RLS enabled but **0 policies** (effectively deny-all) | |
| 15 | +| A2 | high | flags | Grants exist on a table with **RLS disabled** | |
| 16 | +| A3 | medium | flags | RLS enabled but **`FORCE ROW LEVEL SECURITY` not set** (table owner bypass) | |
| 17 | +| A4 | high | coverage | INSERT / UPDATE / DELETE grant with **no covering policy** for that verb | |
| 18 | +| A5 | medium | coverage | SELECT grant with **no policy** (silent empty result) | |
| 19 | +| A6 | info | coverage | UPDATE has `USING` but **no `WITH CHECK`** (row-smuggling surface) | |
| 20 | +| A7 | high | anti-pattern | Trivially-permissive policy (`USING (true)` / `WITH CHECK (true)`) | |
| 21 | +| P1 | high | anti-pattern | Policy body calls a **VOLATILE function** (per-row evaluation) | |
| 22 | +| P5 | high | anti-pattern | Policy body references **`session_user`** / `current_user` / `pg_has_role(...)` | |
| 23 | + |
| 24 | +Coverage is aggregated `(table, role) → { hasUsing, hasWithCheck }` across every applicable permissive policy (FOR ALL + PUBLIC-role policies considered). Roles with `BYPASSRLS` are suppressed. |
| 25 | + |
| 26 | +## Library use |
| 27 | + |
| 28 | +```ts |
| 29 | +import { Client } from 'pg'; |
| 30 | +import { auditPg, renderPretty } from 'safegres'; |
| 31 | + |
| 32 | +const client = new Client({ connectionString: process.env.DATABASE_URL }); |
| 33 | +await client.connect(); |
| 34 | + |
| 35 | +const report = await auditPg(client, { |
| 36 | + excludeSchemas: ['my_private_schema'] |
| 37 | +}); |
| 38 | + |
| 39 | +console.log(renderPretty(report)); |
| 40 | +console.log(`${report.findings.length} findings`); |
| 41 | +``` |
| 42 | + |
| 43 | +## Authz* type re-exports |
| 44 | + |
| 45 | +`safegres` re-exports the [`node-type-registry`](../node-type-registry) Authz* / Data* / Relation* / View* type registry so consumers building auditors on top of Constructive's type system can stay on a single dependency: |
| 46 | + |
| 47 | +```ts |
| 48 | +import { AuthzDirectOwner, type NodeTypeDefinition } from 'safegres'; |
| 49 | +``` |
| 50 | + |
| 51 | +## License |
| 52 | + |
| 53 | +MIT. |
0 commit comments