Skip to content

feat(safegres): pure-Postgres RLS auditor package#1030

Merged
pyramation merged 7 commits intomainfrom
feat/safegres
Apr 27, 2026
Merged

feat(safegres): pure-Postgres RLS auditor package#1030
pyramation merged 7 commits intomainfrom
feat/safegres

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

Summary

Adds graphql/safegres/ — a pure-PostgreSQL Row-Level-Security auditor, MIT-licensed, ready to publish on npm as safegres. The package has zero application dependencies and reads only catalog tables (pg_class, pg_policy, information_schema.role_table_grants, pg_proc).

For convenience, the node-type-registry Authz* / Data* / Relation* / View* type definitions are re-exported here so downstream auditors built on Constructive's type system only need a single dependency:

import { auditPg, AuthzDirectOwner, type NodeTypeDefinition } from 'safegres';

This is the open-source half of the RLS audit work — the closed-source Authz* fingerprint matcher lives in a sibling package in constructive-db.

Findings produced

Code Severity Category Check
A1 critical flags RLS enabled with 0 policies (deny-all)
A2 high flags grants on a table with RLS disabled
A3 medium flags RLS on but FORCE ROW LEVEL SECURITY not set
A4 high coverage INSERT / UPDATE / DELETE grant with no covering policy
A5 medium coverage SELECT grant with no policy
A6 info coverage UPDATE has USING but no WITH CHECK
A7 high anti-pattern trivially-permissive policy (USING (true))
P1 high anti-pattern policy body calls a VOLATILE function
P5 high anti-pattern policy references session_user / pg_has_role

Coverage is aggregated per (table, role) across all applicable permissive policies (FOR ALL, PUBLIC-role policies considered). BYPASSRLS roles are suppressed.

Files added

  • graphql/safegres/src/{ast,checks,pg,report,util,commands}/… — auditor implementation
  • graphql/safegres/src/index.ts — public surface + re-exports
  • graphql/safegres/src/cli.tssafegres pg CLI
  • graphql/safegres/__tests__/… — 16 tests across 3 suites (parse / roles / pg with fixtures)
  • .github/workflows/run-tests.yaml — adds graphql/safegres to the CI matrix

Test results

Test Suites: 3 passed, 3 total
Tests:       16 passed, 16 total

Review & Testing Checklist for Human

  • Confirm safegres is the right package name (vs scoped @constructive-io/safegres). It currently sits as a bare-name public package matching node-type-registry's convention.
  • Confirm the re-export surface in src/index.ts (only Authz* values + NodeTypeDefinition / JSONSchema types) — Data* / Relation* / View* are intentionally not re-exported here since the auditor doesn't need them; happy to widen if you want.
  • When ready, publish safegres@0.1.0 to npm. Then constructive-db's follow-up PR (rls-audit + testing/constructive-audit) will install from npm.

Notes

  • match/ (the fingerprint matcher engine) was deliberately not lifted — it stays closed-source in constructive-db's packages/rls-audit/.
  • Build is via makage (matches node-type-registry); tests via ts-jest (matches graphql/codegen).
  • pgsql-parser is pinned to ^17.9.14 to match other packages in this repo.

Link to Devin session: https://app.devin.ai/sessions/6ab67cb5b65b4d2ba498263198f43e46
Requested by: @pyramation

Pure-PostgreSQL Row-Level-Security auditor with zero application
dependencies. Re-exports the node-type-registry Authz*/Data*/Relation*
type definitions so consumers writing auditors on top of Constructive's
type system can stay on a single dependency.

Detects:
- A1: RLS enabled but no policies (deny-all)
- A2: grants on tables with RLS disabled
- A3: RLS enabled but FORCE not set (owner bypass)
- A4: write grants without covering policy
- A5: read grants without covering policy
- A6: UPDATE coverage missing WITH CHECK
- A7: trivially-permissive policy (USING (true))
- P1: volatile function in policy body
- P5: session_user / pg_has_role gating

Coverage is aggregated per (table, role) across applicable permissive
policies (FOR ALL, PUBLIC role considered). BYPASSRLS roles suppressed.

Adds graphql/safegres to the run-tests CI matrix.
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Drop the hand-rolled argv parser in favor of inquirerer's CLI class +
@inquirerer/utils helpers — same convention as cnc, pgpm, and csdk.

- Remove src/util/args.ts
- Add src/cli/commands.ts (router via extractFirst)
- Add src/cli/pg.ts (pg command handler)
- src/cli.ts now constructs the inquirerer CLI

CLI surface is unchanged (`safegres pg --connection ...`).
- AST walking: drop our 75-line walker; use `@pgsql/traverse`'s walk +
  NodePath. Keep domain-specific helpers (funcNameParts, columnRefPath).
- Logging: `@pgpmjs/logger` Logger replaces console.log/error for
  diagnostics. Report payload still goes to stdout for piping.
- Colors: drop hand-rolled ANSI escape codes in pretty.ts; use `yanse`
  (the same lib @pgpmjs/logger already uses).
- Connection: drop process.env.DATABASE_URL read; use `pg-env`'s
  getPgEnvOptions() with --host/--port/--user/--password/--database
  per-field overrides and `--connection <url>` for full overrides.
- argv coercion: declare flag types in minimist's `string` / `boolean`
  config; drop the local string()/number()/bool() coercer helpers.
@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 27, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​types/​babel__generator@​7.27.01001007280100
Added@​testing-library/​react@​11.2.510010010087100
Added@​tanstack/​react-query@​5.90.219910088100100
Added@​testing-library/​jest-dom@​5.11.1010010010089100
Added@​pgsql/​traverse@​17.2.59210010089100

View full report

The pure-Postgres auditor doesn't use Authz* anywhere — its findings
(A1–A7, P1, P5) are catalog/AST checks with no Constructive-template
knowledge. Re-exporting Authz* values + JSON-Schema configs from a
public MIT package would leak the Constructive policy DSL.

Consumers that need Authz* (rls-audit in constructive-db) can import
directly from node-type-registry. safegres no longer depends on it.
- git mv graphql/safegres/ packages/safegres/ — sibling to other public
  packages instead of under graphql/.
- Update CI matrix entry in .github/workflows/run-tests.yaml.
- Add Safegres brand logo to README:
  https://raw.githubusercontent.com/Safegres/brand/refs/heads/main/safegres.svg
…ions

- README quickstart now uses PGHOST/PGUSER/PGPASSWORD/PGDATABASE env
  vars (matching the rest of the ecosystem) instead of a connection URL.
- Library example uses getPgEnvOptions() from pg-env.
- Drop orphaned 'Authz* type re-exports' section (re-exports were
  already removed in the previous commit).
- Drop trailing 'License: MIT' section.
… audit

- CLI: `safegres pg` -> `safegres audit`. The pg/match split was for a
  match engine that lives in the private rls-audit package, so safegres
  has only one verb — audit is the clearer name.
- Library: `auditPg` -> `audit`, `AuditPgOptions` -> `AuditOptions`.
- Renamed source files to match (cli/pg.ts -> cli/audit.ts, etc.).
- Fix help routing so `safegres audit --help` shows the subcommand help
  instead of the top-level usage.
- README rewrite per Dan's positioning suggestions:
  - 'Pure-Postgres Row-Level Security auditor' headline
  - 'No app framework required' (was 'Zero application dependencies')
  - 'risky SQL policy patterns' (was 'AST-level anti-patterns')
  - Added the longer intro paragraph describing what it actually checks.
@pyramation pyramation merged commit 1fd9e11 into main Apr 27, 2026
52 checks passed
@pyramation pyramation deleted the feat/safegres branch April 27, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant