@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
package/types.d.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report types for the safegres audit.
|
|
3
|
+
*
|
|
4
|
+
* Kept intentionally minimal and dependency-free so they can be imported
|
|
5
|
+
* by downstream packages (e.g. `@constructive-db/rls-audit-constructive`)
|
|
6
|
+
* without pulling in `pg` or `pgsql-parser`.
|
|
7
|
+
*/
|
|
8
|
+
export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
9
|
+
/**
|
|
10
|
+
* Which way a finding fails:
|
|
11
|
+
* - `fail-open` — the untrusted side can read/write more than intended (a leak).
|
|
12
|
+
* - `fail-closed` — the operation is denied at runtime; an availability/hygiene
|
|
13
|
+
* concern, not an exposure. Excluded from the score by default.
|
|
14
|
+
* - `neutral` — directionless (performance, meta).
|
|
15
|
+
*/
|
|
16
|
+
export type Direction = 'fail-open' | 'fail-closed' | 'neutral';
|
|
17
|
+
/**
|
|
18
|
+
* Which axis a finding is scored on. `security` findings drive `report.score`;
|
|
19
|
+
* `perf` findings drive `report.perf.score`. The two are never mixed — a
|
|
20
|
+
* database can be an A+ on security and a D on index hygiene, and both
|
|
21
|
+
* numbers stay meaningful.
|
|
22
|
+
*/
|
|
23
|
+
export type Dimension = 'security' | 'perf';
|
|
24
|
+
export declare const SEVERITY_ORDER: Record<Severity, number>;
|
|
25
|
+
export interface Finding {
|
|
26
|
+
/** Finding code, e.g. `A1`, `P7`. Stable across versions. */
|
|
27
|
+
code: string;
|
|
28
|
+
severity: Severity;
|
|
29
|
+
/** High-level bucket — helps renderers group findings. */
|
|
30
|
+
category: 'flags' | 'coverage' | 'anti-pattern' | 'index' | 'sync' | 'match' | 'meta' | 'convention';
|
|
31
|
+
/** Leak vs deny vs directionless. Stamped from the rule registry. */
|
|
32
|
+
direction?: Direction;
|
|
33
|
+
/** Scoring axis. Stamped from the rule registry; defaults to `security`. */
|
|
34
|
+
dimension?: Dimension;
|
|
35
|
+
/**
|
|
36
|
+
* Whether the finding's table is on the resolved exposure surface — i.e.
|
|
37
|
+
* reachable on the *primary* plane. `undefined` when no exposure surface is
|
|
38
|
+
* known (everything is assumed reachable).
|
|
39
|
+
*/
|
|
40
|
+
exposed?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Every access plane the finding is reachable on, by name. A relation that
|
|
43
|
+
* is internal to the API can still be reachable by a role holding a direct
|
|
44
|
+
* connection, and this is where that shows up. Not part of a finding's
|
|
45
|
+
* identity: baselines and comparisons key on the finding, not on who can
|
|
46
|
+
* reach it.
|
|
47
|
+
*/
|
|
48
|
+
planes?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* The finding is acknowledged by config as intentional (e.g. an open read
|
|
51
|
+
* on a table declared in `public.read`) — reported, but excluded from the
|
|
52
|
+
* score.
|
|
53
|
+
*/
|
|
54
|
+
acknowledged?: boolean;
|
|
55
|
+
/** Schema-qualified location, where applicable. */
|
|
56
|
+
schema?: string;
|
|
57
|
+
table?: string;
|
|
58
|
+
policy?: string;
|
|
59
|
+
role?: string;
|
|
60
|
+
privilege?: string;
|
|
61
|
+
/** Human-readable summary. */
|
|
62
|
+
message: string;
|
|
63
|
+
/** Optional remediation hint / pointer to docs. */
|
|
64
|
+
hint?: string;
|
|
65
|
+
/** Optional machine-readable extras (AST nodes, offending function name, …). */
|
|
66
|
+
context?: Record<string, unknown>;
|
|
67
|
+
/**
|
|
68
|
+
* Proof attached by `--explain`: the plan the database produced for the
|
|
69
|
+
* query shape this finding is a claim about.
|
|
70
|
+
*/
|
|
71
|
+
evidence?: FindingEvidence;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Planner evidence for a finding. `refuted` means the planner disagreed with
|
|
75
|
+
* the catalog inference — the finding is reported but no longer scored.
|
|
76
|
+
*/
|
|
77
|
+
export interface FindingEvidence {
|
|
78
|
+
source: 'explain';
|
|
79
|
+
status: 'confirmed' | 'refuted' | 'inconclusive';
|
|
80
|
+
/** The probe query, with parameters left unbound. */
|
|
81
|
+
probe: string;
|
|
82
|
+
/** Plan node types, outermost first. */
|
|
83
|
+
plan: string;
|
|
84
|
+
/** Why an inconclusive probe was inconclusive. */
|
|
85
|
+
note?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface Summary {
|
|
88
|
+
critical: number;
|
|
89
|
+
high: number;
|
|
90
|
+
medium: number;
|
|
91
|
+
low: number;
|
|
92
|
+
info: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* One graded access plane: a way into the database, with its own score.
|
|
96
|
+
*
|
|
97
|
+
* The primary plane is the declared API surface, and its score *is*
|
|
98
|
+
* `report.score` — secondary planes never move it. They answer the question
|
|
99
|
+
* the headline cannot: what does this database grade for somebody who does
|
|
100
|
+
* not come through the API?
|
|
101
|
+
*/
|
|
102
|
+
export interface PlaneReport {
|
|
103
|
+
name: string;
|
|
104
|
+
kind: 'api' | 'role' | 'schema';
|
|
105
|
+
/** The headline plane. Exactly one plane is primary. */
|
|
106
|
+
primary: boolean;
|
|
107
|
+
/** Adapter name, `config`, or `none`. */
|
|
108
|
+
source: string;
|
|
109
|
+
schemas: string[];
|
|
110
|
+
roles?: string[];
|
|
111
|
+
/** Relations the plane reaches (the density denominator). */
|
|
112
|
+
exposedTables: number;
|
|
113
|
+
/**
|
|
114
|
+
* Relations in the plane's schemas its API cannot address, and which are
|
|
115
|
+
* therefore excluded from `exposedTables`.
|
|
116
|
+
*/
|
|
117
|
+
unaddressableTables?: number;
|
|
118
|
+
/** Role planes: the most direct way the reach arrives. */
|
|
119
|
+
reachedVia?: 'grant' | 'PUBLIC' | 'inheritance';
|
|
120
|
+
/** Security score for this plane, same model as the headline. */
|
|
121
|
+
score: import('./score/score').Score;
|
|
122
|
+
/** Severity counts for the findings reachable on this plane. */
|
|
123
|
+
summary: Summary;
|
|
124
|
+
/** Present when the plane was reported but deliberately not graded. */
|
|
125
|
+
skipped?: string;
|
|
126
|
+
}
|
|
127
|
+
/** The resolved exposure surface an audit was scored against. */
|
|
128
|
+
export interface ExposureReport {
|
|
129
|
+
/** True when a surface was configured or auto-resolved. */
|
|
130
|
+
known: boolean;
|
|
131
|
+
/** Where the surface came from: an adapter name, `config`, or `none`. */
|
|
132
|
+
source: string;
|
|
133
|
+
/** Name of the primary plane. */
|
|
134
|
+
plane?: string;
|
|
135
|
+
/** Schemas reachable from the exposed APIs. Empty when unknown. */
|
|
136
|
+
schemas: string[];
|
|
137
|
+
/** API-edge roles, when the resolver can discover them. */
|
|
138
|
+
roles?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* The subset of `roles` an unauthenticated caller arrives as — the answer to
|
|
141
|
+
* "what can someone with no credentials reach?". Omitted when none resolve.
|
|
142
|
+
*/
|
|
143
|
+
anonRoles?: string[];
|
|
144
|
+
/** Tables on the exposed surface (the score denominator). */
|
|
145
|
+
exposedTables: number;
|
|
146
|
+
/** All tables the audit introspected. */
|
|
147
|
+
totalTables: number;
|
|
148
|
+
/**
|
|
149
|
+
* Relations in the exposed schemas the generated API cannot address, and
|
|
150
|
+
* which are therefore excluded from `exposedTables`. Present only when an
|
|
151
|
+
* adapter could prove it; listed rather than counted, because a subtraction
|
|
152
|
+
* from the score denominator should be readable.
|
|
153
|
+
*/
|
|
154
|
+
unaddressable?: import('./exposure/reach').UnreachableRelation[];
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The optional performance dimension (`--perf`): index-hygiene and
|
|
158
|
+
* policy-cost findings, scored on their own 0-100 axis against the same
|
|
159
|
+
* exposure surface.
|
|
160
|
+
*/
|
|
161
|
+
export interface PerfReport {
|
|
162
|
+
/** Perf-dimension findings (also present in `report.findings`). */
|
|
163
|
+
findings: Finding[];
|
|
164
|
+
summary: Summary;
|
|
165
|
+
/** Perf score — computed only over perf-dimension findings. */
|
|
166
|
+
score: import('./score/score').Score;
|
|
167
|
+
/**
|
|
168
|
+
* Diff against a committed perf baseline (`--perf-baseline`): which findings
|
|
169
|
+
* are new debt, which were fixed, which are accepted.
|
|
170
|
+
*/
|
|
171
|
+
diff?: import('./perf/baseline').PerfDiff;
|
|
172
|
+
/** Runtime-statistics provenance, present when the audit ran with `--stats`. */
|
|
173
|
+
stats?: PerfStatsReport;
|
|
174
|
+
/**
|
|
175
|
+
* Access-path classification: how many foreign keys X1 was not applied to,
|
|
176
|
+
* because nothing reads them. Reported so a suppression this broad is never
|
|
177
|
+
* silent.
|
|
178
|
+
*/
|
|
179
|
+
paths?: PerfPathsReport;
|
|
180
|
+
/** Planner-proof summary, present when the audit ran with `--explain`. */
|
|
181
|
+
explain?: import('./perf/explain').ExplainReport;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* What the access-path signals found, and what X1 did about it. Reported so
|
|
185
|
+
* the evidence is visible even when — as by default — it changes nothing.
|
|
186
|
+
*/
|
|
187
|
+
export interface PerfPathsReport {
|
|
188
|
+
/** Foreign keys examined. */
|
|
189
|
+
total: number;
|
|
190
|
+
/** Keys with a `read` signal: an RLS policy or a view names the column. */
|
|
191
|
+
read: number;
|
|
192
|
+
/** Keys whose only signals are shape: they look like provisioning pointers. */
|
|
193
|
+
writeOnceShaped: number;
|
|
194
|
+
/** Tables carrying enough write-once pointers to look like config records. */
|
|
195
|
+
tables: number;
|
|
196
|
+
/** What X1 did with the write-once-shaped keys. */
|
|
197
|
+
onWriteOncePointer: 'report' | 'demote' | 'suppress';
|
|
198
|
+
/**
|
|
199
|
+
* Keys whose reverse relation an API behavior declares absent. Reported
|
|
200
|
+
* only: one missing path is not proof that nothing traverses the key.
|
|
201
|
+
*/
|
|
202
|
+
declaredHidden?: number;
|
|
203
|
+
}
|
|
204
|
+
/** Where the `S*` findings' numbers came from, and how much to trust them. */
|
|
205
|
+
export interface PerfStatsReport {
|
|
206
|
+
source: 'live';
|
|
207
|
+
/** Tables whose cumulative statistics were read. */
|
|
208
|
+
tables: number;
|
|
209
|
+
/** When the counters were last reset — the window the numbers describe. */
|
|
210
|
+
statsReset: string | null;
|
|
211
|
+
/** Whether `S*` findings counted toward the perf score. */
|
|
212
|
+
scored: boolean;
|
|
213
|
+
/** Non-fatal gaps, e.g. `pg_stat_statements` not installed. */
|
|
214
|
+
notes?: string[];
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The per-role exposure report: the direct answer to "what can role X
|
|
218
|
+
* access?", computed over effective grants (direct, TO PUBLIC, inherited)
|
|
219
|
+
* for the configured untrusted roles. Present whenever such roles are
|
|
220
|
+
* configured (e.g. L5/R1 options), independent of any findings.
|
|
221
|
+
*/
|
|
222
|
+
export interface RoleAccessReport {
|
|
223
|
+
roles: import('./checks/lattice').RoleAccessEntry[];
|
|
224
|
+
}
|
|
225
|
+
export interface Report {
|
|
226
|
+
version: string;
|
|
227
|
+
generatedAt: string;
|
|
228
|
+
/**
|
|
229
|
+
* What ruler this score was measured with: a fingerprint of the resolved
|
|
230
|
+
* configuration, and whether the run refused local config entirely. Two
|
|
231
|
+
* reports are comparable when their fingerprints match.
|
|
232
|
+
*/
|
|
233
|
+
provenance?: import('./config/fingerprint').Provenance;
|
|
234
|
+
summary: Summary;
|
|
235
|
+
findings: Finding[];
|
|
236
|
+
/** Config-driven audit score (weighted deductions, 0-100 + grade). */
|
|
237
|
+
score?: import('./score/score').Score;
|
|
238
|
+
/** Performance dimension, present when the audit ran with `perf` enabled. */
|
|
239
|
+
perf?: PerfReport;
|
|
240
|
+
/** The exposure surface the score was computed against. */
|
|
241
|
+
exposure?: ExposureReport;
|
|
242
|
+
/**
|
|
243
|
+
* Every graded access plane, primary first. `planes[0].score` is
|
|
244
|
+
* `report.score`; the rest are advisory unless `failOn.planes` opts them
|
|
245
|
+
* into gating.
|
|
246
|
+
*/
|
|
247
|
+
planes?: PlaneReport[];
|
|
248
|
+
/**
|
|
249
|
+
* Named scores over slices of the same findings (`scorecards` config), the
|
|
250
|
+
* reserved `default` and `raw` cards first. Different teams gate on
|
|
251
|
+
* different questions; this is where each one's answer lives, computed
|
|
252
|
+
* from the one set of findings so they can never disagree about the facts.
|
|
253
|
+
*/
|
|
254
|
+
scorecards?: import('./score/scorecards').ScorecardReport[];
|
|
255
|
+
/** Effective per-role access, for the configured untrusted roles. */
|
|
256
|
+
roleAccess?: RoleAccessReport;
|
|
257
|
+
/**
|
|
258
|
+
* L21's `granted − reachable` result: per role, the EXECUTE grants that are
|
|
259
|
+
* revocable, the ones retained (each with the reachability path that proves
|
|
260
|
+
* it load-bearing), and the ones suppressed because the closure could not be
|
|
261
|
+
* fully read. The retained-and-suppressed lists are the point of the rule —
|
|
262
|
+
* they are what a human reviews before dropping anything.
|
|
263
|
+
*/
|
|
264
|
+
revocableGrants?: import('./checks/revocable-grants').RevocableGrantsReport;
|
|
265
|
+
/**
|
|
266
|
+
* Unscored call-graph audit (`--call-graph`): trust boundaries reachable
|
|
267
|
+
* from the exposed entry points, for human review.
|
|
268
|
+
*/
|
|
269
|
+
callGraph?: import('./callgraph/graph').CallGraphReport;
|
|
270
|
+
/**
|
|
271
|
+
* Diff against a committed call-graph baseline (`--baseline`): trust
|
|
272
|
+
* boundaries added since the snapshot (require sign-off) and boundaries
|
|
273
|
+
* that were resolved.
|
|
274
|
+
*/
|
|
275
|
+
callGraphDiff?: import('./callgraph/baseline').CallGraphDiff;
|
|
276
|
+
/**
|
|
277
|
+
* Movement against a previous run (`--compare`): score deltas, severity
|
|
278
|
+
* deltas and the rules that changed. A report describes a database; this is
|
|
279
|
+
* the only part that describes a change to one.
|
|
280
|
+
*/
|
|
281
|
+
comparison?: import('./report/compare').ReportComparison;
|
|
282
|
+
/**
|
|
283
|
+
* Why there is no `comparison` (`--compare-skipped`): a baseline was looked
|
|
284
|
+
* for and none qualified. Silence would read as "nothing moved", which is
|
|
285
|
+
* how a delta nobody could see went wrong unnoticed; the absolute score and
|
|
286
|
+
* the perf ratchet still gate the run, and this line says so.
|
|
287
|
+
*/
|
|
288
|
+
comparisonSkipped?: string;
|
|
289
|
+
}
|
|
290
|
+
export declare function newSummary(): Summary;
|
|
291
|
+
export declare function summarize(findings: Finding[]): Summary;
|
|
292
|
+
export declare function meetsThreshold(sev: Severity, threshold: Severity): boolean;
|
package/types.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Report types for the safegres audit.
|
|
4
|
+
*
|
|
5
|
+
* Kept intentionally minimal and dependency-free so they can be imported
|
|
6
|
+
* by downstream packages (e.g. `@constructive-db/rls-audit-constructive`)
|
|
7
|
+
* without pulling in `pg` or `pgsql-parser`.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SEVERITY_ORDER = void 0;
|
|
11
|
+
exports.newSummary = newSummary;
|
|
12
|
+
exports.summarize = summarize;
|
|
13
|
+
exports.meetsThreshold = meetsThreshold;
|
|
14
|
+
exports.SEVERITY_ORDER = {
|
|
15
|
+
critical: 4,
|
|
16
|
+
high: 3,
|
|
17
|
+
medium: 2,
|
|
18
|
+
low: 1,
|
|
19
|
+
info: 0
|
|
20
|
+
};
|
|
21
|
+
function newSummary() {
|
|
22
|
+
return { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
23
|
+
}
|
|
24
|
+
function summarize(findings) {
|
|
25
|
+
const s = newSummary();
|
|
26
|
+
for (const f of findings)
|
|
27
|
+
s[f.severity] += 1;
|
|
28
|
+
return s;
|
|
29
|
+
}
|
|
30
|
+
function meetsThreshold(sev, threshold) {
|
|
31
|
+
return exports.SEVERITY_ORDER[sev] >= exports.SEVERITY_ORDER[threshold];
|
|
32
|
+
}
|
package/version.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The analyzer version stamped into every report and into the SARIF tool
|
|
3
|
+
* record. Read from package.json the same way the CLI reads it, rather than
|
|
4
|
+
* held in a generated constant: a constant only stays true if a sync step runs
|
|
5
|
+
* on the same commit lerna bumps the manifest, and it drifted (1.16.1 against a
|
|
6
|
+
* 1.18.0 manifest) precisely because it doesn't.
|
|
7
|
+
*/
|
|
8
|
+
export declare const version: string;
|
package/version.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.version = void 0;
|
|
4
|
+
const utils_1 = require("@inquirerer/utils");
|
|
5
|
+
/**
|
|
6
|
+
* The analyzer version stamped into every report and into the SARIF tool
|
|
7
|
+
* record. Read from package.json the same way the CLI reads it, rather than
|
|
8
|
+
* held in a generated constant: a constant only stays true if a sync step runs
|
|
9
|
+
* on the same commit lerna bumps the manifest, and it drifted (1.16.1 against a
|
|
10
|
+
* 1.18.0 manifest) precisely because it doesn't.
|
|
11
|
+
*/
|
|
12
|
+
exports.version = (0, utils_1.getPackageVersion)(__dirname);
|
package/LICENSE
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
|
|
4
|
-
Copyright (c) 2025 Hyperweb <developers@hyperweb.io>
|
|
5
|
-
Copyright (c) 2020-present, Interweb, Inc.
|
|
6
|
-
|
|
7
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
in the Software without restriction, including without limitation the rights
|
|
10
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
furnished to do so, subject to the following conditions:
|
|
13
|
-
|
|
14
|
-
The above copyright notice and this permission notice shall be included in all
|
|
15
|
-
copies or substantial portions of the Software.
|
|
16
|
-
|
|
17
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
-
SOFTWARE.
|
package/admin.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { PgTestConnectionOptions } from '@launchql/types';
|
|
2
|
-
import { PgConfig } from 'pg-env';
|
|
3
|
-
import { SeedAdapter } from './seed/types';
|
|
4
|
-
export declare class DbAdmin {
|
|
5
|
-
private config;
|
|
6
|
-
private verbose;
|
|
7
|
-
private roleConfig?;
|
|
8
|
-
constructor(config: PgConfig, verbose?: boolean, roleConfig?: PgTestConnectionOptions);
|
|
9
|
-
private getEnv;
|
|
10
|
-
private run;
|
|
11
|
-
private safeDropDb;
|
|
12
|
-
drop(dbName?: string): void;
|
|
13
|
-
dropTemplate(dbName: string): void;
|
|
14
|
-
create(dbName?: string): void;
|
|
15
|
-
createFromTemplate(template: string, dbName?: string): void;
|
|
16
|
-
installExtensions(extensions: string[] | string, dbName?: string): void;
|
|
17
|
-
connectionString(dbName?: string): string;
|
|
18
|
-
createTemplateFromBase(base: string, template: string): void;
|
|
19
|
-
cleanupTemplate(template: string): void;
|
|
20
|
-
grantRole(role: string, user: string, dbName?: string): Promise<void>;
|
|
21
|
-
grantConnect(role: string, dbName?: string): Promise<void>;
|
|
22
|
-
createUserRole(user: string, password: string, dbName: string): Promise<void>;
|
|
23
|
-
loadSql(file: string, dbName: string): void;
|
|
24
|
-
streamSql(sql: string, dbName: string): Promise<void>;
|
|
25
|
-
createSeededTemplate(templateName: string, adapter: SeedAdapter): Promise<void>;
|
|
26
|
-
}
|
package/admin.js
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DbAdmin = void 0;
|
|
4
|
-
const logger_1 = require("@launchql/logger");
|
|
5
|
-
const child_process_1 = require("child_process");
|
|
6
|
-
const fs_1 = require("fs");
|
|
7
|
-
const pg_env_1 = require("pg-env");
|
|
8
|
-
const roles_1 = require("./roles");
|
|
9
|
-
const stream_1 = require("./stream");
|
|
10
|
-
const log = new logger_1.Logger('db-admin');
|
|
11
|
-
class DbAdmin {
|
|
12
|
-
config;
|
|
13
|
-
verbose;
|
|
14
|
-
roleConfig;
|
|
15
|
-
constructor(config, verbose = false, roleConfig) {
|
|
16
|
-
this.config = config;
|
|
17
|
-
this.verbose = verbose;
|
|
18
|
-
this.roleConfig = roleConfig;
|
|
19
|
-
this.config = (0, pg_env_1.getPgEnvOptions)(config);
|
|
20
|
-
}
|
|
21
|
-
getEnv() {
|
|
22
|
-
return {
|
|
23
|
-
PGHOST: this.config.host,
|
|
24
|
-
PGPORT: String(this.config.port),
|
|
25
|
-
PGUSER: this.config.user,
|
|
26
|
-
PGPASSWORD: this.config.password
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
run(command) {
|
|
30
|
-
try {
|
|
31
|
-
(0, child_process_1.execSync)(command, {
|
|
32
|
-
stdio: this.verbose ? 'inherit' : 'pipe',
|
|
33
|
-
env: {
|
|
34
|
-
...process.env,
|
|
35
|
-
...this.getEnv()
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
if (this.verbose)
|
|
39
|
-
log.success(`Executed: ${command}`);
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
log.error(`Command failed: ${command}`);
|
|
43
|
-
if (this.verbose)
|
|
44
|
-
log.error(err.message);
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
safeDropDb(name) {
|
|
49
|
-
try {
|
|
50
|
-
this.run(`dropdb "${name}"`);
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
if (!err.message.includes('does not exist')) {
|
|
54
|
-
log.warn(`Could not drop database ${name}: ${err.message}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
drop(dbName) {
|
|
59
|
-
this.safeDropDb(dbName ?? this.config.database);
|
|
60
|
-
}
|
|
61
|
-
dropTemplate(dbName) {
|
|
62
|
-
this.run(`psql -c "UPDATE pg_database SET datistemplate='false' WHERE datname='${dbName}';"`);
|
|
63
|
-
this.drop(dbName);
|
|
64
|
-
}
|
|
65
|
-
create(dbName) {
|
|
66
|
-
const db = dbName ?? this.config.database;
|
|
67
|
-
this.run(`createdb -U ${this.config.user} -h ${this.config.host} -p ${this.config.port} "${db}"`);
|
|
68
|
-
}
|
|
69
|
-
createFromTemplate(template, dbName) {
|
|
70
|
-
const db = dbName ?? this.config.database;
|
|
71
|
-
this.run(`createdb -U ${this.config.user} -h ${this.config.host} -p ${this.config.port} -e "${db}" -T "${template}"`);
|
|
72
|
-
}
|
|
73
|
-
installExtensions(extensions, dbName) {
|
|
74
|
-
const db = dbName ?? this.config.database;
|
|
75
|
-
const extList = typeof extensions === 'string' ? extensions.split(',') : extensions;
|
|
76
|
-
for (const extension of extList) {
|
|
77
|
-
this.run(`psql --dbname "${db}" -c 'CREATE EXTENSION IF NOT EXISTS "${extension}" CASCADE;'`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
connectionString(dbName) {
|
|
81
|
-
const { user, password, host, port } = this.config;
|
|
82
|
-
const db = dbName ?? this.config.database;
|
|
83
|
-
return `postgres://${user}:${password}@${host}:${port}/${db}`;
|
|
84
|
-
}
|
|
85
|
-
createTemplateFromBase(base, template) {
|
|
86
|
-
this.run(`createdb -T "${base}" "${template}"`);
|
|
87
|
-
this.run(`psql -c "UPDATE pg_database SET datistemplate = true WHERE datname = '${template}';"`);
|
|
88
|
-
}
|
|
89
|
-
cleanupTemplate(template) {
|
|
90
|
-
try {
|
|
91
|
-
this.run(`psql -c "UPDATE pg_database SET datistemplate = false WHERE datname = '${template}'"`);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
log.warn(`Skipping failed UPDATE of datistemplate for ${template}`);
|
|
95
|
-
}
|
|
96
|
-
this.safeDropDb(template);
|
|
97
|
-
}
|
|
98
|
-
async grantRole(role, user, dbName) {
|
|
99
|
-
const db = dbName ?? this.config.database;
|
|
100
|
-
const sql = `GRANT ${role} TO ${user};`;
|
|
101
|
-
await this.streamSql(sql, db);
|
|
102
|
-
}
|
|
103
|
-
async grantConnect(role, dbName) {
|
|
104
|
-
const db = dbName ?? this.config.database;
|
|
105
|
-
const sql = `GRANT CONNECT ON DATABASE "${db}" TO ${role};`;
|
|
106
|
-
await this.streamSql(sql, db);
|
|
107
|
-
}
|
|
108
|
-
// TODO: make adminRole a configurable option
|
|
109
|
-
// ONLY granting admin role for testing purposes, normally the db connection for apps won't have admin role
|
|
110
|
-
// DO NOT USE THIS FOR PRODUCTION
|
|
111
|
-
async createUserRole(user, password, dbName) {
|
|
112
|
-
const anonRole = (0, roles_1.getRoleName)('anonymous', this.roleConfig);
|
|
113
|
-
const authRole = (0, roles_1.getRoleName)('authenticated', this.roleConfig);
|
|
114
|
-
const adminRole = (0, roles_1.getRoleName)('administrator', this.roleConfig);
|
|
115
|
-
const sql = `
|
|
116
|
-
DO $$
|
|
117
|
-
BEGIN
|
|
118
|
-
-- Create role if it doesn't exist
|
|
119
|
-
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${user}') THEN
|
|
120
|
-
CREATE ROLE ${user} LOGIN PASSWORD '${password}';
|
|
121
|
-
END IF;
|
|
122
|
-
|
|
123
|
-
-- Grant anonymous role if not already granted
|
|
124
|
-
IF NOT EXISTS (
|
|
125
|
-
SELECT 1 FROM pg_auth_members am
|
|
126
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
127
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
128
|
-
WHERE r1.rolname = '${anonRole}' AND r2.rolname = '${user}'
|
|
129
|
-
) THEN
|
|
130
|
-
GRANT ${anonRole} TO ${user};
|
|
131
|
-
END IF;
|
|
132
|
-
|
|
133
|
-
-- Grant authenticated role if not already granted
|
|
134
|
-
IF NOT EXISTS (
|
|
135
|
-
SELECT 1 FROM pg_auth_members am
|
|
136
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
137
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
138
|
-
WHERE r1.rolname = '${authRole}' AND r2.rolname = '${user}'
|
|
139
|
-
) THEN
|
|
140
|
-
GRANT ${authRole} TO ${user};
|
|
141
|
-
END IF;
|
|
142
|
-
|
|
143
|
-
-- Grant administrator role if not already granted
|
|
144
|
-
IF NOT EXISTS (
|
|
145
|
-
SELECT 1 FROM pg_auth_members am
|
|
146
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
147
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
148
|
-
WHERE r1.rolname = '${adminRole}' AND r2.rolname = '${user}'
|
|
149
|
-
) THEN
|
|
150
|
-
GRANT ${adminRole} TO ${user};
|
|
151
|
-
END IF;
|
|
152
|
-
END $$;
|
|
153
|
-
`.trim();
|
|
154
|
-
await this.streamSql(sql, dbName);
|
|
155
|
-
}
|
|
156
|
-
loadSql(file, dbName) {
|
|
157
|
-
if (!(0, fs_1.existsSync)(file)) {
|
|
158
|
-
throw new Error(`Missing SQL file: ${file}`);
|
|
159
|
-
}
|
|
160
|
-
this.run(`psql -f ${file} ${dbName}`);
|
|
161
|
-
}
|
|
162
|
-
async streamSql(sql, dbName) {
|
|
163
|
-
await (0, stream_1.streamSql)({
|
|
164
|
-
...this.config,
|
|
165
|
-
database: dbName
|
|
166
|
-
}, sql);
|
|
167
|
-
}
|
|
168
|
-
async createSeededTemplate(templateName, adapter) {
|
|
169
|
-
const seedDb = this.config.database;
|
|
170
|
-
this.create(seedDb);
|
|
171
|
-
await adapter.seed({
|
|
172
|
-
admin: this,
|
|
173
|
-
config: this.config,
|
|
174
|
-
pg: null, // placeholder for PgTestClient
|
|
175
|
-
connect: null // placeholder for connection factory
|
|
176
|
-
});
|
|
177
|
-
this.cleanupTemplate(templateName);
|
|
178
|
-
this.createTemplateFromBase(seedDb, templateName);
|
|
179
|
-
this.drop(seedDb);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
exports.DbAdmin = DbAdmin;
|
package/connect.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { PgTestConnectionOptions } from '@launchql/types';
|
|
2
|
-
import { PgConfig } from 'pg-env';
|
|
3
|
-
import { DbAdmin } from './admin';
|
|
4
|
-
import { PgTestConnector } from './manager';
|
|
5
|
-
import { SeedAdapter } from './seed/types';
|
|
6
|
-
import { PgTestClient } from './test-client';
|
|
7
|
-
export declare const getPgRootAdmin: (connOpts?: PgTestConnectionOptions) => DbAdmin;
|
|
8
|
-
export interface GetConnectionOpts {
|
|
9
|
-
pg?: Partial<PgConfig>;
|
|
10
|
-
db?: Partial<PgTestConnectionOptions>;
|
|
11
|
-
}
|
|
12
|
-
export interface GetConnectionResult {
|
|
13
|
-
pg: PgTestClient;
|
|
14
|
-
db: PgTestClient;
|
|
15
|
-
admin: DbAdmin;
|
|
16
|
-
teardown: () => Promise<void>;
|
|
17
|
-
manager: PgTestConnector;
|
|
18
|
-
}
|
|
19
|
-
export declare const getConnections: (cn?: GetConnectionOpts, seedAdapters?: SeedAdapter[]) => Promise<GetConnectionResult>;
|
package/connect.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getConnections = exports.getPgRootAdmin = void 0;
|
|
4
|
-
const env_1 = require("@launchql/env");
|
|
5
|
-
const crypto_1 = require("crypto");
|
|
6
|
-
const pg_cache_1 = require("pg-cache");
|
|
7
|
-
const pg_env_1 = require("pg-env");
|
|
8
|
-
const admin_1 = require("./admin");
|
|
9
|
-
const manager_1 = require("./manager");
|
|
10
|
-
const roles_1 = require("./roles");
|
|
11
|
-
const seed_1 = require("./seed");
|
|
12
|
-
let manager;
|
|
13
|
-
const getPgRootAdmin = (connOpts = {}) => {
|
|
14
|
-
const opts = (0, pg_env_1.getPgEnvOptions)({
|
|
15
|
-
database: connOpts.rootDb
|
|
16
|
-
});
|
|
17
|
-
const admin = new admin_1.DbAdmin(opts, false, connOpts);
|
|
18
|
-
return admin;
|
|
19
|
-
};
|
|
20
|
-
exports.getPgRootAdmin = getPgRootAdmin;
|
|
21
|
-
const getConnOopts = (cn = {}) => {
|
|
22
|
-
const connect = (0, env_1.getConnEnvOptions)(cn.db);
|
|
23
|
-
const config = (0, pg_env_1.getPgEnvOptions)({
|
|
24
|
-
database: `${connect.prefix}${(0, crypto_1.randomUUID)()}`,
|
|
25
|
-
...cn.pg
|
|
26
|
-
});
|
|
27
|
-
return {
|
|
28
|
-
pg: config,
|
|
29
|
-
db: connect
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
const getConnections = async (cn = {}, seedAdapters = [seed_1.seed.launchql()]) => {
|
|
33
|
-
cn = getConnOopts(cn);
|
|
34
|
-
const config = cn.pg;
|
|
35
|
-
const connOpts = cn.db;
|
|
36
|
-
const root = (0, exports.getPgRootAdmin)(connOpts);
|
|
37
|
-
await root.createUserRole(connOpts.connection.user, connOpts.connection.password, connOpts.rootDb);
|
|
38
|
-
const admin = new admin_1.DbAdmin(config, false, connOpts);
|
|
39
|
-
if (process.env.TEST_DB) {
|
|
40
|
-
config.database = process.env.TEST_DB;
|
|
41
|
-
}
|
|
42
|
-
else if (connOpts.template) {
|
|
43
|
-
admin.createFromTemplate(connOpts.template, config.database);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
admin.create(config.database);
|
|
47
|
-
admin.installExtensions(connOpts.extensions);
|
|
48
|
-
}
|
|
49
|
-
await admin.grantConnect(connOpts.connection.user, config.database);
|
|
50
|
-
manager = manager_1.PgTestConnector.getInstance();
|
|
51
|
-
const pg = manager.getClient(config);
|
|
52
|
-
const teardown = async () => {
|
|
53
|
-
manager.beginTeardown();
|
|
54
|
-
await (0, pg_cache_1.teardownPgPools)();
|
|
55
|
-
await manager.closeAll();
|
|
56
|
-
};
|
|
57
|
-
if (seedAdapters.length) {
|
|
58
|
-
try {
|
|
59
|
-
await seed_1.seed.compose(seedAdapters).seed({
|
|
60
|
-
connect: connOpts,
|
|
61
|
-
admin,
|
|
62
|
-
config: config,
|
|
63
|
-
pg: manager.getClient(config)
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
await teardown();
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
const dbConfig = {
|
|
72
|
-
...config,
|
|
73
|
-
user: connOpts.connection.user,
|
|
74
|
-
password: connOpts.connection.password
|
|
75
|
-
};
|
|
76
|
-
const db = manager.getClient(dbConfig, {
|
|
77
|
-
auth: connOpts.auth,
|
|
78
|
-
roles: connOpts.roles
|
|
79
|
-
});
|
|
80
|
-
db.setContext({ role: (0, roles_1.getDefaultRole)(connOpts) });
|
|
81
|
-
return { pg, db, teardown, manager, admin };
|
|
82
|
-
};
|
|
83
|
-
exports.getConnections = getConnections;
|