@safegres/test 0.0.1 → 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/cli/commands.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.commands = void 0;
|
|
7
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
8
|
+
const inquirerer_1 = require("inquirerer");
|
|
9
|
+
const audit_1 = __importDefault(require("./audit"));
|
|
10
|
+
const baseline_1 = __importDefault(require("./baseline"));
|
|
11
|
+
const doctor_1 = __importDefault(require("./doctor"));
|
|
12
|
+
const eval_1 = __importDefault(require("./eval"));
|
|
13
|
+
const print_config_1 = __importDefault(require("./print-config"));
|
|
14
|
+
const log = new logger_1.Logger('safegres');
|
|
15
|
+
const usage = `
|
|
16
|
+
safegres — Postgres security and performance auditor
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
safegres <command> [OPTIONS]
|
|
20
|
+
|
|
21
|
+
Commands:
|
|
22
|
+
audit Audit grants, RLS flags, policy coverage, and anti-patterns
|
|
23
|
+
lint Alias for audit, for a package.json script
|
|
24
|
+
perf Audit index hygiene and policy cost (audit --perf)
|
|
25
|
+
baseline Choose the report a delta is measured against (CI)
|
|
26
|
+
doctor Diagnose environment, connection, and configuration
|
|
27
|
+
eval Grade the auditor against a corpus with known answers
|
|
28
|
+
print-config Show the resolved effective configuration
|
|
29
|
+
help Show this help message
|
|
30
|
+
|
|
31
|
+
Run \`safegres <command> --help\` for command-specific options.
|
|
32
|
+
`;
|
|
33
|
+
const commandMap = {
|
|
34
|
+
audit: audit_1.default,
|
|
35
|
+
lint: audit_1.default,
|
|
36
|
+
perf: (argv, prompter, options) => (0, audit_1.default)({ ...argv, perf: true }, prompter, options),
|
|
37
|
+
baseline: baseline_1.default,
|
|
38
|
+
doctor: doctor_1.default,
|
|
39
|
+
eval: eval_1.default,
|
|
40
|
+
'print-config': print_config_1.default
|
|
41
|
+
};
|
|
42
|
+
const commands = async (argv, prompter, options) => {
|
|
43
|
+
const { first: command, newArgv } = (0, inquirerer_1.extractFirst)(argv);
|
|
44
|
+
if (!command && (argv.help || argv.h)) {
|
|
45
|
+
process.stdout.write(usage);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!command || command === 'help') {
|
|
49
|
+
process.stdout.write(usage);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const handler = commandMap[command];
|
|
53
|
+
if (!handler) {
|
|
54
|
+
log.error(`Unknown command: ${command}`);
|
|
55
|
+
process.stdout.write(usage);
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
await handler(newArgv, prompter, options);
|
|
59
|
+
};
|
|
60
|
+
exports.commands = commands;
|
package/cli/doctor.d.ts
ADDED
package/cli/doctor.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const yanse_1 = __importDefault(require("yanse"));
|
|
7
|
+
const doctor_1 = require("../commands/doctor");
|
|
8
|
+
const shared_1 = require("./shared");
|
|
9
|
+
const usage = `
|
|
10
|
+
safegres doctor — diagnose the environment, connection, and configuration
|
|
11
|
+
|
|
12
|
+
safegres doctor [OPTIONS]
|
|
13
|
+
|
|
14
|
+
Connection (same flags as \`safegres audit\`):
|
|
15
|
+
--connection <url> Full PostgreSQL connection string
|
|
16
|
+
--host / --port / --user / --password / --database
|
|
17
|
+
|
|
18
|
+
Configuration:
|
|
19
|
+
--config <path> Explicit config file
|
|
20
|
+
--preset <name> Apply a built-in preset
|
|
21
|
+
--rule <CODE=SETTING> Retune a rule (repeatable)
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--no-color Disable ANSI colors
|
|
25
|
+
--help, -h Show this help message
|
|
26
|
+
|
|
27
|
+
Checks: config discovery & rule validation, pgsql-parser availability,
|
|
28
|
+
connection, catalog access (pg_policy), audit blind spots (BYPASSRLS),
|
|
29
|
+
and whether any tables actually have RLS enabled.
|
|
30
|
+
`;
|
|
31
|
+
const STATUS_LABEL = {
|
|
32
|
+
ok: 'OK ',
|
|
33
|
+
warn: 'WARN',
|
|
34
|
+
fail: 'FAIL'
|
|
35
|
+
};
|
|
36
|
+
exports.default = async (argv, _prompter, _options) => {
|
|
37
|
+
if (argv.help || argv.h) {
|
|
38
|
+
process.stdout.write(usage);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const colorEnabled = argv.color !== false;
|
|
42
|
+
const paint = (status, s) => {
|
|
43
|
+
if (!colorEnabled)
|
|
44
|
+
return s;
|
|
45
|
+
if (status === 'ok')
|
|
46
|
+
return yanse_1.default.green(s);
|
|
47
|
+
if (status === 'warn')
|
|
48
|
+
return yanse_1.default.yellow(s);
|
|
49
|
+
return yanse_1.default.bold(yanse_1.default.red(s));
|
|
50
|
+
};
|
|
51
|
+
let client = (0, shared_1.buildClient)(argv);
|
|
52
|
+
try {
|
|
53
|
+
await client.connect();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
client = null;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const report = await (0, doctor_1.doctor)(client, (0, shared_1.configParamsFromArgv)(argv));
|
|
60
|
+
for (const check of report.checks) {
|
|
61
|
+
process.stdout.write(`[${paint(check.status, STATUS_LABEL[check.status])}] ${check.name.padEnd(12)} ${check.detail}\n`);
|
|
62
|
+
}
|
|
63
|
+
process.stdout.write('\n');
|
|
64
|
+
process.stdout.write(report.ok ? 'doctor: all checks passed\n' : 'doctor: some checks failed\n');
|
|
65
|
+
if (!report.ok)
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
if (client)
|
|
70
|
+
await client.end();
|
|
71
|
+
}
|
|
72
|
+
};
|
package/cli/eval.d.ts
ADDED
package/cli/eval.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const yanse_1 = __importDefault(require("yanse"));
|
|
41
|
+
const eval_1 = require("../commands/eval");
|
|
42
|
+
const loader_1 = require("../config/loader");
|
|
43
|
+
const corpus_1 = require("../corpus");
|
|
44
|
+
const shared_1 = require("./shared");
|
|
45
|
+
const usage = `
|
|
46
|
+
safegres eval — grade the auditor against a corpus with known answers
|
|
47
|
+
|
|
48
|
+
safegres eval [OPTIONS]
|
|
49
|
+
|
|
50
|
+
Deploys each corpus case into the connected database, audits it under a sealed
|
|
51
|
+
preset, and grades the report against the case's answer key: every expected
|
|
52
|
+
finding present (recall), nothing the case forbids (precision). Exits non-zero
|
|
53
|
+
if any case fails. Each case's schemas are dropped afterwards.
|
|
54
|
+
|
|
55
|
+
Connection (same flags as \`safegres audit\`):
|
|
56
|
+
--connection <url> Full PostgreSQL connection string
|
|
57
|
+
--host / --port / --user / --password / --database
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
--preset <name> Preset every case is graded under (default: recommended)
|
|
61
|
+
--corpus <dir> Corpus directory of <id>/{case.json,schema.sql}
|
|
62
|
+
--case <id> Run only these cases; id or id prefix, comma-separated
|
|
63
|
+
--list List the corpus without connecting to a database
|
|
64
|
+
--keep Leave the case schemas in the database
|
|
65
|
+
--json Emit the machine-readable result instead of a table
|
|
66
|
+
--no-color Disable ANSI colors
|
|
67
|
+
--help, -h Show this help message
|
|
68
|
+
|
|
69
|
+
Config: a discovered safegres config may set \`eval.corpus\`, \`eval.preset\` and
|
|
70
|
+
\`eval.cases\` — what to run. It cannot retune the rules: cases are always
|
|
71
|
+
graded by the named preset alone, or the corpus would be measuring itself.
|
|
72
|
+
`;
|
|
73
|
+
/**
|
|
74
|
+
* Discovery is used for *selection only* (which corpus, which preset, which
|
|
75
|
+
* cases). Grading always loads the preset sealed, so nothing in the working
|
|
76
|
+
* tree can change the answers.
|
|
77
|
+
*/
|
|
78
|
+
function evalDefaults(configFile) {
|
|
79
|
+
try {
|
|
80
|
+
const loaded = (0, loader_1.loadConfig)({ configFile });
|
|
81
|
+
const config = loaded.config.eval ?? {};
|
|
82
|
+
if (config.corpus === undefined)
|
|
83
|
+
return config;
|
|
84
|
+
// Like every other configured path: relative to the file that declared it,
|
|
85
|
+
// so a corpus committed next to the config is found from any cwd.
|
|
86
|
+
return { ...config, corpus: path.resolve((0, loader_1.configPathBase)(loaded).dirFor('eval.corpus'), config.corpus) };
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function line(r, color) {
|
|
93
|
+
const paint = (s) => (!color ? s : r.passed ? yanse_1.default.green(s) : yanse_1.default.bold(yanse_1.default.red(s)));
|
|
94
|
+
const detail = r.passed
|
|
95
|
+
? r.found.map((e) => e.code).join(' ')
|
|
96
|
+
: [
|
|
97
|
+
...r.missed.map((e) => `missed ${e.code}${e.relation ? `@${e.relation}` : ''}`),
|
|
98
|
+
...r.falsePositives.map((code) => `false positive ${code}`)
|
|
99
|
+
].join(', ');
|
|
100
|
+
return ` ${paint(r.passed ? 'PASS' : 'FAIL')} ${r.id.padEnd(32)} ${r.dimension.padEnd(8)} `
|
|
101
|
+
+ `${String(r.score).padStart(3)} (${r.grade.padEnd(2)}) ${detail}\n`;
|
|
102
|
+
}
|
|
103
|
+
function summary(report, color) {
|
|
104
|
+
const pct = (n) => `${Math.round(n * 100)}%`;
|
|
105
|
+
const ok = report.passed === report.total;
|
|
106
|
+
const headline = `${report.passed}/${report.total} cases passed`;
|
|
107
|
+
return `\n${color ? (ok ? yanse_1.default.green(headline) : yanse_1.default.bold(yanse_1.default.red(headline))) : headline}`
|
|
108
|
+
+ ` · recall ${pct(report.recall)} · precision ${pct(report.precision)}\n`;
|
|
109
|
+
}
|
|
110
|
+
exports.default = async (argv, _prompter, _options) => {
|
|
111
|
+
if (argv.help || argv.h) {
|
|
112
|
+
process.stdout.write(usage);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const defaults = evalDefaults(typeof argv.config === 'string' ? argv.config : undefined);
|
|
116
|
+
const corpus = typeof argv.corpus === 'string' ? argv.corpus : defaults.corpus;
|
|
117
|
+
const preset = typeof argv.preset === 'string' ? argv.preset : (defaults.preset ?? 'recommended');
|
|
118
|
+
const cases = (0, shared_1.csvList)(argv.case) ?? defaults.cases;
|
|
119
|
+
const color = argv.color !== false && argv.json !== true;
|
|
120
|
+
if (argv.list === true) {
|
|
121
|
+
for (const c of (0, corpus_1.loadCorpus)(corpus)) {
|
|
122
|
+
process.stdout.write(`${c.id.padEnd(32)} ${c.dimension.padEnd(8)} ${c.title}\n`);
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const { config } = (0, loader_1.loadConfig)({ sealed: true, preset });
|
|
127
|
+
const client = (0, shared_1.buildClient)(argv);
|
|
128
|
+
await client.connect();
|
|
129
|
+
try {
|
|
130
|
+
const report = await (0, eval_1.runEval)(client, {
|
|
131
|
+
config,
|
|
132
|
+
preset,
|
|
133
|
+
corpus,
|
|
134
|
+
cases,
|
|
135
|
+
keep: argv.keep === true,
|
|
136
|
+
onResult: argv.json === true ? undefined : (r) => process.stdout.write(line(r, color))
|
|
137
|
+
});
|
|
138
|
+
if (argv.json === true) {
|
|
139
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
process.stdout.write(summary(report, color));
|
|
143
|
+
for (const r of report.results.filter((x) => !x.passed)) {
|
|
144
|
+
process.stdout.write(`\n${r.id}: ${r.title}\n fix: ${r.fix}\n`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (report.passed !== report.total)
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
await client.end();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const loader_1 = require("../config/loader");
|
|
4
|
+
const resolve_1 = require("../config/resolve");
|
|
5
|
+
const schema_1 = require("../config/schema");
|
|
6
|
+
const registry_1 = require("../rules/registry");
|
|
7
|
+
const shared_1 = require("./shared");
|
|
8
|
+
const usage = `
|
|
9
|
+
safegres print-config — show the resolved effective configuration
|
|
10
|
+
|
|
11
|
+
safegres print-config [OPTIONS]
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
--config <path> Explicit config file
|
|
15
|
+
--preset <name> Apply a built-in preset
|
|
16
|
+
--rule <CODE=SETTING> Retune a rule (repeatable)
|
|
17
|
+
--explain Show per-key provenance (which layer set each value)
|
|
18
|
+
--schema Print the config JSON Schema instead, for an editor
|
|
19
|
+
--help, -h Show this help message
|
|
20
|
+
`;
|
|
21
|
+
exports.default = async (argv, _prompter, _options) => {
|
|
22
|
+
if (argv.help || argv.h) {
|
|
23
|
+
process.stdout.write(usage);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (argv.schema === true) {
|
|
27
|
+
process.stdout.write(`${JSON.stringify((0, schema_1.toJsonSchema)(), null, 2)}\n`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const params = (0, shared_1.configParamsFromArgv)(argv);
|
|
31
|
+
if (argv.explain === true) {
|
|
32
|
+
const loader = (0, loader_1.safegresConfigLoader)();
|
|
33
|
+
const explained = loader.explainSync({
|
|
34
|
+
configFile: params.configFile,
|
|
35
|
+
overrides: params.overrides
|
|
36
|
+
});
|
|
37
|
+
for (const e of explained) {
|
|
38
|
+
process.stdout.write(`${e.path} = ${JSON.stringify(e.value)} (${e.source}: ${e.origin})\n`);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { config, filepath, isEmpty } = (0, loader_1.loadConfig)(params);
|
|
43
|
+
const resolved = (0, resolve_1.resolveRules)(config);
|
|
44
|
+
const effectiveRules = {};
|
|
45
|
+
for (const rule of registry_1.RULES) {
|
|
46
|
+
const r = resolved.rules.get(rule.code);
|
|
47
|
+
effectiveRules[rule.code] = r.enabled ? r.severity : 'off';
|
|
48
|
+
}
|
|
49
|
+
process.stdout.write(`${JSON.stringify({
|
|
50
|
+
source: filepath ?? (isEmpty ? '(no config file — defaults)' : undefined),
|
|
51
|
+
config,
|
|
52
|
+
effectiveRules
|
|
53
|
+
}, null, 2)}\n`);
|
|
54
|
+
};
|
package/cli/shared.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ParsedArgs } from 'inquirerer';
|
|
2
|
+
import { Client } from 'pg';
|
|
3
|
+
import type { ConfigPathBase, LoadConfigParams } from '../config/loader';
|
|
4
|
+
import type { ExtensionsConfig, RulesConfig, SafegresConfig } from '../config/types';
|
|
5
|
+
export declare function csvList(value: unknown): string[] | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Merge `--ignore-extensions` / `--audit-extension-owned` over the config's
|
|
8
|
+
* `extensions` block. Returns `undefined` when neither side says anything, so
|
|
9
|
+
* the introspection defaults apply.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extensionScopeFromArgv(argv: ParsedArgs, config: SafegresConfig): ExtensionsConfig | undefined;
|
|
12
|
+
export declare function buildClient(argv: ParsedArgs): Client;
|
|
13
|
+
/**
|
|
14
|
+
* Parse repeatable `--rule CODE=SETTING` flags into a RulesConfig, e.g.
|
|
15
|
+
* `--rule A3=off --rule A5=high --rule 'P*'=off`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseRuleFlags(value: unknown): RulesConfig | undefined;
|
|
18
|
+
/** Every file a run reads or writes, after flags and config have been merged. */
|
|
19
|
+
export interface RunPaths {
|
|
20
|
+
/** The pgpm workspace to deploy, when `usePgpm`. Undefined means "nearest". */
|
|
21
|
+
pgpm?: string;
|
|
22
|
+
usePgpm: boolean;
|
|
23
|
+
perfBaseline?: string;
|
|
24
|
+
callGraphBaseline?: string;
|
|
25
|
+
outputs: {
|
|
26
|
+
json?: string;
|
|
27
|
+
markdown?: string;
|
|
28
|
+
sarif?: string;
|
|
29
|
+
sarifSources?: string;
|
|
30
|
+
snapshot?: string;
|
|
31
|
+
githubComment?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Flags win over the config file. A path from a config file is resolved
|
|
36
|
+
* against *the file that declared it* — which is not always the discovered
|
|
37
|
+
* one, since a file can extend another — so a CI job can run from any
|
|
38
|
+
* directory; a path on the command line stays relative to cwd, like every
|
|
39
|
+
* other command's arguments.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveRunPaths(argv: ParsedArgs, config: SafegresConfig, base: ConfigPathBase | string): RunPaths;
|
|
42
|
+
/** Build config-loading params from shared CLI flags. */
|
|
43
|
+
export declare function configParamsFromArgv(argv: ParsedArgs): LoadConfigParams;
|
package/cli/shared.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.csvList = csvList;
|
|
37
|
+
exports.extensionScopeFromArgv = extensionScopeFromArgv;
|
|
38
|
+
exports.buildClient = buildClient;
|
|
39
|
+
exports.parseRuleFlags = parseRuleFlags;
|
|
40
|
+
exports.resolveRunPaths = resolveRunPaths;
|
|
41
|
+
exports.configParamsFromArgv = configParamsFromArgv;
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const pg_1 = require("pg");
|
|
44
|
+
const pg_env_1 = require("pg-env");
|
|
45
|
+
function csvList(value) {
|
|
46
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
47
|
+
return undefined;
|
|
48
|
+
return value
|
|
49
|
+
.split(',')
|
|
50
|
+
.map((p) => p.trim())
|
|
51
|
+
.filter(Boolean);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Merge `--ignore-extensions` / `--audit-extension-owned` over the config's
|
|
55
|
+
* `extensions` block. Returns `undefined` when neither side says anything, so
|
|
56
|
+
* the introspection defaults apply.
|
|
57
|
+
*/
|
|
58
|
+
function extensionScopeFromArgv(argv, config) {
|
|
59
|
+
const ignore = csvList(argv['ignore-extensions']) ?? config.extensions?.ignore;
|
|
60
|
+
const skipOwned = argv['audit-extension-owned'] === true ? false : config.extensions?.skipOwned;
|
|
61
|
+
if (ignore === undefined && skipOwned === undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
return { ...(ignore !== undefined && { ignore }), ...(skipOwned !== undefined && { skipOwned }) };
|
|
64
|
+
}
|
|
65
|
+
function buildClient(argv) {
|
|
66
|
+
if (typeof argv.connection === 'string' && argv.connection.length > 0) {
|
|
67
|
+
return new pg_1.Client({ connectionString: argv.connection });
|
|
68
|
+
}
|
|
69
|
+
const overrides = {};
|
|
70
|
+
if (typeof argv.host === 'string')
|
|
71
|
+
overrides.host = argv.host;
|
|
72
|
+
if (typeof argv.port === 'number')
|
|
73
|
+
overrides.port = argv.port;
|
|
74
|
+
if (typeof argv.user === 'string')
|
|
75
|
+
overrides.user = argv.user;
|
|
76
|
+
if (typeof argv.password === 'string')
|
|
77
|
+
overrides.password = argv.password;
|
|
78
|
+
if (typeof argv.database === 'string')
|
|
79
|
+
overrides.database = argv.database;
|
|
80
|
+
return new pg_1.Client((0, pg_env_1.getPgEnvOptions)(overrides));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Parse repeatable `--rule CODE=SETTING` flags into a RulesConfig, e.g.
|
|
84
|
+
* `--rule A3=off --rule A5=high --rule 'P*'=off`.
|
|
85
|
+
*/
|
|
86
|
+
function parseRuleFlags(value) {
|
|
87
|
+
if (value == null)
|
|
88
|
+
return undefined;
|
|
89
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
90
|
+
const rules = {};
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (typeof entry !== 'string')
|
|
93
|
+
continue;
|
|
94
|
+
const eq = entry.indexOf('=');
|
|
95
|
+
if (eq <= 0) {
|
|
96
|
+
throw new Error(`Invalid --rule "${entry}": expected CODE=off|<severity>.`);
|
|
97
|
+
}
|
|
98
|
+
const code = entry.slice(0, eq).trim();
|
|
99
|
+
const setting = entry.slice(eq + 1).trim();
|
|
100
|
+
rules[code] = setting;
|
|
101
|
+
}
|
|
102
|
+
return Object.keys(rules).length > 0 ? rules : undefined;
|
|
103
|
+
}
|
|
104
|
+
/** Did the caller name a database on the command line, rather than in the environment? */
|
|
105
|
+
function hasConnectionFlag(argv) {
|
|
106
|
+
return ['connection', 'database', 'host', 'port'].some((flag) => typeof argv[flag] === 'string' || typeof argv[flag] === 'number');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Flags win over the config file. A path from a config file is resolved
|
|
110
|
+
* against *the file that declared it* — which is not always the discovered
|
|
111
|
+
* one, since a file can extend another — so a CI job can run from any
|
|
112
|
+
* directory; a path on the command line stays relative to cwd, like every
|
|
113
|
+
* other command's arguments.
|
|
114
|
+
*/
|
|
115
|
+
function resolveRunPaths(argv, config, base) {
|
|
116
|
+
const dirFor = typeof base === 'string' ? () => base : (key) => base.dirFor(key);
|
|
117
|
+
const pick = (flag, key, configured) => typeof flag === 'string' ? flag : configured && path.resolve(dirFor(key), configured);
|
|
118
|
+
// A directory is the common case: one path, conventional names, no remembering
|
|
119
|
+
// which extension goes with which renderer. A named file still wins.
|
|
120
|
+
const dir = pick(argv.out, 'outputs.dir', config.outputs?.dir);
|
|
121
|
+
const inDir = (name) => dir && path.join(dir, name);
|
|
122
|
+
return {
|
|
123
|
+
pgpm: pick(argv.pgpm, 'source.pgpm', config.source?.pgpm),
|
|
124
|
+
// An explicit connection on the command line beats a configured source:
|
|
125
|
+
// pointing the same config at a database you already have is the whole
|
|
126
|
+
// reason to type one, and deploying a throwaway copy instead would ignore it.
|
|
127
|
+
usePgpm: argv.pgpm !== undefined || (config.source?.pgpm !== undefined && !hasConnectionFlag(argv)),
|
|
128
|
+
perfBaseline: pick(argv['perf-baseline'], 'perf.baseline', config.perf?.baseline),
|
|
129
|
+
callGraphBaseline: pick(argv.baseline, 'callGraph.baseline', config.callGraph?.baseline),
|
|
130
|
+
outputs: {
|
|
131
|
+
json: pick(argv['write-json'], 'outputs.json', config.outputs?.json) ?? inDir('safegres.json'),
|
|
132
|
+
markdown: pick(argv['write-markdown'], 'outputs.markdown', config.outputs?.markdown)
|
|
133
|
+
?? inDir('safegres.md'),
|
|
134
|
+
sarif: pick(argv['write-sarif'], 'outputs.sarif', config.outputs?.sarif) ?? inDir('safegres.sarif'),
|
|
135
|
+
sarifSources: pick(argv['sarif-sources'], 'outputs.sarifSources', config.outputs?.sarifSources),
|
|
136
|
+
snapshot: pick(argv['write-snapshot'], 'outputs.snapshot', config.outputs?.snapshot),
|
|
137
|
+
githubComment: pick(argv['write-github-comment'], 'outputs.githubComment', config.outputs?.githubComment)
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** Build config-loading params from shared CLI flags. */
|
|
142
|
+
function configParamsFromArgv(argv) {
|
|
143
|
+
const cliRules = parseRuleFlags(argv.rule);
|
|
144
|
+
const overrides = {};
|
|
145
|
+
if (cliRules)
|
|
146
|
+
overrides.rules = cliRules;
|
|
147
|
+
return {
|
|
148
|
+
configFile: typeof argv.config === 'string' ? argv.config : undefined,
|
|
149
|
+
preset: typeof argv.preset === 'string' ? argv.preset : undefined,
|
|
150
|
+
overrides: Object.keys(overrides).length > 0 ? overrides : undefined,
|
|
151
|
+
sealed: argv.sealed === true
|
|
152
|
+
};
|
|
153
|
+
}
|
package/cli.d.ts
ADDED
package/cli.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const logger_1 = require("@pgpmjs/logger");
|
|
5
|
+
const inquirerer_1 = require("inquirerer");
|
|
6
|
+
const commands_1 = require("./cli/commands");
|
|
7
|
+
const log = new logger_1.Logger('safegres');
|
|
8
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
9
|
+
const pkg = (0, inquirerer_1.getPackageJson)(__dirname);
|
|
10
|
+
process.stdout.write(`${pkg.version}\n`);
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
const options = {
|
|
14
|
+
minimistOpts: {
|
|
15
|
+
alias: { v: 'version', h: 'help', q: 'summary' },
|
|
16
|
+
boolean: [
|
|
17
|
+
'skip-ast',
|
|
18
|
+
'color',
|
|
19
|
+
'help',
|
|
20
|
+
'version',
|
|
21
|
+
'summary',
|
|
22
|
+
'verbose',
|
|
23
|
+
'call-graph',
|
|
24
|
+
'fail-on-new-boundaries',
|
|
25
|
+
'keep',
|
|
26
|
+
'list',
|
|
27
|
+
'json'
|
|
28
|
+
],
|
|
29
|
+
string: [
|
|
30
|
+
'baseline',
|
|
31
|
+
'write-baseline',
|
|
32
|
+
'compare',
|
|
33
|
+
'compare-ref',
|
|
34
|
+
'compare-sha',
|
|
35
|
+
'compare-run-id',
|
|
36
|
+
'compare-run-url',
|
|
37
|
+
'compare-age',
|
|
38
|
+
'compare-skipped',
|
|
39
|
+
'write-snapshot',
|
|
40
|
+
'connection',
|
|
41
|
+
'host',
|
|
42
|
+
'user',
|
|
43
|
+
'password',
|
|
44
|
+
'database',
|
|
45
|
+
'schemas',
|
|
46
|
+
'exclude-schemas',
|
|
47
|
+
'ignore-extensions',
|
|
48
|
+
'roles',
|
|
49
|
+
'exclude-roles',
|
|
50
|
+
'format',
|
|
51
|
+
'fail-on',
|
|
52
|
+
'out',
|
|
53
|
+
'preset',
|
|
54
|
+
'corpus',
|
|
55
|
+
'case',
|
|
56
|
+
'provider',
|
|
57
|
+
'repo',
|
|
58
|
+
'base',
|
|
59
|
+
'head',
|
|
60
|
+
'workflow',
|
|
61
|
+
'artifact',
|
|
62
|
+
'dir'
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
new inquirerer_1.CLI(commands_1.commands, options).run().catch((error) => {
|
|
67
|
+
log.error(error);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|