feat(safegres): pure-Postgres RLS auditor package#1030
Merged
pyramation merged 7 commits intomainfrom Apr 27, 2026
Merged
Conversation
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.
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
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.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
graphql/safegres/— a pure-PostgreSQL Row-Level-Security auditor, MIT-licensed, ready to publish on npm assafegres. 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-registryAuthz* / Data* / Relation* / View* type definitions are re-exported here so downstream auditors built on Constructive's type system only need a single dependency: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
FORCE ROW LEVEL SECURITYnot setUSINGbut noWITH CHECKUSING (true))session_user/pg_has_roleCoverage is aggregated per
(table, role)across all applicable permissive policies (FOR ALL,PUBLIC-role policies considered).BYPASSRLSroles are suppressed.Files added
graphql/safegres/src/{ast,checks,pg,report,util,commands}/…— auditor implementationgraphql/safegres/src/index.ts— public surface + re-exportsgraphql/safegres/src/cli.ts—safegres pgCLIgraphql/safegres/__tests__/…— 16 tests across 3 suites (parse / roles / pg with fixtures).github/workflows/run-tests.yaml— addsgraphql/safegresto the CI matrixTest results
Review & Testing Checklist for Human
safegresis the right package name (vs scoped@constructive-io/safegres). It currently sits as a bare-name public package matchingnode-type-registry's convention.src/index.ts(only Authz* values +NodeTypeDefinition/JSONSchematypes) — Data* / Relation* / View* are intentionally not re-exported here since the auditor doesn't need them; happy to widen if you want.safegres@0.1.0to 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 inconstructive-db'spackages/rls-audit/.makage(matchesnode-type-registry); tests viats-jest(matchesgraphql/codegen).pgsql-parseris pinned to^17.9.14to match other packages in this repo.Link to Devin session: https://app.devin.ai/sessions/6ab67cb5b65b4d2ba498263198f43e46
Requested by: @pyramation