@safegres/test 0.0.2 → 1.30.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +825 -412
- package/adapters.d.ts +8 -0
- package/adapters.js +18 -0
- package/ast/helpers.d.ts +16 -0
- package/ast/helpers.js +40 -0
- package/ast/parse.d.ts +31 -0
- package/ast/parse.js +87 -0
- package/ast/walk.d.ts +27 -0
- package/ast/walk.js +79 -0
- package/callgraph/baseline.d.ts +28 -0
- package/callgraph/baseline.js +55 -0
- package/callgraph/extract.d.ts +93 -0
- package/callgraph/extract.js +340 -0
- package/callgraph/graph.d.ts +82 -0
- package/callgraph/graph.js +276 -0
- package/checks/anti-patterns.d.ts +53 -0
- package/checks/anti-patterns.js +247 -0
- package/checks/column-grants.d.ts +20 -0
- package/checks/column-grants.js +74 -0
- package/checks/coverage.d.ts +43 -0
- package/checks/coverage.js +110 -0
- package/checks/definer-function.d.ts +91 -0
- package/checks/definer-function.js +458 -0
- package/checks/definer-view.d.ts +167 -0
- package/checks/definer-view.js +392 -0
- package/checks/indexes.d.ts +82 -0
- package/checks/indexes.js +263 -0
- package/checks/lattice.d.ts +179 -0
- package/checks/lattice.js +487 -0
- package/checks/object-acls.d.ts +32 -0
- package/checks/object-acls.js +129 -0
- package/checks/policy-index.d.ts +78 -0
- package/checks/policy-index.js +349 -0
- package/checks/revocable-grants.d.ts +140 -0
- package/checks/revocable-grants.js +377 -0
- package/checks/rls-flags.d.ts +25 -0
- package/checks/rls-flags.js +82 -0
- package/checks/role-reach.d.ts +329 -0
- package/checks/role-reach.js +277 -0
- package/checks/role-trust.d.ts +45 -0
- package/checks/role-trust.js +91 -0
- package/checks/set-role.d.ts +21 -0
- package/checks/set-role.js +66 -0
- package/checks/stats.d.ts +52 -0
- package/checks/stats.js +192 -0
- package/checks/view-exposure.d.ts +68 -0
- package/checks/view-exposure.js +236 -0
- package/checks/view-writes.d.ts +88 -0
- package/checks/view-writes.js +350 -0
- package/ci/baseline.d.ts +104 -0
- package/ci/baseline.js +111 -0
- package/ci/github.d.ts +47 -0
- package/ci/github.js +197 -0
- package/cli/audit.d.ts +3 -0
- package/cli/audit.js +560 -0
- package/cli/baseline.d.ts +3 -0
- package/cli/baseline.js +104 -0
- package/cli/commands.d.ts +2 -0
- package/cli/commands.js +60 -0
- package/cli/doctor.d.ts +3 -0
- package/cli/doctor.js +72 -0
- package/cli/eval.d.ts +3 -0
- package/cli/eval.js +153 -0
- package/cli/print-config.d.ts +3 -0
- package/cli/print-config.js +54 -0
- package/cli/shared.d.ts +43 -0
- package/cli/shared.js +153 -0
- package/cli.d.ts +2 -0
- package/cli.js +69 -0
- package/commands/audit.d.ts +65 -0
- package/commands/audit.js +779 -0
- package/commands/doctor.d.ts +19 -0
- package/commands/doctor.js +181 -0
- package/commands/eval.d.ts +67 -0
- package/commands/eval.js +93 -0
- package/config/fingerprint.d.ts +40 -0
- package/config/fingerprint.js +71 -0
- package/config/loader.d.ts +44 -0
- package/config/loader.js +210 -0
- package/config/presets.d.ts +95 -0
- package/config/presets.js +327 -0
- package/config/resolve.d.ts +47 -0
- package/config/resolve.js +192 -0
- package/config/schema.d.ts +54 -0
- package/config/schema.js +269 -0
- package/config/types.d.ts +562 -0
- package/config/validate.d.ts +14 -0
- package/config/validate.js +125 -0
- package/corpus/README.md +83 -0
- package/corpus/bootstrap.sql +14 -0
- package/corpus/cases/01-anon-write-grant/case.json +26 -0
- package/corpus/cases/01-anon-write-grant/schema.sql +19 -0
- package/corpus/cases/02-grant-to-public/case.json +25 -0
- package/corpus/cases/02-grant-to-public/schema.sql +18 -0
- package/corpus/cases/03-rls-off-reachable-by-anon/case.json +30 -0
- package/corpus/cases/03-rls-off-reachable-by-anon/schema.sql +13 -0
- package/corpus/cases/04-permissive-write-policy/case.json +30 -0
- package/corpus/cases/04-permissive-write-policy/schema.sql +21 -0
- package/corpus/cases/05-public-read-policy/case.json +25 -0
- package/corpus/cases/05-public-read-policy/schema.sql +16 -0
- package/corpus/cases/06-update-without-with-check/case.json +25 -0
- package/corpus/cases/06-update-without-with-check/schema.sql +19 -0
- package/corpus/cases/07-rls-enabled-no-policies/case.json +29 -0
- package/corpus/cases/07-rls-enabled-no-policies/schema.sql +14 -0
- package/corpus/cases/08-select-grant-no-policy/case.json +25 -0
- package/corpus/cases/08-select-grant-no-policy/schema.sql +20 -0
- package/corpus/cases/09-write-grant-no-policy/case.json +24 -0
- package/corpus/cases/09-write-grant-no-policy/schema.sql +18 -0
- package/corpus/cases/10-rls-not-forced/case.json +24 -0
- package/corpus/cases/10-rls-not-forced/schema.sql +18 -0
- package/corpus/cases/11-session-user-in-policy/case.json +24 -0
- package/corpus/cases/11-session-user-in-policy/schema.sql +18 -0
- package/corpus/cases/12-volatile-function-in-policy/case.json +24 -0
- package/corpus/cases/12-volatile-function-in-policy/schema.sql +21 -0
- package/corpus/cases/13-security-definer-policy-wrapper/case.json +24 -0
- package/corpus/cases/13-security-definer-policy-wrapper/schema.sql +21 -0
- package/corpus/cases/14-dead-policy/case.json +24 -0
- package/corpus/cases/14-dead-policy/schema.sql +18 -0
- package/corpus/cases/15-unreachable-grant/case.json +24 -0
- package/corpus/cases/15-unreachable-grant/schema.sql +18 -0
- package/corpus/cases/16-anon-permissive-write-policy/case.json +34 -0
- package/corpus/cases/16-anon-permissive-write-policy/schema.sql +17 -0
- package/corpus/cases/17-foreign-key-without-index/case.json +24 -0
- package/corpus/cases/17-foreign-key-without-index/schema.sql +18 -0
- package/corpus/cases/18-policy-column-unindexed/case.json +24 -0
- package/corpus/cases/18-policy-column-unindexed/schema.sql +23 -0
- package/corpus/cases/19-policy-column-cast/case.json +24 -0
- package/corpus/cases/19-policy-column-cast/schema.sql +19 -0
- package/corpus/cases/20-stable-function-per-row/case.json +24 -0
- package/corpus/cases/20-stable-function-per-row/schema.sql +25 -0
- package/corpus/cases/21-table-without-primary-key/case.json +24 -0
- package/corpus/cases/21-table-without-primary-key/schema.sql +14 -0
- package/corpus/cases/22-redundant-index/case.json +24 -0
- package/corpus/cases/22-redundant-index/schema.sql +16 -0
- package/corpus/cases/23-tsvector-without-index/case.json +24 -0
- package/corpus/cases/23-tsvector-without-index/schema.sql +13 -0
- package/corpus/cases/24-anon-set-role-escalation/case.json +29 -0
- package/corpus/cases/24-anon-set-role-escalation/schema.sql +30 -0
- package/corpus/cases/25-definer-view-bypass/case.json +31 -0
- package/corpus/cases/25-definer-view-bypass/schema.sql +36 -0
- package/corpus/cases/26-invoker-view-no-bypass/case.json +31 -0
- package/corpus/cases/26-invoker-view-no-bypass/schema.sql +44 -0
- package/corpus/cases/27-definer-view-write/case.json +36 -0
- package/corpus/cases/27-definer-view-write/schema.sql +40 -0
- package/corpus/cases/28-invoker-view-no-write/case.json +31 -0
- package/corpus/cases/28-invoker-view-no-write/schema.sql +37 -0
- package/corpus/cases/29-rewrite-rule-bypass/case.json +36 -0
- package/corpus/cases/29-rewrite-rule-bypass/schema.sql +52 -0
- package/corpus/cases/30-instead-nothing-rule/case.json +31 -0
- package/corpus/cases/30-instead-nothing-rule/schema.sql +44 -0
- package/corpus/cases/31-matview-snapshot/case.json +32 -0
- package/corpus/cases/31-matview-snapshot/schema.sql +36 -0
- package/corpus/cases/32-matview-no-rls-no-bypass/case.json +30 -0
- package/corpus/cases/32-matview-no-rls-no-bypass/schema.sql +18 -0
- package/corpus/cases/33-leaky-filter-view/case.json +36 -0
- package/corpus/cases/33-leaky-filter-view/schema.sql +29 -0
- package/corpus/cases/34-barrier-view-no-leak/case.json +32 -0
- package/corpus/cases/34-barrier-view-no-leak/schema.sql +29 -0
- package/corpus/cases/35-column-grant-projection/case.json +27 -0
- package/corpus/cases/35-column-grant-projection/schema.sql +21 -0
- package/corpus/cases/35-policy-function-not-leakproof/case.json +24 -0
- package/corpus/cases/35-policy-function-not-leakproof/schema.sql +27 -0
- package/corpus/cases/36-column-grant-rls-mediated/case.json +27 -0
- package/corpus/cases/36-column-grant-rls-mediated/schema.sql +32 -0
- package/corpus/cases/36-policy-function-leakproof/case.json +24 -0
- package/corpus/cases/36-policy-function-leakproof/schema.sql +22 -0
- package/corpus/cases/37-sort-column-unindexed/case.json +24 -0
- package/corpus/cases/37-sort-column-unindexed/schema.sql +14 -0
- package/corpus/cases/37-unaudited-base-relation/case.json +30 -0
- package/corpus/cases/37-unaudited-base-relation/schema.sql +45 -0
- package/corpus/cases/38-foreign-key-with-index/case.json +22 -0
- package/corpus/cases/38-foreign-key-with-index/schema.sql +17 -0
- package/corpus/cases/38-invoker-view-unaudited-base/case.json +30 -0
- package/corpus/cases/38-invoker-view-unaudited-base/schema.sql +39 -0
- package/corpus/cases/39-definer-view-column-subset/case.json +30 -0
- package/corpus/cases/39-definer-view-column-subset/schema.sql +29 -0
- package/corpus/cases/39-policy-cast-with-expression-index/case.json +23 -0
- package/corpus/cases/39-policy-cast-with-expression-index/schema.sql +19 -0
- package/corpus/cases/40-definer-view-column-overreach/case.json +27 -0
- package/corpus/cases/40-definer-view-column-overreach/schema.sql +29 -0
- package/corpus/cases/40-stable-function-hoisted/case.json +23 -0
- package/corpus/cases/40-stable-function-hoisted/schema.sql +25 -0
- package/corpus/cases/41-index-prefix-not-redundant/case.json +21 -0
- package/corpus/cases/41-index-prefix-not-redundant/schema.sql +15 -0
- package/corpus/cases/41-unreadable-view-body/case.json +33 -0
- package/corpus/cases/41-unreadable-view-body/schema.sql +28 -0
- package/corpus/cases/42-invoker-view-unreadable-body/case.json +30 -0
- package/corpus/cases/42-invoker-view-unreadable-body/schema.sql +27 -0
- package/corpus/cases/42-search-column-indexed/case.json +21 -0
- package/corpus/cases/42-search-column-indexed/schema.sql +12 -0
- package/corpus/cases/43-anon-sequence-grant/case.json +27 -0
- package/corpus/cases/43-anon-sequence-grant/schema.sql +23 -0
- package/corpus/cases/44-serial-sequence-usage/case.json +27 -0
- package/corpus/cases/44-serial-sequence-usage/schema.sql +25 -0
- package/corpus/cases/45-anon-foreign-table/case.json +27 -0
- package/corpus/cases/45-anon-foreign-table/schema.sql +23 -0
- package/corpus/cases/46-unchecked-writable-view/case.json +41 -0
- package/corpus/cases/46-unchecked-writable-view/schema.sql +37 -0
- package/corpus/cases/47-checked-writable-view/case.json +37 -0
- package/corpus/cases/47-checked-writable-view/schema.sql +38 -0
- package/corpus/cases/48-definer-function-reach/case.json +38 -0
- package/corpus/cases/48-definer-function-reach/schema.sql +41 -0
- package/corpus/cases/49-invoker-function-no-reach/case.json +32 -0
- package/corpus/cases/49-invoker-function-no-reach/schema.sql +38 -0
- package/corpus/cases/50-instead-of-trigger-write/case.json +38 -0
- package/corpus/cases/50-instead-of-trigger-write/schema.sql +58 -0
- package/corpus/cases/51-invoker-trigger-no-write/case.json +33 -0
- package/corpus/cases/51-invoker-trigger-no-write/schema.sql +54 -0
- package/corpus/cases/52-revocable-execute-grant/case.json +30 -0
- package/corpus/cases/52-revocable-execute-grant/schema.sql +45 -0
- package/corpus/cases/53-policy-predicate-retains-execute/case.json +23 -0
- package/corpus/cases/53-policy-predicate-retains-execute/schema.sql +49 -0
- package/corpus/index.d.ts +79 -0
- package/corpus/index.js +125 -0
- package/esm/adapters.d.ts +8 -0
- package/esm/adapters.js +6 -0
- package/esm/ast/helpers.d.ts +16 -0
- package/esm/ast/helpers.js +36 -0
- package/esm/ast/parse.d.ts +31 -0
- package/esm/ast/parse.js +82 -0
- package/esm/ast/walk.d.ts +27 -0
- package/esm/ast/walk.js +72 -0
- package/esm/callgraph/baseline.d.ts +28 -0
- package/esm/callgraph/baseline.js +48 -0
- package/esm/callgraph/extract.d.ts +93 -0
- package/esm/callgraph/extract.js +333 -0
- package/esm/callgraph/graph.d.ts +82 -0
- package/esm/callgraph/graph.js +273 -0
- package/esm/checks/anti-patterns.d.ts +53 -0
- package/esm/checks/anti-patterns.js +240 -0
- package/esm/checks/column-grants.d.ts +20 -0
- package/esm/checks/column-grants.js +71 -0
- package/esm/checks/coverage.d.ts +43 -0
- package/esm/checks/coverage.js +104 -0
- package/esm/checks/definer-function.d.ts +91 -0
- package/esm/checks/definer-function.js +452 -0
- package/esm/checks/definer-view.d.ts +167 -0
- package/esm/checks/definer-view.js +382 -0
- package/esm/checks/indexes.d.ts +82 -0
- package/esm/checks/indexes.js +256 -0
- package/esm/checks/lattice.d.ts +179 -0
- package/esm/checks/lattice.js +475 -0
- package/esm/checks/object-acls.d.ts +32 -0
- package/esm/checks/object-acls.js +125 -0
- package/esm/checks/policy-index.d.ts +78 -0
- package/esm/checks/policy-index.js +342 -0
- package/esm/checks/revocable-grants.d.ts +140 -0
- package/esm/checks/revocable-grants.js +373 -0
- package/esm/checks/rls-flags.d.ts +25 -0
- package/esm/checks/rls-flags.js +77 -0
- package/esm/checks/role-reach.d.ts +329 -0
- package/esm/checks/role-reach.js +270 -0
- package/esm/checks/role-trust.d.ts +45 -0
- package/esm/checks/role-trust.js +86 -0
- package/esm/checks/set-role.d.ts +21 -0
- package/esm/checks/set-role.js +63 -0
- package/esm/checks/stats.d.ts +52 -0
- package/esm/checks/stats.js +184 -0
- package/esm/checks/view-exposure.d.ts +68 -0
- package/esm/checks/view-exposure.js +231 -0
- package/esm/checks/view-writes.d.ts +88 -0
- package/esm/checks/view-writes.js +344 -0
- package/esm/ci/baseline.d.ts +104 -0
- package/esm/ci/baseline.js +107 -0
- package/esm/ci/github.d.ts +47 -0
- package/esm/ci/github.js +161 -0
- package/esm/cli/audit.d.ts +3 -0
- package/esm/cli/audit.js +525 -0
- package/esm/cli/baseline.d.ts +3 -0
- package/esm/cli/baseline.js +102 -0
- package/esm/cli/commands.d.ts +2 -0
- package/esm/cli/commands.js +53 -0
- package/esm/cli/doctor.d.ts +3 -0
- package/esm/cli/doctor.js +67 -0
- package/esm/cli/eval.d.ts +3 -0
- package/esm/cli/eval.js +115 -0
- package/esm/cli/print-config.d.ts +3 -0
- package/esm/cli/print-config.js +52 -0
- package/esm/cli/shared.d.ts +43 -0
- package/esm/cli/shared.js +112 -0
- package/esm/cli.d.ts +2 -0
- package/esm/cli.js +67 -0
- package/esm/commands/audit.d.ts +65 -0
- package/esm/commands/audit.js +776 -0
- package/esm/commands/doctor.d.ts +19 -0
- package/esm/commands/doctor.js +178 -0
- package/esm/commands/eval.d.ts +67 -0
- package/esm/commands/eval.js +90 -0
- package/esm/config/fingerprint.d.ts +40 -0
- package/esm/config/fingerprint.js +68 -0
- package/esm/config/loader.d.ts +44 -0
- package/esm/config/loader.js +172 -0
- package/esm/config/presets.d.ts +95 -0
- package/esm/config/presets.js +324 -0
- package/esm/config/resolve.d.ts +47 -0
- package/esm/config/resolve.js +180 -0
- package/esm/config/schema.d.ts +54 -0
- package/esm/config/schema.js +265 -0
- package/esm/config/types.d.ts +562 -0
- package/esm/config/validate.d.ts +14 -0
- package/esm/config/validate.js +122 -0
- package/esm/corpus/index.d.ts +79 -0
- package/esm/corpus/index.js +85 -0
- package/esm/exposure/adapters.d.ts +152 -0
- package/esm/exposure/adapters.js +463 -0
- package/esm/exposure/planes.d.ts +59 -0
- package/esm/exposure/planes.js +144 -0
- package/esm/exposure/reach.d.ts +78 -0
- package/esm/exposure/reach.js +105 -0
- package/esm/exposure/routines.d.ts +36 -0
- package/esm/exposure/routines.js +54 -0
- package/esm/index.d.ts +96 -0
- package/esm/index.js +57 -6
- package/esm/lint/index.d.ts +11 -0
- package/esm/lint/index.js +10 -0
- package/esm/perf/baseline.d.ts +40 -0
- package/esm/perf/baseline.js +83 -0
- package/esm/perf/explain.d.ts +46 -0
- package/esm/perf/explain.js +201 -0
- package/esm/pg/acl.d.ts +72 -0
- package/esm/pg/acl.js +186 -0
- package/esm/pg/behaviors.d.ts +114 -0
- package/esm/pg/behaviors.js +206 -0
- package/esm/pg/exposure.d.ts +74 -0
- package/esm/pg/exposure.js +198 -0
- package/esm/pg/functions.d.ts +52 -0
- package/esm/pg/functions.js +128 -0
- package/esm/pg/indexes.d.ts +192 -0
- package/esm/pg/indexes.js +395 -0
- package/esm/pg/introspect.d.ts +134 -0
- package/esm/pg/introspect.js +274 -0
- package/esm/pg/objects.d.ts +37 -0
- package/esm/pg/objects.js +108 -0
- package/esm/pg/paths.d.ts +114 -0
- package/esm/pg/paths.js +159 -0
- package/esm/pg/proc.d.ts +23 -0
- package/esm/pg/proc.js +55 -0
- package/esm/pg/reach-inputs.d.ts +47 -0
- package/esm/pg/reach-inputs.js +133 -0
- package/esm/pg/roles.d.ts +28 -0
- package/esm/pg/roles.js +50 -0
- package/esm/pg/stats.d.ts +65 -0
- package/esm/pg/stats.js +129 -0
- package/esm/pgpm-test.d.ts +22 -0
- package/esm/pgpm-test.js +39 -0
- package/esm/report/callgraph.d.ts +9 -0
- package/esm/report/callgraph.js +74 -0
- package/esm/report/compare.d.ts +143 -0
- package/esm/report/compare.js +195 -0
- package/esm/report/github.d.ts +74 -0
- package/esm/report/github.js +290 -0
- package/esm/report/json.d.ts +4 -0
- package/esm/report/json.js +3 -0
- package/esm/report/markdown.d.ts +25 -0
- package/esm/report/markdown.js +352 -0
- package/esm/report/pretty.d.ts +14 -0
- package/esm/report/pretty.js +318 -0
- package/esm/report/sarif.d.ts +40 -0
- package/esm/report/sarif.js +189 -0
- package/esm/report/view.d.ts +82 -0
- package/esm/report/view.js +126 -0
- package/esm/rules/registry.d.ts +66 -0
- package/esm/rules/registry.js +562 -0
- package/esm/score/score.d.ts +84 -0
- package/esm/score/score.js +233 -0
- package/esm/score/scorecards.d.ts +68 -0
- package/esm/score/scorecards.js +157 -0
- package/esm/types.d.ts +292 -0
- package/esm/types.js +26 -0
- package/esm/version.d.ts +8 -0
- package/esm/version.js +9 -0
- package/exposure/adapters.d.ts +152 -0
- package/exposure/adapters.js +468 -0
- package/exposure/planes.d.ts +59 -0
- package/exposure/planes.js +151 -0
- package/exposure/reach.d.ts +78 -0
- package/exposure/reach.js +109 -0
- package/exposure/routines.d.ts +36 -0
- package/exposure/routines.js +57 -0
- package/index.d.ts +96 -6
- package/index.js +229 -6
- package/lint/index.d.ts +11 -0
- package/lint/index.js +19 -0
- package/package.json +54 -48
- package/perf/baseline.d.ts +40 -0
- package/perf/baseline.js +92 -0
- package/perf/explain.d.ts +46 -0
- package/perf/explain.js +204 -0
- package/pg/acl.d.ts +72 -0
- package/pg/acl.js +191 -0
- package/pg/behaviors.d.ts +114 -0
- package/pg/behaviors.js +217 -0
- package/pg/exposure.d.ts +74 -0
- package/pg/exposure.js +205 -0
- package/pg/functions.d.ts +52 -0
- package/pg/functions.js +131 -0
- package/pg/indexes.d.ts +192 -0
- package/pg/indexes.js +400 -0
- package/pg/introspect.d.ts +134 -0
- package/pg/introspect.js +280 -0
- package/pg/objects.d.ts +37 -0
- package/pg/objects.js +111 -0
- package/pg/paths.d.ts +114 -0
- package/pg/paths.js +166 -0
- package/pg/proc.d.ts +23 -0
- package/pg/proc.js +58 -0
- package/pg/reach-inputs.d.ts +47 -0
- package/pg/reach-inputs.js +136 -0
- package/pg/roles.d.ts +28 -0
- package/pg/roles.js +54 -0
- package/pg/stats.d.ts +65 -0
- package/pg/stats.js +133 -0
- package/pgpm-test.d.ts +22 -0
- package/pgpm-test.js +42 -0
- package/report/callgraph.d.ts +9 -0
- package/report/callgraph.js +81 -0
- package/report/compare.d.ts +143 -0
- package/report/compare.js +205 -0
- package/report/github.d.ts +74 -0
- package/report/github.js +333 -0
- package/report/json.d.ts +4 -0
- package/report/json.js +6 -0
- package/report/markdown.d.ts +25 -0
- package/report/markdown.js +355 -0
- package/report/pretty.d.ts +14 -0
- package/report/pretty.js +324 -0
- package/report/sarif.d.ts +40 -0
- package/report/sarif.js +193 -0
- package/report/view.d.ts +82 -0
- package/report/view.js +132 -0
- package/rules/registry.d.ts +66 -0
- package/rules/registry.js +569 -0
- package/schema/safegres.schema.json +1119 -0
- package/score/score.d.ts +84 -0
- package/score/score.js +238 -0
- package/score/scorecards.d.ts +68 -0
- package/score/scorecards.js +162 -0
- package/types.d.ts +292 -0
- package/types.js +32 -0
- package/version.d.ts +8 -0
- package/version.js +12 -0
- package/LICENSE +0 -23
- package/admin.d.ts +0 -26
- package/admin.js +0 -182
- package/connect.d.ts +0 -19
- package/connect.js +0 -83
- package/dist/README.md +0 -557
- package/dist/package.json +0 -72
- package/esm/admin.js +0 -178
- package/esm/connect.js +0 -78
- package/esm/manager.js +0 -136
- package/esm/roles.js +0 -32
- package/esm/seed/adapters.js +0 -23
- package/esm/seed/csv.js +0 -44
- package/esm/seed/index.js +0 -16
- package/esm/seed/json.js +0 -18
- package/esm/seed/launchql.js +0 -19
- package/esm/seed/sqitch.js +0 -17
- package/esm/stream.js +0 -43
- package/esm/test-client.js +0 -150
- package/manager.d.ts +0 -25
- package/manager.js +0 -140
- package/roles.d.ts +0 -17
- package/roles.js +0 -38
- package/seed/adapters.d.ts +0 -4
- package/seed/adapters.js +0 -28
- package/seed/csv.d.ts +0 -9
- package/seed/csv.js +0 -49
- package/seed/index.d.ts +0 -16
- package/seed/index.js +0 -33
- package/seed/json.d.ts +0 -6
- package/seed/json.js +0 -21
- package/seed/launchql.d.ts +0 -2
- package/seed/launchql.js +0 -22
- package/seed/sqitch.d.ts +0 -2
- package/seed/sqitch.js +0 -20
- package/seed/types.d.ts +0 -13
- package/stream.d.ts +0 -2
- package/stream.js +0 -46
- package/test-client.d.ts +0 -49
- package/test-client.js +0 -154
- /package/{seed → config}/types.js +0 -0
- /package/esm/{seed → config}/types.js +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Actions output: job summary, workflow annotations, and a sticky PR
|
|
3
|
+
* comment.
|
|
4
|
+
*
|
|
5
|
+
* This is a *renderer*, not a second audit — everything here reads the same
|
|
6
|
+
* `ReportView` the terminal renderer reads, so what CI says and what a
|
|
7
|
+
* developer sees locally cannot disagree.
|
|
8
|
+
*
|
|
9
|
+
* On color: GitHub Markdown has none. The only way to get a real green/red
|
|
10
|
+
* score is an image, so scores render as shields.io badges by default, with
|
|
11
|
+
* 🟢/🟡/🔴 as the offline fallback (`report.github.badges: false`).
|
|
12
|
+
*/
|
|
13
|
+
import type { GithubReportConfig } from '../config/types';
|
|
14
|
+
import type { Grade } from '../config/types';
|
|
15
|
+
import type { Score } from '../score/score';
|
|
16
|
+
import type { Finding, Report } from '../types';
|
|
17
|
+
import { type ViewConfig } from './view';
|
|
18
|
+
/** Marker that makes the PR comment sticky: one comment, edited in place. */
|
|
19
|
+
export declare const COMMENT_MARKER = "<!-- safegres-report -->";
|
|
20
|
+
export interface GithubRenderOptions {
|
|
21
|
+
config?: GithubReportConfig;
|
|
22
|
+
/** Findings that tripped a gate, for `annotations: 'gate-failures'`. */
|
|
23
|
+
gateFailures?: Finding[];
|
|
24
|
+
/** Extra view selection (planes, dimensions) from `report` config. */
|
|
25
|
+
view?: ViewConfig;
|
|
26
|
+
}
|
|
27
|
+
/** A score as a shields.io badge, or as a colored dot when badges are off. */
|
|
28
|
+
export declare function scoreBadge(label: string, score: Score, badges: boolean): string;
|
|
29
|
+
export declare function gradeBadge(label: string, grade: Grade, badges: boolean): string;
|
|
30
|
+
/**
|
|
31
|
+
* The job summary: the badges a reviewer reads first, then the full markdown
|
|
32
|
+
* report. `summary` picks which scores get a badge — `security`, `perf`, and
|
|
33
|
+
* `planes:<glob>` for the secondary planes a team cares about.
|
|
34
|
+
*/
|
|
35
|
+
export declare function renderGithubSummary(report: Report, options?: GithubRenderOptions): string;
|
|
36
|
+
/**
|
|
37
|
+
* GitHub rejects an issue comment body over 65536 characters, and a comment
|
|
38
|
+
* that fails to post is worse than a short one — so a comment carrying the
|
|
39
|
+
* report degrades (verbose → normal → summary → a pointer at the job summary)
|
|
40
|
+
* rather than being truncated at a byte boundary by the API.
|
|
41
|
+
*/
|
|
42
|
+
export declare const COMMENT_MAX_CHARS = 65536;
|
|
43
|
+
/**
|
|
44
|
+
* The sticky PR comment: shorter than the summary by default. A comment is read
|
|
45
|
+
* on the way past, so out of the box it carries the scores, the movement, and
|
|
46
|
+
* what is new, with the full finding tables in the job summary and the SARIF
|
|
47
|
+
* alerts.
|
|
48
|
+
*
|
|
49
|
+
* `comment.sections` chooses what it says. `report` puts the whole markdown
|
|
50
|
+
* report in the comment at `comment.detail` (default `summary`: scores,
|
|
51
|
+
* exposure, counts, the delta and the ratchet verdict — no per-finding tables),
|
|
52
|
+
* which is the same render the job summary uses, so the two cannot disagree.
|
|
53
|
+
*/
|
|
54
|
+
export declare function renderGithubComment(report: Report, options?: GithubRenderOptions): string;
|
|
55
|
+
/**
|
|
56
|
+
* Workflow annotations. Default `gate-failures`: annotating every advisory on
|
|
57
|
+
* a large schema buries the one finding that actually blocked the merge.
|
|
58
|
+
*/
|
|
59
|
+
export declare function renderAnnotations(report: Report, options?: GithubRenderOptions): string[];
|
|
60
|
+
/**
|
|
61
|
+
* Write the summary to `$GITHUB_STEP_SUMMARY` and print the annotations.
|
|
62
|
+
* Returns false when not running under GitHub Actions, so a caller can fall
|
|
63
|
+
* back to stdout rather than silently producing nothing.
|
|
64
|
+
*/
|
|
65
|
+
export declare function emitGithub(report: Report, options?: GithubRenderOptions): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Upsert the sticky comment on the current pull request. No-op (returning a
|
|
68
|
+
* reason) when the environment has no PR or no token: a report is not worth
|
|
69
|
+
* failing a build over, but silence about *why* is how integrations rot.
|
|
70
|
+
*/
|
|
71
|
+
export declare function postStickyComment(body: string, env?: NodeJS.ProcessEnv): Promise<{
|
|
72
|
+
posted: boolean;
|
|
73
|
+
reason?: string;
|
|
74
|
+
}>;
|
package/report/github.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub Actions output: job summary, workflow annotations, and a sticky PR
|
|
4
|
+
* comment.
|
|
5
|
+
*
|
|
6
|
+
* This is a *renderer*, not a second audit — everything here reads the same
|
|
7
|
+
* `ReportView` the terminal renderer reads, so what CI says and what a
|
|
8
|
+
* developer sees locally cannot disagree.
|
|
9
|
+
*
|
|
10
|
+
* On color: GitHub Markdown has none. The only way to get a real green/red
|
|
11
|
+
* score is an image, so scores render as shields.io badges by default, with
|
|
12
|
+
* 🟢/🟡/🔴 as the offline fallback (`report.github.badges: false`).
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.COMMENT_MAX_CHARS = exports.COMMENT_MARKER = void 0;
|
|
49
|
+
exports.scoreBadge = scoreBadge;
|
|
50
|
+
exports.gradeBadge = gradeBadge;
|
|
51
|
+
exports.renderGithubSummary = renderGithubSummary;
|
|
52
|
+
exports.renderGithubComment = renderGithubComment;
|
|
53
|
+
exports.renderAnnotations = renderAnnotations;
|
|
54
|
+
exports.emitGithub = emitGithub;
|
|
55
|
+
exports.postStickyComment = postStickyComment;
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const compare_1 = require("./compare");
|
|
58
|
+
const markdown_1 = require("./markdown");
|
|
59
|
+
const view_1 = require("./view");
|
|
60
|
+
/** Marker that makes the PR comment sticky: one comment, edited in place. */
|
|
61
|
+
exports.COMMENT_MARKER = '<!-- safegres-report -->';
|
|
62
|
+
const GRADE_COLOR = {
|
|
63
|
+
'A+': 'brightgreen',
|
|
64
|
+
A: 'brightgreen',
|
|
65
|
+
B: 'green',
|
|
66
|
+
C: 'yellow',
|
|
67
|
+
D: 'orange',
|
|
68
|
+
F: 'red'
|
|
69
|
+
};
|
|
70
|
+
const GRADE_DOT = {
|
|
71
|
+
'A+': '🟢',
|
|
72
|
+
A: '🟢',
|
|
73
|
+
B: '🟢',
|
|
74
|
+
C: '🟡',
|
|
75
|
+
D: '🟠',
|
|
76
|
+
F: '🔴'
|
|
77
|
+
};
|
|
78
|
+
/** A score as a shields.io badge, or as a colored dot when badges are off. */
|
|
79
|
+
function scoreBadge(label, score, badges) {
|
|
80
|
+
const color = GRADE_COLOR[score.grade] ?? 'lightgrey';
|
|
81
|
+
if (!badges)
|
|
82
|
+
return `${GRADE_DOT[score.grade] ?? '⚪'} **${label} ${score.value} (${score.grade})**`;
|
|
83
|
+
const text = encodeURIComponent(`${score.value} (${score.grade})`);
|
|
84
|
+
const name = encodeURIComponent(label);
|
|
85
|
+
return ``;
|
|
86
|
+
}
|
|
87
|
+
function gradeBadge(label, grade, badges) {
|
|
88
|
+
const color = GRADE_COLOR[grade] ?? 'lightgrey';
|
|
89
|
+
if (!badges)
|
|
90
|
+
return `${GRADE_DOT[grade] ?? '⚪'} **${label} ${grade}**`;
|
|
91
|
+
return `}-${grade}-${color})`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The job summary: the badges a reviewer reads first, then the full markdown
|
|
95
|
+
* report. `summary` picks which scores get a badge — `security`, `perf`, and
|
|
96
|
+
* `planes:<glob>` for the secondary planes a team cares about.
|
|
97
|
+
*/
|
|
98
|
+
function renderGithubSummary(report, options = {}) {
|
|
99
|
+
const config = options.config ?? {};
|
|
100
|
+
const badges = config.badges !== false;
|
|
101
|
+
const selectors = config.summary ?? ['security', 'perf'];
|
|
102
|
+
const viewConfig = {
|
|
103
|
+
planes: planePatterns(selectors),
|
|
104
|
+
...(config.detail ? { detail: config.detail } : {}),
|
|
105
|
+
...options.view
|
|
106
|
+
};
|
|
107
|
+
const view = (0, view_1.selectView)(report, viewConfig);
|
|
108
|
+
const out = [];
|
|
109
|
+
const line = selectedScores(view.scores, selectors)
|
|
110
|
+
.map((s) => scoreBadge(s.label, s.score, badges))
|
|
111
|
+
.join(' ');
|
|
112
|
+
if (line)
|
|
113
|
+
out.push(line, '');
|
|
114
|
+
out.push((0, markdown_1.renderMarkdown)(report, { view: viewConfig }));
|
|
115
|
+
return out.join('\n');
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* GitHub rejects an issue comment body over 65536 characters, and a comment
|
|
119
|
+
* that fails to post is worse than a short one — so a comment carrying the
|
|
120
|
+
* report degrades (verbose → normal → summary → a pointer at the job summary)
|
|
121
|
+
* rather than being truncated at a byte boundary by the API.
|
|
122
|
+
*/
|
|
123
|
+
exports.COMMENT_MAX_CHARS = 65536;
|
|
124
|
+
/**
|
|
125
|
+
* The sticky PR comment: shorter than the summary by default. A comment is read
|
|
126
|
+
* on the way past, so out of the box it carries the scores, the movement, and
|
|
127
|
+
* what is new, with the full finding tables in the job summary and the SARIF
|
|
128
|
+
* alerts.
|
|
129
|
+
*
|
|
130
|
+
* `comment.sections` chooses what it says. `report` puts the whole markdown
|
|
131
|
+
* report in the comment at `comment.detail` (default `summary`: scores,
|
|
132
|
+
* exposure, counts, the delta and the ratchet verdict — no per-finding tables),
|
|
133
|
+
* which is the same render the job summary uses, so the two cannot disagree.
|
|
134
|
+
*/
|
|
135
|
+
function renderGithubComment(report, options = {}) {
|
|
136
|
+
const wanted = options.config?.comment?.detail ?? 'summary';
|
|
137
|
+
const chain = wanted === 'verbose' ? ['verbose', 'normal', 'summary'] : wanted === 'normal' ? ['normal', 'summary'] : ['summary'];
|
|
138
|
+
for (const detail of chain) {
|
|
139
|
+
const body = commentBody(report, options, detail);
|
|
140
|
+
if (body.length <= exports.COMMENT_MAX_CHARS)
|
|
141
|
+
return body;
|
|
142
|
+
}
|
|
143
|
+
return commentBody(report, options, null);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* One comment body. `detail` is the report section's detail, or null to drop
|
|
147
|
+
* the report and say where it went — which is how the size cap is honored.
|
|
148
|
+
*/
|
|
149
|
+
function commentBody(report, options, detail) {
|
|
150
|
+
const config = options.config ?? {};
|
|
151
|
+
const badges = config.badges !== false;
|
|
152
|
+
const sections = new Set(config.comment?.sections ?? ['scores', 'delta', 'new-findings']);
|
|
153
|
+
const selectors = config.summary ?? ['security', 'perf'];
|
|
154
|
+
const view = (0, view_1.selectView)(report, { planes: planePatterns(selectors), ...options.view });
|
|
155
|
+
// `findings` is the old name for `report`; both mean "the markdown report".
|
|
156
|
+
const wantsReport = sections.has('report') || sections.has('findings');
|
|
157
|
+
const withReport = wantsReport && detail != null;
|
|
158
|
+
const out = [exports.COMMENT_MARKER, '## safegres', ''];
|
|
159
|
+
if (sections.has('scores')) {
|
|
160
|
+
out.push(selectedScores(view.scores, selectors)
|
|
161
|
+
.map((s) => scoreBadge(s.label, s.score, badges))
|
|
162
|
+
.join(' '), '');
|
|
163
|
+
// Everything below is in the report too, so it is said once.
|
|
164
|
+
if (report.exposure && !withReport) {
|
|
165
|
+
out.push(report.exposure.known
|
|
166
|
+
? `Exposure (${report.exposure.source}): **${report.exposure.exposedTables}/`
|
|
167
|
+
+ `${report.exposure.totalTables}** tables reachable.`
|
|
168
|
+
: '> [!WARNING]\n> Exposure unknown — the whole database is assumed reachable, '
|
|
169
|
+
+ 'and the score is capped.', '');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (sections.has('planes') && view.planes.length > 0) {
|
|
173
|
+
out.push('| Plane | Kind | Relations | Grade |', '| --- | --- | ---: | --- |', ...view.planes.map((p) => p.skipped
|
|
174
|
+
? `| \`${p.name}\` | ${p.kind} | — | not graded |`
|
|
175
|
+
: `| \`${p.name}\` | ${p.kind} | ${p.exposedTables} | **${p.score.grade}** (${p.score.value}) |`), '');
|
|
176
|
+
}
|
|
177
|
+
// The report renders the comparison (or the reason there is none) itself.
|
|
178
|
+
const wantsDelta = sections.has('delta') && !withReport;
|
|
179
|
+
if (wantsDelta && report.comparison) {
|
|
180
|
+
const cmp = report.comparison;
|
|
181
|
+
const since = (0, compare_1.describeBaseline)(cmp.previous);
|
|
182
|
+
if (cmp.unchanged) {
|
|
183
|
+
out.push(`_No change since ${since}._`, '');
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
out.push(`**Changes since ${since}**`, '');
|
|
187
|
+
for (const [dimension, d] of [
|
|
188
|
+
['security', cmp.security],
|
|
189
|
+
['performance', cmp.perf]
|
|
190
|
+
]) {
|
|
191
|
+
if (!d)
|
|
192
|
+
continue;
|
|
193
|
+
const arrow = d.delta > 0 ? '🟢 ▲' : d.delta < 0 ? '🔴 ▼' : '⚪';
|
|
194
|
+
out.push(`- ${dimension}: ${arrow} ${d.delta > 0 ? '+' : ''}${d.delta.toFixed(1)} `
|
|
195
|
+
+ `(${d.before} → ${d.after}${d.gradeBefore === d.gradeAfter ? '' : `, ${d.gradeBefore} → ${d.gradeAfter}`})`);
|
|
196
|
+
}
|
|
197
|
+
out.push('');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (wantsDelta && report.comparisonSkipped) {
|
|
201
|
+
out.push(`_No delta baseline: ${report.comparisonSkipped}. `
|
|
202
|
+
+ 'The absolute score and the perf baseline still gate this run._', '');
|
|
203
|
+
}
|
|
204
|
+
if (sections.has('new-findings')) {
|
|
205
|
+
const diff = report.perf?.diff;
|
|
206
|
+
// The ratchet's verdict, even when it is "nothing new": a comment that only
|
|
207
|
+
// speaks up on new debt cannot be distinguished from one that never ran.
|
|
208
|
+
// The report carries this line itself, so it is not repeated under it.
|
|
209
|
+
if (diff && !withReport) {
|
|
210
|
+
out.push(`Perf baseline: **${diff.added.length} new**, ${diff.accepted.length} accepted, `
|
|
211
|
+
+ `${diff.removed.length} resolved.`, '');
|
|
212
|
+
}
|
|
213
|
+
const added = diff?.added ?? [];
|
|
214
|
+
if (added.length > 0) {
|
|
215
|
+
out.push(`**${added.length} new performance finding${added.length === 1 ? '' : 's'} since the baseline**`, '', ...added.slice(0, 10).map((f) => `- \`${f.code}\` ${location(f)} — ${f.message}`), '');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (withReport) {
|
|
219
|
+
out.push((0, markdown_1.renderMarkdown)(report, { title: 'Report', view: { detail, ...options.view } }), '');
|
|
220
|
+
}
|
|
221
|
+
else if (wantsReport) {
|
|
222
|
+
out.push('_The report is too large for a PR comment — it is in the job summary and the '
|
|
223
|
+
+ 'reports artifact._', '');
|
|
224
|
+
}
|
|
225
|
+
return out.join('\n');
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Workflow annotations. Default `gate-failures`: annotating every advisory on
|
|
229
|
+
* a large schema buries the one finding that actually blocked the merge.
|
|
230
|
+
*/
|
|
231
|
+
function renderAnnotations(report, options = {}) {
|
|
232
|
+
const mode = options.config?.annotations ?? 'gate-failures';
|
|
233
|
+
if (mode === 'none')
|
|
234
|
+
return [];
|
|
235
|
+
const findings = mode === 'all'
|
|
236
|
+
? report.findings.filter((f) => f.exposed !== false && !f.acknowledged)
|
|
237
|
+
: (options.gateFailures ?? []);
|
|
238
|
+
return findings.map((f) => {
|
|
239
|
+
const level = f.severity === 'critical' || f.severity === 'high' ? 'error' : 'warning';
|
|
240
|
+
const title = `${f.code} ${location(f)}`.trim();
|
|
241
|
+
return `::${level} title=${escapeProperty(title)}::${escapeData(f.message)}`;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Write the summary to `$GITHUB_STEP_SUMMARY` and print the annotations.
|
|
246
|
+
* Returns false when not running under GitHub Actions, so a caller can fall
|
|
247
|
+
* back to stdout rather than silently producing nothing.
|
|
248
|
+
*/
|
|
249
|
+
function emitGithub(report, options = {}) {
|
|
250
|
+
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
|
|
251
|
+
for (const annotation of renderAnnotations(report, options)) {
|
|
252
|
+
process.stdout.write(`${annotation}\n`);
|
|
253
|
+
}
|
|
254
|
+
if (!summaryPath)
|
|
255
|
+
return false;
|
|
256
|
+
fs.appendFileSync(summaryPath, `${renderGithubSummary(report, options)}\n`);
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Upsert the sticky comment on the current pull request. No-op (returning a
|
|
261
|
+
* reason) when the environment has no PR or no token: a report is not worth
|
|
262
|
+
* failing a build over, but silence about *why* is how integrations rot.
|
|
263
|
+
*/
|
|
264
|
+
async function postStickyComment(body, env = process.env) {
|
|
265
|
+
const token = env.GITHUB_TOKEN ?? env.INPUT_GITHUB_TOKEN;
|
|
266
|
+
const repo = env.GITHUB_REPOSITORY;
|
|
267
|
+
if (!token)
|
|
268
|
+
return { posted: false, reason: 'no GITHUB_TOKEN in the environment' };
|
|
269
|
+
if (!repo)
|
|
270
|
+
return { posted: false, reason: 'no GITHUB_REPOSITORY in the environment' };
|
|
271
|
+
const pr = pullRequestNumber(env);
|
|
272
|
+
if (pr == null)
|
|
273
|
+
return { posted: false, reason: 'not running on a pull_request event' };
|
|
274
|
+
const api = env.GITHUB_API_URL ?? 'https://api.github.com';
|
|
275
|
+
const headers = {
|
|
276
|
+
accept: 'application/vnd.github+json',
|
|
277
|
+
authorization: `Bearer ${token}`,
|
|
278
|
+
'content-type': 'application/json'
|
|
279
|
+
};
|
|
280
|
+
const listed = await fetch(`${api}/repos/${repo}/issues/${pr}/comments?per_page=100`, { headers });
|
|
281
|
+
if (!listed.ok) {
|
|
282
|
+
return { posted: false, reason: `GitHub API ${listed.status} listing comments` };
|
|
283
|
+
}
|
|
284
|
+
const comments = (await listed.json());
|
|
285
|
+
const existing = comments.find((c) => c.body?.includes(exports.COMMENT_MARKER));
|
|
286
|
+
const target = existing
|
|
287
|
+
? `${api}/repos/${repo}/issues/comments/${existing.id}`
|
|
288
|
+
: `${api}/repos/${repo}/issues/${pr}/comments`;
|
|
289
|
+
const written = await fetch(target, {
|
|
290
|
+
method: existing ? 'PATCH' : 'POST',
|
|
291
|
+
headers,
|
|
292
|
+
body: JSON.stringify({ body })
|
|
293
|
+
});
|
|
294
|
+
if (!written.ok)
|
|
295
|
+
return { posted: false, reason: `GitHub API ${written.status} writing comment` };
|
|
296
|
+
return { posted: true };
|
|
297
|
+
}
|
|
298
|
+
function pullRequestNumber(env) {
|
|
299
|
+
const eventPath = env.GITHUB_EVENT_PATH;
|
|
300
|
+
if (!eventPath || !fs.existsSync(eventPath))
|
|
301
|
+
return null;
|
|
302
|
+
try {
|
|
303
|
+
const event = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
|
|
304
|
+
return event.pull_request?.number ?? event.issue?.number ?? null;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/** `planes:direct:*` in a summary selector is a plane glob for the view. */
|
|
311
|
+
function planePatterns(selectors) {
|
|
312
|
+
return selectors
|
|
313
|
+
.filter((s) => s.startsWith('planes:'))
|
|
314
|
+
.map((s) => s.slice('planes:'.length));
|
|
315
|
+
}
|
|
316
|
+
function selectedScores(scores, selectors) {
|
|
317
|
+
const planes = planePatterns(selectors);
|
|
318
|
+
return scores.filter((s) => {
|
|
319
|
+
if (s.plane)
|
|
320
|
+
return planes.some((p) => (0, view_1.matchPlane)(p, s.plane.name));
|
|
321
|
+
return selectors.includes(s.id);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
function location(f) {
|
|
325
|
+
return [f.schema, f.table].filter(Boolean).join('.') + (f.policy ? ` (${f.policy})` : '');
|
|
326
|
+
}
|
|
327
|
+
// https://github.com/actions/toolkit/blob/main/packages/core/src/command.ts
|
|
328
|
+
function escapeData(value) {
|
|
329
|
+
return value.replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
|
|
330
|
+
}
|
|
331
|
+
function escapeProperty(value) {
|
|
332
|
+
return escapeData(value).replace(/:/g, '%3A').replace(/,/g, '%2C');
|
|
333
|
+
}
|
package/report/json.d.ts
ADDED
package/report/json.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown rendering (`--format markdown`), for the places CI reads a report:
|
|
3
|
+
* a GitHub job summary (`$GITHUB_STEP_SUMMARY`) or a PR comment.
|
|
4
|
+
*
|
|
5
|
+
* The pretty renderer is a terminal artifact — ANSI colors, fixed-width
|
|
6
|
+
* severity labels, a long scrollable list. A PR comment is read once, by
|
|
7
|
+
* someone deciding whether to look further, so this renders the same report
|
|
8
|
+
* as tables: scores first, then findings grouped by rule, with the noisy
|
|
9
|
+
* parts (internal advisories, accepted debt) collapsed into `<details>`.
|
|
10
|
+
*/
|
|
11
|
+
import type { Report } from '../types';
|
|
12
|
+
import { type ViewConfig } from './view';
|
|
13
|
+
export interface RenderMarkdownOptions {
|
|
14
|
+
/** Scores and counts only — no per-finding tables. */
|
|
15
|
+
summary?: boolean;
|
|
16
|
+
/** Expand internal (non-exposed) advisories instead of collapsing them. */
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
/** Heading text. Default `safegres`. */
|
|
19
|
+
title?: string;
|
|
20
|
+
/** Secondary planes to expand, by name or glob. Default: one summary table. */
|
|
21
|
+
planes?: string[];
|
|
22
|
+
/** Everything else the view layer selects. Beats the flags above. */
|
|
23
|
+
view?: ViewConfig;
|
|
24
|
+
}
|
|
25
|
+
export declare function renderMarkdown(report: Report, options?: RenderMarkdownOptions): string;
|