@safegres/test 0.0.2 → 1.30.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +825 -412
- package/adapters.d.ts +8 -0
- package/adapters.js +18 -0
- package/ast/helpers.d.ts +16 -0
- package/ast/helpers.js +40 -0
- package/ast/parse.d.ts +31 -0
- package/ast/parse.js +87 -0
- package/ast/walk.d.ts +27 -0
- package/ast/walk.js +79 -0
- package/callgraph/baseline.d.ts +28 -0
- package/callgraph/baseline.js +55 -0
- package/callgraph/extract.d.ts +93 -0
- package/callgraph/extract.js +340 -0
- package/callgraph/graph.d.ts +82 -0
- package/callgraph/graph.js +276 -0
- package/checks/anti-patterns.d.ts +53 -0
- package/checks/anti-patterns.js +247 -0
- package/checks/column-grants.d.ts +20 -0
- package/checks/column-grants.js +74 -0
- package/checks/coverage.d.ts +43 -0
- package/checks/coverage.js +110 -0
- package/checks/definer-function.d.ts +91 -0
- package/checks/definer-function.js +458 -0
- package/checks/definer-view.d.ts +167 -0
- package/checks/definer-view.js +392 -0
- package/checks/indexes.d.ts +82 -0
- package/checks/indexes.js +263 -0
- package/checks/lattice.d.ts +179 -0
- package/checks/lattice.js +487 -0
- package/checks/object-acls.d.ts +32 -0
- package/checks/object-acls.js +129 -0
- package/checks/policy-index.d.ts +78 -0
- package/checks/policy-index.js +349 -0
- package/checks/revocable-grants.d.ts +140 -0
- package/checks/revocable-grants.js +377 -0
- package/checks/rls-flags.d.ts +25 -0
- package/checks/rls-flags.js +82 -0
- package/checks/role-reach.d.ts +329 -0
- package/checks/role-reach.js +277 -0
- package/checks/role-trust.d.ts +45 -0
- package/checks/role-trust.js +91 -0
- package/checks/set-role.d.ts +21 -0
- package/checks/set-role.js +66 -0
- package/checks/stats.d.ts +52 -0
- package/checks/stats.js +192 -0
- package/checks/view-exposure.d.ts +68 -0
- package/checks/view-exposure.js +236 -0
- package/checks/view-writes.d.ts +88 -0
- package/checks/view-writes.js +350 -0
- package/ci/baseline.d.ts +104 -0
- package/ci/baseline.js +111 -0
- package/ci/github.d.ts +47 -0
- package/ci/github.js +197 -0
- package/cli/audit.d.ts +3 -0
- package/cli/audit.js +560 -0
- package/cli/baseline.d.ts +3 -0
- package/cli/baseline.js +104 -0
- package/cli/commands.d.ts +2 -0
- package/cli/commands.js +60 -0
- package/cli/doctor.d.ts +3 -0
- package/cli/doctor.js +72 -0
- package/cli/eval.d.ts +3 -0
- package/cli/eval.js +153 -0
- package/cli/print-config.d.ts +3 -0
- package/cli/print-config.js +54 -0
- package/cli/shared.d.ts +43 -0
- package/cli/shared.js +153 -0
- package/cli.d.ts +2 -0
- package/cli.js +69 -0
- package/commands/audit.d.ts +65 -0
- package/commands/audit.js +779 -0
- package/commands/doctor.d.ts +19 -0
- package/commands/doctor.js +181 -0
- package/commands/eval.d.ts +67 -0
- package/commands/eval.js +93 -0
- package/config/fingerprint.d.ts +40 -0
- package/config/fingerprint.js +71 -0
- package/config/loader.d.ts +44 -0
- package/config/loader.js +210 -0
- package/config/presets.d.ts +95 -0
- package/config/presets.js +327 -0
- package/config/resolve.d.ts +47 -0
- package/config/resolve.js +192 -0
- package/config/schema.d.ts +54 -0
- package/config/schema.js +269 -0
- package/config/types.d.ts +562 -0
- package/config/validate.d.ts +14 -0
- package/config/validate.js +125 -0
- package/corpus/README.md +83 -0
- package/corpus/bootstrap.sql +14 -0
- package/corpus/cases/01-anon-write-grant/case.json +26 -0
- package/corpus/cases/01-anon-write-grant/schema.sql +19 -0
- package/corpus/cases/02-grant-to-public/case.json +25 -0
- package/corpus/cases/02-grant-to-public/schema.sql +18 -0
- package/corpus/cases/03-rls-off-reachable-by-anon/case.json +30 -0
- package/corpus/cases/03-rls-off-reachable-by-anon/schema.sql +13 -0
- package/corpus/cases/04-permissive-write-policy/case.json +30 -0
- package/corpus/cases/04-permissive-write-policy/schema.sql +21 -0
- package/corpus/cases/05-public-read-policy/case.json +25 -0
- package/corpus/cases/05-public-read-policy/schema.sql +16 -0
- package/corpus/cases/06-update-without-with-check/case.json +25 -0
- package/corpus/cases/06-update-without-with-check/schema.sql +19 -0
- package/corpus/cases/07-rls-enabled-no-policies/case.json +29 -0
- package/corpus/cases/07-rls-enabled-no-policies/schema.sql +14 -0
- package/corpus/cases/08-select-grant-no-policy/case.json +25 -0
- package/corpus/cases/08-select-grant-no-policy/schema.sql +20 -0
- package/corpus/cases/09-write-grant-no-policy/case.json +24 -0
- package/corpus/cases/09-write-grant-no-policy/schema.sql +18 -0
- package/corpus/cases/10-rls-not-forced/case.json +24 -0
- package/corpus/cases/10-rls-not-forced/schema.sql +18 -0
- package/corpus/cases/11-session-user-in-policy/case.json +24 -0
- package/corpus/cases/11-session-user-in-policy/schema.sql +18 -0
- package/corpus/cases/12-volatile-function-in-policy/case.json +24 -0
- package/corpus/cases/12-volatile-function-in-policy/schema.sql +21 -0
- package/corpus/cases/13-security-definer-policy-wrapper/case.json +24 -0
- package/corpus/cases/13-security-definer-policy-wrapper/schema.sql +21 -0
- package/corpus/cases/14-dead-policy/case.json +24 -0
- package/corpus/cases/14-dead-policy/schema.sql +18 -0
- package/corpus/cases/15-unreachable-grant/case.json +24 -0
- package/corpus/cases/15-unreachable-grant/schema.sql +18 -0
- package/corpus/cases/16-anon-permissive-write-policy/case.json +34 -0
- package/corpus/cases/16-anon-permissive-write-policy/schema.sql +17 -0
- package/corpus/cases/17-foreign-key-without-index/case.json +24 -0
- package/corpus/cases/17-foreign-key-without-index/schema.sql +18 -0
- package/corpus/cases/18-policy-column-unindexed/case.json +24 -0
- package/corpus/cases/18-policy-column-unindexed/schema.sql +23 -0
- package/corpus/cases/19-policy-column-cast/case.json +24 -0
- package/corpus/cases/19-policy-column-cast/schema.sql +19 -0
- package/corpus/cases/20-stable-function-per-row/case.json +24 -0
- package/corpus/cases/20-stable-function-per-row/schema.sql +25 -0
- package/corpus/cases/21-table-without-primary-key/case.json +24 -0
- package/corpus/cases/21-table-without-primary-key/schema.sql +14 -0
- package/corpus/cases/22-redundant-index/case.json +24 -0
- package/corpus/cases/22-redundant-index/schema.sql +16 -0
- package/corpus/cases/23-tsvector-without-index/case.json +24 -0
- package/corpus/cases/23-tsvector-without-index/schema.sql +13 -0
- package/corpus/cases/24-anon-set-role-escalation/case.json +29 -0
- package/corpus/cases/24-anon-set-role-escalation/schema.sql +30 -0
- package/corpus/cases/25-definer-view-bypass/case.json +31 -0
- package/corpus/cases/25-definer-view-bypass/schema.sql +36 -0
- package/corpus/cases/26-invoker-view-no-bypass/case.json +31 -0
- package/corpus/cases/26-invoker-view-no-bypass/schema.sql +44 -0
- package/corpus/cases/27-definer-view-write/case.json +36 -0
- package/corpus/cases/27-definer-view-write/schema.sql +40 -0
- package/corpus/cases/28-invoker-view-no-write/case.json +31 -0
- package/corpus/cases/28-invoker-view-no-write/schema.sql +37 -0
- package/corpus/cases/29-rewrite-rule-bypass/case.json +36 -0
- package/corpus/cases/29-rewrite-rule-bypass/schema.sql +52 -0
- package/corpus/cases/30-instead-nothing-rule/case.json +31 -0
- package/corpus/cases/30-instead-nothing-rule/schema.sql +44 -0
- package/corpus/cases/31-matview-snapshot/case.json +32 -0
- package/corpus/cases/31-matview-snapshot/schema.sql +36 -0
- package/corpus/cases/32-matview-no-rls-no-bypass/case.json +30 -0
- package/corpus/cases/32-matview-no-rls-no-bypass/schema.sql +18 -0
- package/corpus/cases/33-leaky-filter-view/case.json +36 -0
- package/corpus/cases/33-leaky-filter-view/schema.sql +29 -0
- package/corpus/cases/34-barrier-view-no-leak/case.json +32 -0
- package/corpus/cases/34-barrier-view-no-leak/schema.sql +29 -0
- package/corpus/cases/35-column-grant-projection/case.json +27 -0
- package/corpus/cases/35-column-grant-projection/schema.sql +21 -0
- package/corpus/cases/35-policy-function-not-leakproof/case.json +24 -0
- package/corpus/cases/35-policy-function-not-leakproof/schema.sql +27 -0
- package/corpus/cases/36-column-grant-rls-mediated/case.json +27 -0
- package/corpus/cases/36-column-grant-rls-mediated/schema.sql +32 -0
- package/corpus/cases/36-policy-function-leakproof/case.json +24 -0
- package/corpus/cases/36-policy-function-leakproof/schema.sql +22 -0
- package/corpus/cases/37-sort-column-unindexed/case.json +24 -0
- package/corpus/cases/37-sort-column-unindexed/schema.sql +14 -0
- package/corpus/cases/37-unaudited-base-relation/case.json +30 -0
- package/corpus/cases/37-unaudited-base-relation/schema.sql +45 -0
- package/corpus/cases/38-foreign-key-with-index/case.json +22 -0
- package/corpus/cases/38-foreign-key-with-index/schema.sql +17 -0
- package/corpus/cases/38-invoker-view-unaudited-base/case.json +30 -0
- package/corpus/cases/38-invoker-view-unaudited-base/schema.sql +39 -0
- package/corpus/cases/39-definer-view-column-subset/case.json +30 -0
- package/corpus/cases/39-definer-view-column-subset/schema.sql +29 -0
- package/corpus/cases/39-policy-cast-with-expression-index/case.json +23 -0
- package/corpus/cases/39-policy-cast-with-expression-index/schema.sql +19 -0
- package/corpus/cases/40-definer-view-column-overreach/case.json +27 -0
- package/corpus/cases/40-definer-view-column-overreach/schema.sql +29 -0
- package/corpus/cases/40-stable-function-hoisted/case.json +23 -0
- package/corpus/cases/40-stable-function-hoisted/schema.sql +25 -0
- package/corpus/cases/41-index-prefix-not-redundant/case.json +21 -0
- package/corpus/cases/41-index-prefix-not-redundant/schema.sql +15 -0
- package/corpus/cases/41-unreadable-view-body/case.json +33 -0
- package/corpus/cases/41-unreadable-view-body/schema.sql +28 -0
- package/corpus/cases/42-invoker-view-unreadable-body/case.json +30 -0
- package/corpus/cases/42-invoker-view-unreadable-body/schema.sql +27 -0
- package/corpus/cases/42-search-column-indexed/case.json +21 -0
- package/corpus/cases/42-search-column-indexed/schema.sql +12 -0
- package/corpus/cases/43-anon-sequence-grant/case.json +27 -0
- package/corpus/cases/43-anon-sequence-grant/schema.sql +23 -0
- package/corpus/cases/44-serial-sequence-usage/case.json +27 -0
- package/corpus/cases/44-serial-sequence-usage/schema.sql +25 -0
- package/corpus/cases/45-anon-foreign-table/case.json +27 -0
- package/corpus/cases/45-anon-foreign-table/schema.sql +23 -0
- package/corpus/cases/46-unchecked-writable-view/case.json +41 -0
- package/corpus/cases/46-unchecked-writable-view/schema.sql +37 -0
- package/corpus/cases/47-checked-writable-view/case.json +37 -0
- package/corpus/cases/47-checked-writable-view/schema.sql +38 -0
- package/corpus/cases/48-definer-function-reach/case.json +38 -0
- package/corpus/cases/48-definer-function-reach/schema.sql +41 -0
- package/corpus/cases/49-invoker-function-no-reach/case.json +32 -0
- package/corpus/cases/49-invoker-function-no-reach/schema.sql +38 -0
- package/corpus/cases/50-instead-of-trigger-write/case.json +38 -0
- package/corpus/cases/50-instead-of-trigger-write/schema.sql +58 -0
- package/corpus/cases/51-invoker-trigger-no-write/case.json +33 -0
- package/corpus/cases/51-invoker-trigger-no-write/schema.sql +54 -0
- package/corpus/cases/52-revocable-execute-grant/case.json +30 -0
- package/corpus/cases/52-revocable-execute-grant/schema.sql +45 -0
- package/corpus/cases/53-policy-predicate-retains-execute/case.json +23 -0
- package/corpus/cases/53-policy-predicate-retains-execute/schema.sql +49 -0
- package/corpus/index.d.ts +79 -0
- package/corpus/index.js +125 -0
- package/esm/adapters.d.ts +8 -0
- package/esm/adapters.js +6 -0
- package/esm/ast/helpers.d.ts +16 -0
- package/esm/ast/helpers.js +36 -0
- package/esm/ast/parse.d.ts +31 -0
- package/esm/ast/parse.js +82 -0
- package/esm/ast/walk.d.ts +27 -0
- package/esm/ast/walk.js +72 -0
- package/esm/callgraph/baseline.d.ts +28 -0
- package/esm/callgraph/baseline.js +48 -0
- package/esm/callgraph/extract.d.ts +93 -0
- package/esm/callgraph/extract.js +333 -0
- package/esm/callgraph/graph.d.ts +82 -0
- package/esm/callgraph/graph.js +273 -0
- package/esm/checks/anti-patterns.d.ts +53 -0
- package/esm/checks/anti-patterns.js +240 -0
- package/esm/checks/column-grants.d.ts +20 -0
- package/esm/checks/column-grants.js +71 -0
- package/esm/checks/coverage.d.ts +43 -0
- package/esm/checks/coverage.js +104 -0
- package/esm/checks/definer-function.d.ts +91 -0
- package/esm/checks/definer-function.js +452 -0
- package/esm/checks/definer-view.d.ts +167 -0
- package/esm/checks/definer-view.js +382 -0
- package/esm/checks/indexes.d.ts +82 -0
- package/esm/checks/indexes.js +256 -0
- package/esm/checks/lattice.d.ts +179 -0
- package/esm/checks/lattice.js +475 -0
- package/esm/checks/object-acls.d.ts +32 -0
- package/esm/checks/object-acls.js +125 -0
- package/esm/checks/policy-index.d.ts +78 -0
- package/esm/checks/policy-index.js +342 -0
- package/esm/checks/revocable-grants.d.ts +140 -0
- package/esm/checks/revocable-grants.js +373 -0
- package/esm/checks/rls-flags.d.ts +25 -0
- package/esm/checks/rls-flags.js +77 -0
- package/esm/checks/role-reach.d.ts +329 -0
- package/esm/checks/role-reach.js +270 -0
- package/esm/checks/role-trust.d.ts +45 -0
- package/esm/checks/role-trust.js +86 -0
- package/esm/checks/set-role.d.ts +21 -0
- package/esm/checks/set-role.js +63 -0
- package/esm/checks/stats.d.ts +52 -0
- package/esm/checks/stats.js +184 -0
- package/esm/checks/view-exposure.d.ts +68 -0
- package/esm/checks/view-exposure.js +231 -0
- package/esm/checks/view-writes.d.ts +88 -0
- package/esm/checks/view-writes.js +344 -0
- package/esm/ci/baseline.d.ts +104 -0
- package/esm/ci/baseline.js +107 -0
- package/esm/ci/github.d.ts +47 -0
- package/esm/ci/github.js +161 -0
- package/esm/cli/audit.d.ts +3 -0
- package/esm/cli/audit.js +525 -0
- package/esm/cli/baseline.d.ts +3 -0
- package/esm/cli/baseline.js +102 -0
- package/esm/cli/commands.d.ts +2 -0
- package/esm/cli/commands.js +53 -0
- package/esm/cli/doctor.d.ts +3 -0
- package/esm/cli/doctor.js +67 -0
- package/esm/cli/eval.d.ts +3 -0
- package/esm/cli/eval.js +115 -0
- package/esm/cli/print-config.d.ts +3 -0
- package/esm/cli/print-config.js +52 -0
- package/esm/cli/shared.d.ts +43 -0
- package/esm/cli/shared.js +112 -0
- package/esm/cli.d.ts +2 -0
- package/esm/cli.js +67 -0
- package/esm/commands/audit.d.ts +65 -0
- package/esm/commands/audit.js +776 -0
- package/esm/commands/doctor.d.ts +19 -0
- package/esm/commands/doctor.js +178 -0
- package/esm/commands/eval.d.ts +67 -0
- package/esm/commands/eval.js +90 -0
- package/esm/config/fingerprint.d.ts +40 -0
- package/esm/config/fingerprint.js +68 -0
- package/esm/config/loader.d.ts +44 -0
- package/esm/config/loader.js +172 -0
- package/esm/config/presets.d.ts +95 -0
- package/esm/config/presets.js +324 -0
- package/esm/config/resolve.d.ts +47 -0
- package/esm/config/resolve.js +180 -0
- package/esm/config/schema.d.ts +54 -0
- package/esm/config/schema.js +265 -0
- package/esm/config/types.d.ts +562 -0
- package/esm/config/validate.d.ts +14 -0
- package/esm/config/validate.js +122 -0
- package/esm/corpus/index.d.ts +79 -0
- package/esm/corpus/index.js +85 -0
- package/esm/exposure/adapters.d.ts +152 -0
- package/esm/exposure/adapters.js +463 -0
- package/esm/exposure/planes.d.ts +59 -0
- package/esm/exposure/planes.js +144 -0
- package/esm/exposure/reach.d.ts +78 -0
- package/esm/exposure/reach.js +105 -0
- package/esm/exposure/routines.d.ts +36 -0
- package/esm/exposure/routines.js +54 -0
- package/esm/index.d.ts +96 -0
- package/esm/index.js +57 -6
- package/esm/lint/index.d.ts +11 -0
- package/esm/lint/index.js +10 -0
- package/esm/perf/baseline.d.ts +40 -0
- package/esm/perf/baseline.js +83 -0
- package/esm/perf/explain.d.ts +46 -0
- package/esm/perf/explain.js +201 -0
- package/esm/pg/acl.d.ts +72 -0
- package/esm/pg/acl.js +186 -0
- package/esm/pg/behaviors.d.ts +114 -0
- package/esm/pg/behaviors.js +206 -0
- package/esm/pg/exposure.d.ts +74 -0
- package/esm/pg/exposure.js +198 -0
- package/esm/pg/functions.d.ts +52 -0
- package/esm/pg/functions.js +128 -0
- package/esm/pg/indexes.d.ts +192 -0
- package/esm/pg/indexes.js +395 -0
- package/esm/pg/introspect.d.ts +134 -0
- package/esm/pg/introspect.js +274 -0
- package/esm/pg/objects.d.ts +37 -0
- package/esm/pg/objects.js +108 -0
- package/esm/pg/paths.d.ts +114 -0
- package/esm/pg/paths.js +159 -0
- package/esm/pg/proc.d.ts +23 -0
- package/esm/pg/proc.js +55 -0
- package/esm/pg/reach-inputs.d.ts +47 -0
- package/esm/pg/reach-inputs.js +133 -0
- package/esm/pg/roles.d.ts +28 -0
- package/esm/pg/roles.js +50 -0
- package/esm/pg/stats.d.ts +65 -0
- package/esm/pg/stats.js +129 -0
- package/esm/pgpm-test.d.ts +22 -0
- package/esm/pgpm-test.js +39 -0
- package/esm/report/callgraph.d.ts +9 -0
- package/esm/report/callgraph.js +74 -0
- package/esm/report/compare.d.ts +143 -0
- package/esm/report/compare.js +195 -0
- package/esm/report/github.d.ts +74 -0
- package/esm/report/github.js +290 -0
- package/esm/report/json.d.ts +4 -0
- package/esm/report/json.js +3 -0
- package/esm/report/markdown.d.ts +25 -0
- package/esm/report/markdown.js +352 -0
- package/esm/report/pretty.d.ts +14 -0
- package/esm/report/pretty.js +318 -0
- package/esm/report/sarif.d.ts +40 -0
- package/esm/report/sarif.js +189 -0
- package/esm/report/view.d.ts +82 -0
- package/esm/report/view.js +126 -0
- package/esm/rules/registry.d.ts +66 -0
- package/esm/rules/registry.js +562 -0
- package/esm/score/score.d.ts +84 -0
- package/esm/score/score.js +233 -0
- package/esm/score/scorecards.d.ts +68 -0
- package/esm/score/scorecards.js +157 -0
- package/esm/types.d.ts +292 -0
- package/esm/types.js +26 -0
- package/esm/version.d.ts +8 -0
- package/esm/version.js +9 -0
- package/exposure/adapters.d.ts +152 -0
- package/exposure/adapters.js +468 -0
- package/exposure/planes.d.ts +59 -0
- package/exposure/planes.js +151 -0
- package/exposure/reach.d.ts +78 -0
- package/exposure/reach.js +109 -0
- package/exposure/routines.d.ts +36 -0
- package/exposure/routines.js +57 -0
- package/index.d.ts +96 -6
- package/index.js +229 -6
- package/lint/index.d.ts +11 -0
- package/lint/index.js +19 -0
- package/package.json +54 -48
- package/perf/baseline.d.ts +40 -0
- package/perf/baseline.js +92 -0
- package/perf/explain.d.ts +46 -0
- package/perf/explain.js +204 -0
- package/pg/acl.d.ts +72 -0
- package/pg/acl.js +191 -0
- package/pg/behaviors.d.ts +114 -0
- package/pg/behaviors.js +217 -0
- package/pg/exposure.d.ts +74 -0
- package/pg/exposure.js +205 -0
- package/pg/functions.d.ts +52 -0
- package/pg/functions.js +131 -0
- package/pg/indexes.d.ts +192 -0
- package/pg/indexes.js +400 -0
- package/pg/introspect.d.ts +134 -0
- package/pg/introspect.js +280 -0
- package/pg/objects.d.ts +37 -0
- package/pg/objects.js +111 -0
- package/pg/paths.d.ts +114 -0
- package/pg/paths.js +166 -0
- package/pg/proc.d.ts +23 -0
- package/pg/proc.js +58 -0
- package/pg/reach-inputs.d.ts +47 -0
- package/pg/reach-inputs.js +136 -0
- package/pg/roles.d.ts +28 -0
- package/pg/roles.js +54 -0
- package/pg/stats.d.ts +65 -0
- package/pg/stats.js +133 -0
- package/pgpm-test.d.ts +22 -0
- package/pgpm-test.js +42 -0
- package/report/callgraph.d.ts +9 -0
- package/report/callgraph.js +81 -0
- package/report/compare.d.ts +143 -0
- package/report/compare.js +205 -0
- package/report/github.d.ts +74 -0
- package/report/github.js +333 -0
- package/report/json.d.ts +4 -0
- package/report/json.js +6 -0
- package/report/markdown.d.ts +25 -0
- package/report/markdown.js +355 -0
- package/report/pretty.d.ts +14 -0
- package/report/pretty.js +324 -0
- package/report/sarif.d.ts +40 -0
- package/report/sarif.js +193 -0
- package/report/view.d.ts +82 -0
- package/report/view.js +132 -0
- package/rules/registry.d.ts +66 -0
- package/rules/registry.js +569 -0
- package/schema/safegres.schema.json +1119 -0
- package/score/score.d.ts +84 -0
- package/score/score.js +238 -0
- package/score/scorecards.d.ts +68 -0
- package/score/scorecards.js +162 -0
- package/types.d.ts +292 -0
- package/types.js +32 -0
- package/version.d.ts +8 -0
- package/version.js +12 -0
- package/LICENSE +0 -23
- package/admin.d.ts +0 -26
- package/admin.js +0 -182
- package/connect.d.ts +0 -19
- package/connect.js +0 -83
- package/dist/README.md +0 -557
- package/dist/package.json +0 -72
- package/esm/admin.js +0 -178
- package/esm/connect.js +0 -78
- package/esm/manager.js +0 -136
- package/esm/roles.js +0 -32
- package/esm/seed/adapters.js +0 -23
- package/esm/seed/csv.js +0 -44
- package/esm/seed/index.js +0 -16
- package/esm/seed/json.js +0 -18
- package/esm/seed/launchql.js +0 -19
- package/esm/seed/sqitch.js +0 -17
- package/esm/stream.js +0 -43
- package/esm/test-client.js +0 -150
- package/manager.d.ts +0 -25
- package/manager.js +0 -140
- package/roles.d.ts +0 -17
- package/roles.js +0 -38
- package/seed/adapters.d.ts +0 -4
- package/seed/adapters.js +0 -28
- package/seed/csv.d.ts +0 -9
- package/seed/csv.js +0 -49
- package/seed/index.d.ts +0 -16
- package/seed/index.js +0 -33
- package/seed/json.d.ts +0 -6
- package/seed/json.js +0 -21
- package/seed/launchql.d.ts +0 -2
- package/seed/launchql.js +0 -22
- package/seed/sqitch.d.ts +0 -2
- package/seed/sqitch.js +0 -20
- package/seed/types.d.ts +0 -13
- package/stream.d.ts +0 -2
- package/stream.js +0 -46
- package/test-client.d.ts +0 -49
- package/test-client.js +0 -154
- /package/{seed → config}/types.js +0 -0
- /package/esm/{seed → config}/types.js +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { ConfigValidationError } from './resolve';
|
|
2
|
+
import { CONFIG_SHAPE } from './schema';
|
|
3
|
+
/**
|
|
4
|
+
* Check a config against the described shape: unknown keys, and values of the
|
|
5
|
+
* wrong kind.
|
|
6
|
+
*
|
|
7
|
+
* A typo'd key used to be *silently ignored*, which for a file that decides
|
|
8
|
+
* whether CI fails is the worst possible outcome — `failon: { grade: 'B' }`
|
|
9
|
+
* reads as a passing build rather than as a mistake. So this rejects rather
|
|
10
|
+
* than warns, and names the key it thinks you meant.
|
|
11
|
+
*
|
|
12
|
+
* Value checks stay shallow on purpose: rule settings, severities and grades
|
|
13
|
+
* are validated by `resolveRules` and by the gate code, which know the rule
|
|
14
|
+
* registry. This is the shape, not the semantics.
|
|
15
|
+
*/
|
|
16
|
+
export function validateConfigShape(config) {
|
|
17
|
+
const problems = [];
|
|
18
|
+
checkObject(config, CONFIG_SHAPE, '', problems, ['$schema', 'extends']);
|
|
19
|
+
if (problems.length === 0)
|
|
20
|
+
return;
|
|
21
|
+
throw new ConfigValidationError(`Invalid safegres configuration:\n${problems.map((p) => ` - ${p}`).join('\n')}`);
|
|
22
|
+
}
|
|
23
|
+
function checkObject(value, properties, path, problems, extraKeys = []) {
|
|
24
|
+
if (!isPlainObject(value))
|
|
25
|
+
return;
|
|
26
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
27
|
+
if (extraKeys.includes(key))
|
|
28
|
+
continue;
|
|
29
|
+
const node = properties[key];
|
|
30
|
+
if (!node) {
|
|
31
|
+
problems.push(`unknown key ${quote(path, key)}${suggestion(key, Object.keys(properties))}`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
checkNode(entry, node, path ? `${path}.${key}` : key, problems);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function checkNode(value, node, path, problems) {
|
|
38
|
+
if (value === undefined || value === null)
|
|
39
|
+
return;
|
|
40
|
+
switch (node.type) {
|
|
41
|
+
case 'any':
|
|
42
|
+
return;
|
|
43
|
+
case 'string':
|
|
44
|
+
if (typeof value !== 'string')
|
|
45
|
+
return void problems.push(wrongType(path, 'a string', value));
|
|
46
|
+
if (node.enum && !node.enum.includes(value)) {
|
|
47
|
+
problems.push(`"${path}" is "${value}"; expected one of ${node.enum.map((v) => `"${v}"`).join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
case 'number':
|
|
51
|
+
if (typeof value !== 'number')
|
|
52
|
+
problems.push(wrongType(path, 'a number', value));
|
|
53
|
+
return;
|
|
54
|
+
case 'boolean':
|
|
55
|
+
if (typeof value !== 'boolean')
|
|
56
|
+
problems.push(wrongType(path, 'a boolean', value));
|
|
57
|
+
return;
|
|
58
|
+
case 'array':
|
|
59
|
+
if (!Array.isArray(value))
|
|
60
|
+
return void problems.push(wrongType(path, 'an array', value));
|
|
61
|
+
value.forEach((item, i) => checkNode(item, node.items, `${path}[${i}]`, problems));
|
|
62
|
+
return;
|
|
63
|
+
case 'object':
|
|
64
|
+
if (!isPlainObject(value))
|
|
65
|
+
return void problems.push(wrongType(path, 'an object', value));
|
|
66
|
+
checkObject(value, node.properties, path, problems);
|
|
67
|
+
return;
|
|
68
|
+
case 'record':
|
|
69
|
+
if (!isPlainObject(value))
|
|
70
|
+
return void problems.push(wrongType(path, 'an object', value));
|
|
71
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
72
|
+
checkNode(entry, node.values, `${path}.${key}`, problems);
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
case 'union': {
|
|
76
|
+
// A union is satisfied by any branch, so only report when every branch
|
|
77
|
+
// rejects — and then report the branch that complained least.
|
|
78
|
+
const attempts = node.of.map((branch) => {
|
|
79
|
+
const branchProblems = [];
|
|
80
|
+
checkNode(value, branch, path, branchProblems);
|
|
81
|
+
return branchProblems;
|
|
82
|
+
});
|
|
83
|
+
if (attempts.some((a) => a.length === 0))
|
|
84
|
+
return;
|
|
85
|
+
const best = attempts.reduce((a, b) => (b.length < a.length ? b : a));
|
|
86
|
+
problems.push(...best);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function wrongType(path, expected, value) {
|
|
91
|
+
return `"${path}" is ${describe(value)}; expected ${expected}`;
|
|
92
|
+
}
|
|
93
|
+
function describe(value) {
|
|
94
|
+
if (Array.isArray(value))
|
|
95
|
+
return 'an array';
|
|
96
|
+
if (value === null)
|
|
97
|
+
return 'null';
|
|
98
|
+
return `a ${typeof value}`;
|
|
99
|
+
}
|
|
100
|
+
function quote(path, key) {
|
|
101
|
+
return `"${path ? `${path}.${key}` : key}"`;
|
|
102
|
+
}
|
|
103
|
+
/** "did you mean" for one edit's worth of typo, which is the common case. */
|
|
104
|
+
function suggestion(key, known) {
|
|
105
|
+
const lower = key.toLowerCase();
|
|
106
|
+
const near = known.find((k) => k.toLowerCase() === lower)
|
|
107
|
+
?? known.find((k) => distance(k.toLowerCase(), lower) <= Math.max(1, Math.floor(key.length / 4)));
|
|
108
|
+
return near ? ` — did you mean "${near}"?` : '';
|
|
109
|
+
}
|
|
110
|
+
function distance(a, b) {
|
|
111
|
+
const rows = [Array.from({ length: b.length + 1 }, (_, j) => j)];
|
|
112
|
+
for (let i = 1; i <= a.length; i++) {
|
|
113
|
+
rows[i] = [i];
|
|
114
|
+
for (let j = 1; j <= b.length; j++) {
|
|
115
|
+
rows[i][j] = Math.min(rows[i - 1][j] + 1, rows[i][j - 1] + 1, rows[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return rows[a.length][b.length];
|
|
119
|
+
}
|
|
120
|
+
function isPlainObject(value) {
|
|
121
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
122
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evaluation corpus: small schemas with a deliberate flaw and a written-down
|
|
3
|
+
* answer.
|
|
4
|
+
*
|
|
5
|
+
* It exists because "the score went up" is not evidence of anything on its own.
|
|
6
|
+
* A corpus with known answers turns safegres into a measuring instrument you
|
|
7
|
+
* can calibrate: every case names the findings a correct audit must produce, so
|
|
8
|
+
* a run can be graded on recall (did it find the flaw?) rather than on a number
|
|
9
|
+
* whose provenance nobody can check. It is used three ways —
|
|
10
|
+
*
|
|
11
|
+
* 1. safegres's own regression suite (`__tests__/corpus.test.ts`);
|
|
12
|
+
* 2. an evaluation harness for an agent asked to *fix* the case: audit,
|
|
13
|
+
* hand the findings over, re-audit, and require the expected findings to
|
|
14
|
+
* be gone without new ones appearing;
|
|
15
|
+
* 3. worked examples — each case is short enough to read.
|
|
16
|
+
*
|
|
17
|
+
* Cases live in `corpus/cases/<id>/` as `schema.sql` plus `case.json`, i.e.
|
|
18
|
+
* data, not code: another tool can consume the corpus without running ours.
|
|
19
|
+
*/
|
|
20
|
+
import type { ExposureConfig } from '../config/types';
|
|
21
|
+
import type { Report, Severity } from '../types';
|
|
22
|
+
/** One expected finding: a rule code, optionally pinned to a relation. */
|
|
23
|
+
export interface ExpectedFinding {
|
|
24
|
+
code: string;
|
|
25
|
+
/** `schema.table`, when the case has more than one relation in play. */
|
|
26
|
+
relation?: string;
|
|
27
|
+
/** Why this is the right answer — the part a reader learns from. */
|
|
28
|
+
note?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CorpusCase {
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
/** Which axis the flaw is on. A case may be graded on both. */
|
|
34
|
+
dimension: 'security' | 'perf';
|
|
35
|
+
/** The SQL that builds the case, as committed. */
|
|
36
|
+
sql: string;
|
|
37
|
+
/** The surface the case is graded against — its whole point, for most cases. */
|
|
38
|
+
exposure: ExposureConfig;
|
|
39
|
+
/** Findings a correct audit must produce. */
|
|
40
|
+
expect: ExpectedFinding[];
|
|
41
|
+
/** Rule codes that must NOT fire: the false positives this case guards. */
|
|
42
|
+
forbid?: string[];
|
|
43
|
+
/** Worst severity the case should produce, as a coarse sanity check. */
|
|
44
|
+
worstSeverity?: Severity;
|
|
45
|
+
/** How the flaw is fixed, in one sentence — the answer key. */
|
|
46
|
+
fix: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The corpus shipped with the package. Two candidates because the package
|
|
50
|
+
* publishes from `dist/`, where the corpus sits one directory closer.
|
|
51
|
+
*/
|
|
52
|
+
export declare function corpusDir(): string;
|
|
53
|
+
/**
|
|
54
|
+
* The SQL creating the roles every case is graded against (`corpus_anon`,
|
|
55
|
+
* `corpus_user`). Idempotent, so a harness can run it before every case.
|
|
56
|
+
*/
|
|
57
|
+
export declare function corpusBootstrap(dir?: string): string;
|
|
58
|
+
/** Load every case in `dir` (default: the shipped corpus), ordered by id. */
|
|
59
|
+
export declare function loadCorpus(dir?: string): CorpusCase[];
|
|
60
|
+
/** Load a single case directory (`case.json` + `schema.sql`). */
|
|
61
|
+
export declare function loadCase(dir: string): CorpusCase;
|
|
62
|
+
export interface CaseResult {
|
|
63
|
+
id: string;
|
|
64
|
+
/** Expected findings the audit produced. */
|
|
65
|
+
found: ExpectedFinding[];
|
|
66
|
+
/** Expected findings the audit missed — recall failures. */
|
|
67
|
+
missed: ExpectedFinding[];
|
|
68
|
+
/** Forbidden rule codes the audit produced — precision failures. */
|
|
69
|
+
falsePositives: string[];
|
|
70
|
+
/** True when nothing was missed and nothing forbidden fired. */
|
|
71
|
+
passed: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Grade a report against the case it was produced from. Deliberately not a
|
|
75
|
+
* strict equality check on the finding set: a case pins the findings that
|
|
76
|
+
* define it, and a later release adding an unrelated advisory should not
|
|
77
|
+
* invalidate the corpus. What a case *does* pin negatively goes in `forbid`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function gradeCase(report: Report, testCase: CorpusCase): CaseResult;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The evaluation corpus: small schemas with a deliberate flaw and a written-down
|
|
3
|
+
* answer.
|
|
4
|
+
*
|
|
5
|
+
* It exists because "the score went up" is not evidence of anything on its own.
|
|
6
|
+
* A corpus with known answers turns safegres into a measuring instrument you
|
|
7
|
+
* can calibrate: every case names the findings a correct audit must produce, so
|
|
8
|
+
* a run can be graded on recall (did it find the flaw?) rather than on a number
|
|
9
|
+
* whose provenance nobody can check. It is used three ways —
|
|
10
|
+
*
|
|
11
|
+
* 1. safegres's own regression suite (`__tests__/corpus.test.ts`);
|
|
12
|
+
* 2. an evaluation harness for an agent asked to *fix* the case: audit,
|
|
13
|
+
* hand the findings over, re-audit, and require the expected findings to
|
|
14
|
+
* be gone without new ones appearing;
|
|
15
|
+
* 3. worked examples — each case is short enough to read.
|
|
16
|
+
*
|
|
17
|
+
* Cases live in `corpus/cases/<id>/` as `schema.sql` plus `case.json`, i.e.
|
|
18
|
+
* data, not code: another tool can consume the corpus without running ours.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'fs';
|
|
21
|
+
import * as path from 'path';
|
|
22
|
+
/**
|
|
23
|
+
* The corpus shipped with the package. Two candidates because the package
|
|
24
|
+
* publishes from `dist/`, where the corpus sits one directory closer.
|
|
25
|
+
*/
|
|
26
|
+
export function corpusDir() {
|
|
27
|
+
const candidates = [
|
|
28
|
+
path.resolve(__dirname, '..', 'corpus', 'cases'),
|
|
29
|
+
path.resolve(__dirname, '..', '..', 'corpus', 'cases')
|
|
30
|
+
];
|
|
31
|
+
const found = candidates.find((dir) => fs.existsSync(dir));
|
|
32
|
+
if (!found)
|
|
33
|
+
throw new Error(`Corpus not found. Looked in: ${candidates.join(', ')}`);
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The SQL creating the roles every case is graded against (`corpus_anon`,
|
|
38
|
+
* `corpus_user`). Idempotent, so a harness can run it before every case.
|
|
39
|
+
*/
|
|
40
|
+
export function corpusBootstrap(dir = corpusDir()) {
|
|
41
|
+
return fs.readFileSync(path.resolve(dir, '..', 'bootstrap.sql'), 'utf8');
|
|
42
|
+
}
|
|
43
|
+
/** Load every case in `dir` (default: the shipped corpus), ordered by id. */
|
|
44
|
+
export function loadCorpus(dir = corpusDir()) {
|
|
45
|
+
return fs
|
|
46
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
47
|
+
.filter((e) => e.isDirectory())
|
|
48
|
+
.map((e) => loadCase(path.join(dir, e.name)))
|
|
49
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
50
|
+
}
|
|
51
|
+
/** Load a single case directory (`case.json` + `schema.sql`). */
|
|
52
|
+
export function loadCase(dir) {
|
|
53
|
+
const meta = JSON.parse(fs.readFileSync(path.join(dir, 'case.json'), 'utf8'));
|
|
54
|
+
return {
|
|
55
|
+
...meta,
|
|
56
|
+
id: meta.id ?? path.basename(dir),
|
|
57
|
+
sql: fs.readFileSync(path.join(dir, 'schema.sql'), 'utf8')
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function matches(finding, expected) {
|
|
61
|
+
if (finding.code !== expected.code)
|
|
62
|
+
return false;
|
|
63
|
+
if (!expected.relation)
|
|
64
|
+
return true;
|
|
65
|
+
return `${finding.schema}.${finding.table}` === expected.relation;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Grade a report against the case it was produced from. Deliberately not a
|
|
69
|
+
* strict equality check on the finding set: a case pins the findings that
|
|
70
|
+
* define it, and a later release adding an unrelated advisory should not
|
|
71
|
+
* invalidate the corpus. What a case *does* pin negatively goes in `forbid`.
|
|
72
|
+
*/
|
|
73
|
+
export function gradeCase(report, testCase) {
|
|
74
|
+
const findings = report.findings;
|
|
75
|
+
const found = testCase.expect.filter((e) => findings.some((f) => matches(f, e)));
|
|
76
|
+
const missed = testCase.expect.filter((e) => !findings.some((f) => matches(f, e)));
|
|
77
|
+
const falsePositives = [...new Set(findings.map((f) => f.code))].filter((code) => (testCase.forbid ?? []).includes(code));
|
|
78
|
+
return {
|
|
79
|
+
id: testCase.id,
|
|
80
|
+
found,
|
|
81
|
+
missed,
|
|
82
|
+
falsePositives,
|
|
83
|
+
passed: missed.length === 0 && falsePositives.length === 0
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exposure adapters: how safegres learns what a stack exposes.
|
|
3
|
+
*
|
|
4
|
+
* An adapter is a value, not a module name. Built-ins are named exports of
|
|
5
|
+
* this module, a custom one is an object you construct in your own repo, and
|
|
6
|
+
* both are passed the same way — nothing is resolved by package name, and
|
|
7
|
+
* there is no plugin loader to reason about:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { constructiveAdapter, definePlanes } from 'safegres/adapters';
|
|
11
|
+
*
|
|
12
|
+
* export default defineConfig({
|
|
13
|
+
* exposure: { adapters: [constructiveAdapter, myAdapter], schemas: ['app_public'] }
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* `detect()` answers "is this stack present in this database?" and `resolve()`
|
|
18
|
+
* returns the planes it exposes — one per API where the stack has more than
|
|
19
|
+
* one, because "the admin API grades A and the public API grades C" is
|
|
20
|
+
* strictly more useful than their union.
|
|
21
|
+
*/
|
|
22
|
+
import type { PlaneKind } from '../config/types';
|
|
23
|
+
import type { QueryExecutor } from '../pg/introspect';
|
|
24
|
+
import type { ApiReach } from './reach';
|
|
25
|
+
/** A plane as an adapter reports it, before roles are resolved against the catalog. */
|
|
26
|
+
export interface PlaneInput {
|
|
27
|
+
name: string;
|
|
28
|
+
kind?: PlaneKind;
|
|
29
|
+
primary?: boolean;
|
|
30
|
+
schemas?: string[];
|
|
31
|
+
/** Every role that reaches this plane, anonymous ones included. */
|
|
32
|
+
roles?: string[];
|
|
33
|
+
/**
|
|
34
|
+
* The subset of `roles` an *unauthenticated* caller arrives as. Every stack
|
|
35
|
+
* knows which one this is — Constructive's `apis.anon_role`, PostgREST's
|
|
36
|
+
* `pgrst.db_anon_role`, Supabase's `anon`, graphile's visitor — and the
|
|
37
|
+
* distinction is the difference between "a signed-in user can write this"
|
|
38
|
+
* (usually the point) and "anyone on the internet can" (usually the bug).
|
|
39
|
+
*/
|
|
40
|
+
anonRoles?: string[];
|
|
41
|
+
}
|
|
42
|
+
/** What an adapter is asked to compute reach for. */
|
|
43
|
+
export interface ReachContext {
|
|
44
|
+
/** Schemas on the plane. Empty means "the whole database". */
|
|
45
|
+
schemas: string[];
|
|
46
|
+
excludeSchemas?: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ExposureAdapter {
|
|
49
|
+
/** Stable identifier, reported as the exposure `source`. */
|
|
50
|
+
name: string;
|
|
51
|
+
/** True when this stack is present in the connected database. */
|
|
52
|
+
detect(exec: QueryExecutor): Promise<boolean>;
|
|
53
|
+
/** The planes this stack exposes. An empty array means "present, exposes nothing". */
|
|
54
|
+
resolve(exec: QueryExecutor): Promise<PlaneInput[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Optional relation-level precision *within* a plane's schemas: which
|
|
57
|
+
* relations the stack's generated API cannot address at all.
|
|
58
|
+
*
|
|
59
|
+
* Separate from `resolve` because it answers a different question and most
|
|
60
|
+
* adapters cannot answer it. An adapter that knows the schemas but not the
|
|
61
|
+
* fields simply omits this, and the plane stays schema-granular.
|
|
62
|
+
*/
|
|
63
|
+
reach?(exec: QueryExecutor, context: ReachContext): Promise<ApiReach>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Constructive routing-plane introspection: an API exposes a set of schemas
|
|
67
|
+
* via `routing_public.apis` → `routing_public.api_schemas` →
|
|
68
|
+
* `metaschema_public.schema` (and the platform plane via `platform_apis` →
|
|
69
|
+
* `platform_api_schemas`). API-edge roles come from `apis.role_name` /
|
|
70
|
+
* `apis.anon_role`.
|
|
71
|
+
*
|
|
72
|
+
* Emits one `api` plane per API, plus a primary plane unioning them: the union
|
|
73
|
+
* is what the headline score has always been computed against, and the
|
|
74
|
+
* per-API planes are what let a reader see which API carries the debt.
|
|
75
|
+
*/
|
|
76
|
+
export declare const constructiveAdapter: ExposureAdapter;
|
|
77
|
+
/**
|
|
78
|
+
* PostGraphile behaviors as relation-level reach.
|
|
79
|
+
*
|
|
80
|
+
* Deliberately *not* folded into {@link constructiveAdapter}, even though
|
|
81
|
+
* Constructive is a PostGraphile stack: behaviors are a Graphile convention
|
|
82
|
+
* that any Graphile database follows, and each adapter should say one true
|
|
83
|
+
* thing. This one contributes no planes — it has no idea which schemas an API
|
|
84
|
+
* serves — and only narrows the planes another adapter, or the config, already
|
|
85
|
+
* established.
|
|
86
|
+
*/
|
|
87
|
+
export declare const postgraphileAdapter: ExposureAdapter;
|
|
88
|
+
/**
|
|
89
|
+
* PostgREST exposure, read from the catalog rather than inferred from a
|
|
90
|
+
* schema name: PostgREST serves exactly `pgrst.db_schemas`, which is set as a
|
|
91
|
+
* role or database GUC (`ALTER ROLE authenticator SET pgrst.db_schemas = …`)
|
|
92
|
+
* and therefore lands in `pg_db_role_setting`. `pgrst.db_anon_role` names the
|
|
93
|
+
* role an unauthenticated request runs as, and the connecting role
|
|
94
|
+
* (`authenticator` by convention) is the one that can `SET ROLE` to it.
|
|
95
|
+
*
|
|
96
|
+
* Supabase is PostgREST underneath, so this covers it too; the difference is
|
|
97
|
+
* the role vocabulary, which the `supabase` preset supplies.
|
|
98
|
+
*/
|
|
99
|
+
export declare const postgrestAdapter: ExposureAdapter;
|
|
100
|
+
/**
|
|
101
|
+
* Supabase runs PostgREST, but configures it *outside* the database — the
|
|
102
|
+
* schema list is a platform setting, so `pgrst.db_schemas` is usually absent
|
|
103
|
+
* and `postgrestAdapter` correctly resolves nothing. Hence a separate
|
|
104
|
+
* adapter: it prefers the GUCs when a self-hosted stack sets them, and only
|
|
105
|
+
* falls back to the platform's fixed surface once it has *proved* it is
|
|
106
|
+
* looking at Supabase — `auth.users` plus the three roles every project has.
|
|
107
|
+
*
|
|
108
|
+
* The fallback is deliberately confined here. `postgrestAdapter` never
|
|
109
|
+
* guesses: an unconfigured PostgREST resolves no planes, which surfaces as
|
|
110
|
+
* unknown exposure (a capped score and a W1) rather than a wrong surface
|
|
111
|
+
* presented as fact.
|
|
112
|
+
*/
|
|
113
|
+
export declare const supabaseAdapter: ExposureAdapter;
|
|
114
|
+
/**
|
|
115
|
+
* Hasura reads its exposed surface out of its own metadata: v2+ keeps one
|
|
116
|
+
* JSON document in `hdb_catalog.hdb_metadata`, older versions a row per
|
|
117
|
+
* tracked table in `hdb_catalog.hdb_table`. Only *tracked* tables are served,
|
|
118
|
+
* so the schemas that contain them are the surface.
|
|
119
|
+
*/
|
|
120
|
+
export declare const hasuraAdapter: ExposureAdapter;
|
|
121
|
+
/**
|
|
122
|
+
* PostGraphile publishes whatever schemas it was started with — a CLI/library
|
|
123
|
+
* argument, invisible from inside the database. So this adapter resolves the
|
|
124
|
+
* `graphile-starter` layout (`app_public` served, `app_hidden`/`app_private`
|
|
125
|
+
* not) and nothing else.
|
|
126
|
+
*
|
|
127
|
+
* That is naming-as-intent, which safegres otherwise refuses. The difference
|
|
128
|
+
* is consent: listing this adapter *is* the declaration that the convention
|
|
129
|
+
* holds here. When it doesn't, list `exposure.schemas` instead — explicit
|
|
130
|
+
* always wins.
|
|
131
|
+
*
|
|
132
|
+
* Reach is a separate question — *which schemas are served* versus *which
|
|
133
|
+
* relations the served schemas expose* — and is delegated to
|
|
134
|
+
* {@link postgraphileAdapter}, which answers it for any Graphile stack
|
|
135
|
+
* regardless of schema layout.
|
|
136
|
+
*/
|
|
137
|
+
export declare const graphileAdapter: ExposureAdapter;
|
|
138
|
+
/** Every adapter a config may name with a string. */
|
|
139
|
+
export declare const BUILTIN_ADAPTERS: Record<string, ExposureAdapter>;
|
|
140
|
+
/**
|
|
141
|
+
* Wrap a fixed set of planes as an adapter — the escape hatch for a surface
|
|
142
|
+
* you know but cannot introspect (a schema list your deployment tooling
|
|
143
|
+
* knows, an API gateway's config read at build time).
|
|
144
|
+
*/
|
|
145
|
+
export declare function definePlanes(name: string, planes: PlaneInput[]): ExposureAdapter;
|
|
146
|
+
/**
|
|
147
|
+
* Coerce whatever a config carried in `exposure.adapters` into adapters.
|
|
148
|
+
* Strings resolve against the built-in table only — an unknown name is an
|
|
149
|
+
* error rather than a silent no-op, because a typo'd adapter name would
|
|
150
|
+
* otherwise present as an unexposed database.
|
|
151
|
+
*/
|
|
152
|
+
export declare function resolveAdapters(entries: Array<string | ExposureAdapter> | undefined): ExposureAdapter[];
|