@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.
Files changed (483) hide show
  1. package/README.md +825 -412
  2. package/adapters.d.ts +8 -0
  3. package/adapters.js +18 -0
  4. package/ast/helpers.d.ts +16 -0
  5. package/ast/helpers.js +40 -0
  6. package/ast/parse.d.ts +31 -0
  7. package/ast/parse.js +87 -0
  8. package/ast/walk.d.ts +27 -0
  9. package/ast/walk.js +79 -0
  10. package/callgraph/baseline.d.ts +28 -0
  11. package/callgraph/baseline.js +55 -0
  12. package/callgraph/extract.d.ts +93 -0
  13. package/callgraph/extract.js +340 -0
  14. package/callgraph/graph.d.ts +82 -0
  15. package/callgraph/graph.js +276 -0
  16. package/checks/anti-patterns.d.ts +53 -0
  17. package/checks/anti-patterns.js +247 -0
  18. package/checks/column-grants.d.ts +20 -0
  19. package/checks/column-grants.js +74 -0
  20. package/checks/coverage.d.ts +43 -0
  21. package/checks/coverage.js +110 -0
  22. package/checks/definer-function.d.ts +91 -0
  23. package/checks/definer-function.js +458 -0
  24. package/checks/definer-view.d.ts +167 -0
  25. package/checks/definer-view.js +392 -0
  26. package/checks/indexes.d.ts +82 -0
  27. package/checks/indexes.js +263 -0
  28. package/checks/lattice.d.ts +179 -0
  29. package/checks/lattice.js +487 -0
  30. package/checks/object-acls.d.ts +32 -0
  31. package/checks/object-acls.js +129 -0
  32. package/checks/policy-index.d.ts +78 -0
  33. package/checks/policy-index.js +349 -0
  34. package/checks/revocable-grants.d.ts +140 -0
  35. package/checks/revocable-grants.js +377 -0
  36. package/checks/rls-flags.d.ts +25 -0
  37. package/checks/rls-flags.js +82 -0
  38. package/checks/role-reach.d.ts +329 -0
  39. package/checks/role-reach.js +277 -0
  40. package/checks/role-trust.d.ts +45 -0
  41. package/checks/role-trust.js +91 -0
  42. package/checks/set-role.d.ts +21 -0
  43. package/checks/set-role.js +66 -0
  44. package/checks/stats.d.ts +52 -0
  45. package/checks/stats.js +192 -0
  46. package/checks/view-exposure.d.ts +68 -0
  47. package/checks/view-exposure.js +236 -0
  48. package/checks/view-writes.d.ts +88 -0
  49. package/checks/view-writes.js +350 -0
  50. package/ci/baseline.d.ts +104 -0
  51. package/ci/baseline.js +111 -0
  52. package/ci/github.d.ts +47 -0
  53. package/ci/github.js +197 -0
  54. package/cli/audit.d.ts +3 -0
  55. package/cli/audit.js +560 -0
  56. package/cli/baseline.d.ts +3 -0
  57. package/cli/baseline.js +104 -0
  58. package/cli/commands.d.ts +2 -0
  59. package/cli/commands.js +60 -0
  60. package/cli/doctor.d.ts +3 -0
  61. package/cli/doctor.js +72 -0
  62. package/cli/eval.d.ts +3 -0
  63. package/cli/eval.js +153 -0
  64. package/cli/print-config.d.ts +3 -0
  65. package/cli/print-config.js +54 -0
  66. package/cli/shared.d.ts +43 -0
  67. package/cli/shared.js +153 -0
  68. package/cli.d.ts +2 -0
  69. package/cli.js +69 -0
  70. package/commands/audit.d.ts +65 -0
  71. package/commands/audit.js +779 -0
  72. package/commands/doctor.d.ts +19 -0
  73. package/commands/doctor.js +181 -0
  74. package/commands/eval.d.ts +67 -0
  75. package/commands/eval.js +93 -0
  76. package/config/fingerprint.d.ts +40 -0
  77. package/config/fingerprint.js +71 -0
  78. package/config/loader.d.ts +44 -0
  79. package/config/loader.js +210 -0
  80. package/config/presets.d.ts +95 -0
  81. package/config/presets.js +327 -0
  82. package/config/resolve.d.ts +47 -0
  83. package/config/resolve.js +192 -0
  84. package/config/schema.d.ts +54 -0
  85. package/config/schema.js +269 -0
  86. package/config/types.d.ts +562 -0
  87. package/config/validate.d.ts +14 -0
  88. package/config/validate.js +125 -0
  89. package/corpus/README.md +83 -0
  90. package/corpus/bootstrap.sql +14 -0
  91. package/corpus/cases/01-anon-write-grant/case.json +26 -0
  92. package/corpus/cases/01-anon-write-grant/schema.sql +19 -0
  93. package/corpus/cases/02-grant-to-public/case.json +25 -0
  94. package/corpus/cases/02-grant-to-public/schema.sql +18 -0
  95. package/corpus/cases/03-rls-off-reachable-by-anon/case.json +30 -0
  96. package/corpus/cases/03-rls-off-reachable-by-anon/schema.sql +13 -0
  97. package/corpus/cases/04-permissive-write-policy/case.json +30 -0
  98. package/corpus/cases/04-permissive-write-policy/schema.sql +21 -0
  99. package/corpus/cases/05-public-read-policy/case.json +25 -0
  100. package/corpus/cases/05-public-read-policy/schema.sql +16 -0
  101. package/corpus/cases/06-update-without-with-check/case.json +25 -0
  102. package/corpus/cases/06-update-without-with-check/schema.sql +19 -0
  103. package/corpus/cases/07-rls-enabled-no-policies/case.json +29 -0
  104. package/corpus/cases/07-rls-enabled-no-policies/schema.sql +14 -0
  105. package/corpus/cases/08-select-grant-no-policy/case.json +25 -0
  106. package/corpus/cases/08-select-grant-no-policy/schema.sql +20 -0
  107. package/corpus/cases/09-write-grant-no-policy/case.json +24 -0
  108. package/corpus/cases/09-write-grant-no-policy/schema.sql +18 -0
  109. package/corpus/cases/10-rls-not-forced/case.json +24 -0
  110. package/corpus/cases/10-rls-not-forced/schema.sql +18 -0
  111. package/corpus/cases/11-session-user-in-policy/case.json +24 -0
  112. package/corpus/cases/11-session-user-in-policy/schema.sql +18 -0
  113. package/corpus/cases/12-volatile-function-in-policy/case.json +24 -0
  114. package/corpus/cases/12-volatile-function-in-policy/schema.sql +21 -0
  115. package/corpus/cases/13-security-definer-policy-wrapper/case.json +24 -0
  116. package/corpus/cases/13-security-definer-policy-wrapper/schema.sql +21 -0
  117. package/corpus/cases/14-dead-policy/case.json +24 -0
  118. package/corpus/cases/14-dead-policy/schema.sql +18 -0
  119. package/corpus/cases/15-unreachable-grant/case.json +24 -0
  120. package/corpus/cases/15-unreachable-grant/schema.sql +18 -0
  121. package/corpus/cases/16-anon-permissive-write-policy/case.json +34 -0
  122. package/corpus/cases/16-anon-permissive-write-policy/schema.sql +17 -0
  123. package/corpus/cases/17-foreign-key-without-index/case.json +24 -0
  124. package/corpus/cases/17-foreign-key-without-index/schema.sql +18 -0
  125. package/corpus/cases/18-policy-column-unindexed/case.json +24 -0
  126. package/corpus/cases/18-policy-column-unindexed/schema.sql +23 -0
  127. package/corpus/cases/19-policy-column-cast/case.json +24 -0
  128. package/corpus/cases/19-policy-column-cast/schema.sql +19 -0
  129. package/corpus/cases/20-stable-function-per-row/case.json +24 -0
  130. package/corpus/cases/20-stable-function-per-row/schema.sql +25 -0
  131. package/corpus/cases/21-table-without-primary-key/case.json +24 -0
  132. package/corpus/cases/21-table-without-primary-key/schema.sql +14 -0
  133. package/corpus/cases/22-redundant-index/case.json +24 -0
  134. package/corpus/cases/22-redundant-index/schema.sql +16 -0
  135. package/corpus/cases/23-tsvector-without-index/case.json +24 -0
  136. package/corpus/cases/23-tsvector-without-index/schema.sql +13 -0
  137. package/corpus/cases/24-anon-set-role-escalation/case.json +29 -0
  138. package/corpus/cases/24-anon-set-role-escalation/schema.sql +30 -0
  139. package/corpus/cases/25-definer-view-bypass/case.json +31 -0
  140. package/corpus/cases/25-definer-view-bypass/schema.sql +36 -0
  141. package/corpus/cases/26-invoker-view-no-bypass/case.json +31 -0
  142. package/corpus/cases/26-invoker-view-no-bypass/schema.sql +44 -0
  143. package/corpus/cases/27-definer-view-write/case.json +36 -0
  144. package/corpus/cases/27-definer-view-write/schema.sql +40 -0
  145. package/corpus/cases/28-invoker-view-no-write/case.json +31 -0
  146. package/corpus/cases/28-invoker-view-no-write/schema.sql +37 -0
  147. package/corpus/cases/29-rewrite-rule-bypass/case.json +36 -0
  148. package/corpus/cases/29-rewrite-rule-bypass/schema.sql +52 -0
  149. package/corpus/cases/30-instead-nothing-rule/case.json +31 -0
  150. package/corpus/cases/30-instead-nothing-rule/schema.sql +44 -0
  151. package/corpus/cases/31-matview-snapshot/case.json +32 -0
  152. package/corpus/cases/31-matview-snapshot/schema.sql +36 -0
  153. package/corpus/cases/32-matview-no-rls-no-bypass/case.json +30 -0
  154. package/corpus/cases/32-matview-no-rls-no-bypass/schema.sql +18 -0
  155. package/corpus/cases/33-leaky-filter-view/case.json +36 -0
  156. package/corpus/cases/33-leaky-filter-view/schema.sql +29 -0
  157. package/corpus/cases/34-barrier-view-no-leak/case.json +32 -0
  158. package/corpus/cases/34-barrier-view-no-leak/schema.sql +29 -0
  159. package/corpus/cases/35-column-grant-projection/case.json +27 -0
  160. package/corpus/cases/35-column-grant-projection/schema.sql +21 -0
  161. package/corpus/cases/35-policy-function-not-leakproof/case.json +24 -0
  162. package/corpus/cases/35-policy-function-not-leakproof/schema.sql +27 -0
  163. package/corpus/cases/36-column-grant-rls-mediated/case.json +27 -0
  164. package/corpus/cases/36-column-grant-rls-mediated/schema.sql +32 -0
  165. package/corpus/cases/36-policy-function-leakproof/case.json +24 -0
  166. package/corpus/cases/36-policy-function-leakproof/schema.sql +22 -0
  167. package/corpus/cases/37-sort-column-unindexed/case.json +24 -0
  168. package/corpus/cases/37-sort-column-unindexed/schema.sql +14 -0
  169. package/corpus/cases/37-unaudited-base-relation/case.json +30 -0
  170. package/corpus/cases/37-unaudited-base-relation/schema.sql +45 -0
  171. package/corpus/cases/38-foreign-key-with-index/case.json +22 -0
  172. package/corpus/cases/38-foreign-key-with-index/schema.sql +17 -0
  173. package/corpus/cases/38-invoker-view-unaudited-base/case.json +30 -0
  174. package/corpus/cases/38-invoker-view-unaudited-base/schema.sql +39 -0
  175. package/corpus/cases/39-definer-view-column-subset/case.json +30 -0
  176. package/corpus/cases/39-definer-view-column-subset/schema.sql +29 -0
  177. package/corpus/cases/39-policy-cast-with-expression-index/case.json +23 -0
  178. package/corpus/cases/39-policy-cast-with-expression-index/schema.sql +19 -0
  179. package/corpus/cases/40-definer-view-column-overreach/case.json +27 -0
  180. package/corpus/cases/40-definer-view-column-overreach/schema.sql +29 -0
  181. package/corpus/cases/40-stable-function-hoisted/case.json +23 -0
  182. package/corpus/cases/40-stable-function-hoisted/schema.sql +25 -0
  183. package/corpus/cases/41-index-prefix-not-redundant/case.json +21 -0
  184. package/corpus/cases/41-index-prefix-not-redundant/schema.sql +15 -0
  185. package/corpus/cases/41-unreadable-view-body/case.json +33 -0
  186. package/corpus/cases/41-unreadable-view-body/schema.sql +28 -0
  187. package/corpus/cases/42-invoker-view-unreadable-body/case.json +30 -0
  188. package/corpus/cases/42-invoker-view-unreadable-body/schema.sql +27 -0
  189. package/corpus/cases/42-search-column-indexed/case.json +21 -0
  190. package/corpus/cases/42-search-column-indexed/schema.sql +12 -0
  191. package/corpus/cases/43-anon-sequence-grant/case.json +27 -0
  192. package/corpus/cases/43-anon-sequence-grant/schema.sql +23 -0
  193. package/corpus/cases/44-serial-sequence-usage/case.json +27 -0
  194. package/corpus/cases/44-serial-sequence-usage/schema.sql +25 -0
  195. package/corpus/cases/45-anon-foreign-table/case.json +27 -0
  196. package/corpus/cases/45-anon-foreign-table/schema.sql +23 -0
  197. package/corpus/cases/46-unchecked-writable-view/case.json +41 -0
  198. package/corpus/cases/46-unchecked-writable-view/schema.sql +37 -0
  199. package/corpus/cases/47-checked-writable-view/case.json +37 -0
  200. package/corpus/cases/47-checked-writable-view/schema.sql +38 -0
  201. package/corpus/cases/48-definer-function-reach/case.json +38 -0
  202. package/corpus/cases/48-definer-function-reach/schema.sql +41 -0
  203. package/corpus/cases/49-invoker-function-no-reach/case.json +32 -0
  204. package/corpus/cases/49-invoker-function-no-reach/schema.sql +38 -0
  205. package/corpus/cases/50-instead-of-trigger-write/case.json +38 -0
  206. package/corpus/cases/50-instead-of-trigger-write/schema.sql +58 -0
  207. package/corpus/cases/51-invoker-trigger-no-write/case.json +33 -0
  208. package/corpus/cases/51-invoker-trigger-no-write/schema.sql +54 -0
  209. package/corpus/cases/52-revocable-execute-grant/case.json +30 -0
  210. package/corpus/cases/52-revocable-execute-grant/schema.sql +45 -0
  211. package/corpus/cases/53-policy-predicate-retains-execute/case.json +23 -0
  212. package/corpus/cases/53-policy-predicate-retains-execute/schema.sql +49 -0
  213. package/corpus/index.d.ts +79 -0
  214. package/corpus/index.js +125 -0
  215. package/esm/adapters.d.ts +8 -0
  216. package/esm/adapters.js +6 -0
  217. package/esm/ast/helpers.d.ts +16 -0
  218. package/esm/ast/helpers.js +36 -0
  219. package/esm/ast/parse.d.ts +31 -0
  220. package/esm/ast/parse.js +82 -0
  221. package/esm/ast/walk.d.ts +27 -0
  222. package/esm/ast/walk.js +72 -0
  223. package/esm/callgraph/baseline.d.ts +28 -0
  224. package/esm/callgraph/baseline.js +48 -0
  225. package/esm/callgraph/extract.d.ts +93 -0
  226. package/esm/callgraph/extract.js +333 -0
  227. package/esm/callgraph/graph.d.ts +82 -0
  228. package/esm/callgraph/graph.js +273 -0
  229. package/esm/checks/anti-patterns.d.ts +53 -0
  230. package/esm/checks/anti-patterns.js +240 -0
  231. package/esm/checks/column-grants.d.ts +20 -0
  232. package/esm/checks/column-grants.js +71 -0
  233. package/esm/checks/coverage.d.ts +43 -0
  234. package/esm/checks/coverage.js +104 -0
  235. package/esm/checks/definer-function.d.ts +91 -0
  236. package/esm/checks/definer-function.js +452 -0
  237. package/esm/checks/definer-view.d.ts +167 -0
  238. package/esm/checks/definer-view.js +382 -0
  239. package/esm/checks/indexes.d.ts +82 -0
  240. package/esm/checks/indexes.js +256 -0
  241. package/esm/checks/lattice.d.ts +179 -0
  242. package/esm/checks/lattice.js +475 -0
  243. package/esm/checks/object-acls.d.ts +32 -0
  244. package/esm/checks/object-acls.js +125 -0
  245. package/esm/checks/policy-index.d.ts +78 -0
  246. package/esm/checks/policy-index.js +342 -0
  247. package/esm/checks/revocable-grants.d.ts +140 -0
  248. package/esm/checks/revocable-grants.js +373 -0
  249. package/esm/checks/rls-flags.d.ts +25 -0
  250. package/esm/checks/rls-flags.js +77 -0
  251. package/esm/checks/role-reach.d.ts +329 -0
  252. package/esm/checks/role-reach.js +270 -0
  253. package/esm/checks/role-trust.d.ts +45 -0
  254. package/esm/checks/role-trust.js +86 -0
  255. package/esm/checks/set-role.d.ts +21 -0
  256. package/esm/checks/set-role.js +63 -0
  257. package/esm/checks/stats.d.ts +52 -0
  258. package/esm/checks/stats.js +184 -0
  259. package/esm/checks/view-exposure.d.ts +68 -0
  260. package/esm/checks/view-exposure.js +231 -0
  261. package/esm/checks/view-writes.d.ts +88 -0
  262. package/esm/checks/view-writes.js +344 -0
  263. package/esm/ci/baseline.d.ts +104 -0
  264. package/esm/ci/baseline.js +107 -0
  265. package/esm/ci/github.d.ts +47 -0
  266. package/esm/ci/github.js +161 -0
  267. package/esm/cli/audit.d.ts +3 -0
  268. package/esm/cli/audit.js +525 -0
  269. package/esm/cli/baseline.d.ts +3 -0
  270. package/esm/cli/baseline.js +102 -0
  271. package/esm/cli/commands.d.ts +2 -0
  272. package/esm/cli/commands.js +53 -0
  273. package/esm/cli/doctor.d.ts +3 -0
  274. package/esm/cli/doctor.js +67 -0
  275. package/esm/cli/eval.d.ts +3 -0
  276. package/esm/cli/eval.js +115 -0
  277. package/esm/cli/print-config.d.ts +3 -0
  278. package/esm/cli/print-config.js +52 -0
  279. package/esm/cli/shared.d.ts +43 -0
  280. package/esm/cli/shared.js +112 -0
  281. package/esm/cli.d.ts +2 -0
  282. package/esm/cli.js +67 -0
  283. package/esm/commands/audit.d.ts +65 -0
  284. package/esm/commands/audit.js +776 -0
  285. package/esm/commands/doctor.d.ts +19 -0
  286. package/esm/commands/doctor.js +178 -0
  287. package/esm/commands/eval.d.ts +67 -0
  288. package/esm/commands/eval.js +90 -0
  289. package/esm/config/fingerprint.d.ts +40 -0
  290. package/esm/config/fingerprint.js +68 -0
  291. package/esm/config/loader.d.ts +44 -0
  292. package/esm/config/loader.js +172 -0
  293. package/esm/config/presets.d.ts +95 -0
  294. package/esm/config/presets.js +324 -0
  295. package/esm/config/resolve.d.ts +47 -0
  296. package/esm/config/resolve.js +180 -0
  297. package/esm/config/schema.d.ts +54 -0
  298. package/esm/config/schema.js +265 -0
  299. package/esm/config/types.d.ts +562 -0
  300. package/esm/config/validate.d.ts +14 -0
  301. package/esm/config/validate.js +122 -0
  302. package/esm/corpus/index.d.ts +79 -0
  303. package/esm/corpus/index.js +85 -0
  304. package/esm/exposure/adapters.d.ts +152 -0
  305. package/esm/exposure/adapters.js +463 -0
  306. package/esm/exposure/planes.d.ts +59 -0
  307. package/esm/exposure/planes.js +144 -0
  308. package/esm/exposure/reach.d.ts +78 -0
  309. package/esm/exposure/reach.js +105 -0
  310. package/esm/exposure/routines.d.ts +36 -0
  311. package/esm/exposure/routines.js +54 -0
  312. package/esm/index.d.ts +96 -0
  313. package/esm/index.js +57 -6
  314. package/esm/lint/index.d.ts +11 -0
  315. package/esm/lint/index.js +10 -0
  316. package/esm/perf/baseline.d.ts +40 -0
  317. package/esm/perf/baseline.js +83 -0
  318. package/esm/perf/explain.d.ts +46 -0
  319. package/esm/perf/explain.js +201 -0
  320. package/esm/pg/acl.d.ts +72 -0
  321. package/esm/pg/acl.js +186 -0
  322. package/esm/pg/behaviors.d.ts +114 -0
  323. package/esm/pg/behaviors.js +206 -0
  324. package/esm/pg/exposure.d.ts +74 -0
  325. package/esm/pg/exposure.js +198 -0
  326. package/esm/pg/functions.d.ts +52 -0
  327. package/esm/pg/functions.js +128 -0
  328. package/esm/pg/indexes.d.ts +192 -0
  329. package/esm/pg/indexes.js +395 -0
  330. package/esm/pg/introspect.d.ts +134 -0
  331. package/esm/pg/introspect.js +274 -0
  332. package/esm/pg/objects.d.ts +37 -0
  333. package/esm/pg/objects.js +108 -0
  334. package/esm/pg/paths.d.ts +114 -0
  335. package/esm/pg/paths.js +159 -0
  336. package/esm/pg/proc.d.ts +23 -0
  337. package/esm/pg/proc.js +55 -0
  338. package/esm/pg/reach-inputs.d.ts +47 -0
  339. package/esm/pg/reach-inputs.js +133 -0
  340. package/esm/pg/roles.d.ts +28 -0
  341. package/esm/pg/roles.js +50 -0
  342. package/esm/pg/stats.d.ts +65 -0
  343. package/esm/pg/stats.js +129 -0
  344. package/esm/pgpm-test.d.ts +22 -0
  345. package/esm/pgpm-test.js +39 -0
  346. package/esm/report/callgraph.d.ts +9 -0
  347. package/esm/report/callgraph.js +74 -0
  348. package/esm/report/compare.d.ts +143 -0
  349. package/esm/report/compare.js +195 -0
  350. package/esm/report/github.d.ts +74 -0
  351. package/esm/report/github.js +290 -0
  352. package/esm/report/json.d.ts +4 -0
  353. package/esm/report/json.js +3 -0
  354. package/esm/report/markdown.d.ts +25 -0
  355. package/esm/report/markdown.js +352 -0
  356. package/esm/report/pretty.d.ts +14 -0
  357. package/esm/report/pretty.js +318 -0
  358. package/esm/report/sarif.d.ts +40 -0
  359. package/esm/report/sarif.js +189 -0
  360. package/esm/report/view.d.ts +82 -0
  361. package/esm/report/view.js +126 -0
  362. package/esm/rules/registry.d.ts +66 -0
  363. package/esm/rules/registry.js +562 -0
  364. package/esm/score/score.d.ts +84 -0
  365. package/esm/score/score.js +233 -0
  366. package/esm/score/scorecards.d.ts +68 -0
  367. package/esm/score/scorecards.js +157 -0
  368. package/esm/types.d.ts +292 -0
  369. package/esm/types.js +26 -0
  370. package/esm/version.d.ts +8 -0
  371. package/esm/version.js +9 -0
  372. package/exposure/adapters.d.ts +152 -0
  373. package/exposure/adapters.js +468 -0
  374. package/exposure/planes.d.ts +59 -0
  375. package/exposure/planes.js +151 -0
  376. package/exposure/reach.d.ts +78 -0
  377. package/exposure/reach.js +109 -0
  378. package/exposure/routines.d.ts +36 -0
  379. package/exposure/routines.js +57 -0
  380. package/index.d.ts +96 -6
  381. package/index.js +229 -6
  382. package/lint/index.d.ts +11 -0
  383. package/lint/index.js +19 -0
  384. package/package.json +54 -48
  385. package/perf/baseline.d.ts +40 -0
  386. package/perf/baseline.js +92 -0
  387. package/perf/explain.d.ts +46 -0
  388. package/perf/explain.js +204 -0
  389. package/pg/acl.d.ts +72 -0
  390. package/pg/acl.js +191 -0
  391. package/pg/behaviors.d.ts +114 -0
  392. package/pg/behaviors.js +217 -0
  393. package/pg/exposure.d.ts +74 -0
  394. package/pg/exposure.js +205 -0
  395. package/pg/functions.d.ts +52 -0
  396. package/pg/functions.js +131 -0
  397. package/pg/indexes.d.ts +192 -0
  398. package/pg/indexes.js +400 -0
  399. package/pg/introspect.d.ts +134 -0
  400. package/pg/introspect.js +280 -0
  401. package/pg/objects.d.ts +37 -0
  402. package/pg/objects.js +111 -0
  403. package/pg/paths.d.ts +114 -0
  404. package/pg/paths.js +166 -0
  405. package/pg/proc.d.ts +23 -0
  406. package/pg/proc.js +58 -0
  407. package/pg/reach-inputs.d.ts +47 -0
  408. package/pg/reach-inputs.js +136 -0
  409. package/pg/roles.d.ts +28 -0
  410. package/pg/roles.js +54 -0
  411. package/pg/stats.d.ts +65 -0
  412. package/pg/stats.js +133 -0
  413. package/pgpm-test.d.ts +22 -0
  414. package/pgpm-test.js +42 -0
  415. package/report/callgraph.d.ts +9 -0
  416. package/report/callgraph.js +81 -0
  417. package/report/compare.d.ts +143 -0
  418. package/report/compare.js +205 -0
  419. package/report/github.d.ts +74 -0
  420. package/report/github.js +333 -0
  421. package/report/json.d.ts +4 -0
  422. package/report/json.js +6 -0
  423. package/report/markdown.d.ts +25 -0
  424. package/report/markdown.js +355 -0
  425. package/report/pretty.d.ts +14 -0
  426. package/report/pretty.js +324 -0
  427. package/report/sarif.d.ts +40 -0
  428. package/report/sarif.js +193 -0
  429. package/report/view.d.ts +82 -0
  430. package/report/view.js +132 -0
  431. package/rules/registry.d.ts +66 -0
  432. package/rules/registry.js +569 -0
  433. package/schema/safegres.schema.json +1119 -0
  434. package/score/score.d.ts +84 -0
  435. package/score/score.js +238 -0
  436. package/score/scorecards.d.ts +68 -0
  437. package/score/scorecards.js +162 -0
  438. package/types.d.ts +292 -0
  439. package/types.js +32 -0
  440. package/version.d.ts +8 -0
  441. package/version.js +12 -0
  442. package/LICENSE +0 -23
  443. package/admin.d.ts +0 -26
  444. package/admin.js +0 -182
  445. package/connect.d.ts +0 -19
  446. package/connect.js +0 -83
  447. package/dist/README.md +0 -557
  448. package/dist/package.json +0 -72
  449. package/esm/admin.js +0 -178
  450. package/esm/connect.js +0 -78
  451. package/esm/manager.js +0 -136
  452. package/esm/roles.js +0 -32
  453. package/esm/seed/adapters.js +0 -23
  454. package/esm/seed/csv.js +0 -44
  455. package/esm/seed/index.js +0 -16
  456. package/esm/seed/json.js +0 -18
  457. package/esm/seed/launchql.js +0 -19
  458. package/esm/seed/sqitch.js +0 -17
  459. package/esm/stream.js +0 -43
  460. package/esm/test-client.js +0 -150
  461. package/manager.d.ts +0 -25
  462. package/manager.js +0 -140
  463. package/roles.d.ts +0 -17
  464. package/roles.js +0 -38
  465. package/seed/adapters.d.ts +0 -4
  466. package/seed/adapters.js +0 -28
  467. package/seed/csv.d.ts +0 -9
  468. package/seed/csv.js +0 -49
  469. package/seed/index.d.ts +0 -16
  470. package/seed/index.js +0 -33
  471. package/seed/json.d.ts +0 -6
  472. package/seed/json.js +0 -21
  473. package/seed/launchql.d.ts +0 -2
  474. package/seed/launchql.js +0 -22
  475. package/seed/sqitch.d.ts +0 -2
  476. package/seed/sqitch.js +0 -20
  477. package/seed/types.d.ts +0 -13
  478. package/stream.d.ts +0 -2
  479. package/stream.js +0 -46
  480. package/test-client.d.ts +0 -49
  481. package/test-client.js +0 -154
  482. /package/{seed → config}/types.js +0 -0
  483. /package/esm/{seed → config}/types.js +0 -0
@@ -0,0 +1,352 @@
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 { describeBaseline, formatDelta } from './compare';
12
+ import { selectView } from './view';
13
+ const SEV_ICON = {
14
+ critical: '🔴',
15
+ high: '🟠',
16
+ medium: '🟡',
17
+ low: '🔵',
18
+ info: '⚪'
19
+ };
20
+ /**
21
+ * Movement, colored by whether it is good news — the severity icons already
22
+ * spend red on "this is serious", so a delta that reuses red for "+15 info
23
+ * findings" reads as a fire when nothing is burning. Green is fewer findings /
24
+ * a higher score, red is the reverse, grey is neither.
25
+ */
26
+ function movement(delta, betterWhen, digits = 0) {
27
+ if (delta === 0)
28
+ return `⚪ ${formatDelta(0)}`;
29
+ const improved = betterWhen === 'lower' ? delta < 0 : delta > 0;
30
+ const arrow = delta > 0 ? '▲' : '▼';
31
+ return `${improved ? '🟢' : '🔴'} ${arrow} ${formatDelta(delta, digits)}`;
32
+ }
33
+ export function renderMarkdown(report, options = {}) {
34
+ const view = selectView(report, {
35
+ detail: options.summary ? 'summary' : options.verbose ? 'verbose' : 'normal',
36
+ ...(options.planes ? { planes: options.planes } : {}),
37
+ ...options.view
38
+ });
39
+ const out = [`## ${options.title ?? 'safegres'}`, ''];
40
+ out.push(...scoreTable(report, options), '');
41
+ if (report.exposure) {
42
+ const { known, source, exposedTables, totalTables, roles, unaddressable } = report.exposure;
43
+ out.push(known
44
+ ? `Exposure (${source}): **${exposedTables}/${totalTables}** tables reachable`
45
+ + `${roles && roles.length > 0 ? ` via \`${roles.join('`, `')}\`` : ''}.`
46
+ + (unaddressable && unaddressable.length > 0
47
+ ? ` ${unaddressable.length} relation(s) in those schemas are declared unaddressable`
48
+ + ` by the API: ${unaddressable.map((r) => `\`${r.schema}.${r.table}\``).join(', ')}.`
49
+ : '')
50
+ : '> [!WARNING]\n> Exposure unknown — the entire database is assumed reachable and the score is capped.', '');
51
+ }
52
+ if (view.has('scorecards'))
53
+ out.push(...scorecardSection(view), '');
54
+ if (view.has('planes'))
55
+ out.push(...planeSection(view), '');
56
+ out.push(countsTable(report), '');
57
+ if (report.comparison)
58
+ out.push(...comparisonSection(report.comparison), '');
59
+ else if (report.comparisonSkipped)
60
+ out.push(...noBaselineSection(report.comparisonSkipped), '');
61
+ if (view.detail === 'summary') {
62
+ // The ratchet's verdict is the one perf number a summary reader needs:
63
+ // the absolute score is dominated by accepted debt, the delta is not.
64
+ const diff = report.perf?.diff;
65
+ if (diff) {
66
+ out.push(`Perf baseline: **${diff.added.length} new**, ${diff.accepted.length} accepted, `
67
+ + `${diff.removed.length} resolved.`, '');
68
+ }
69
+ return out.join('\n');
70
+ }
71
+ out.push(...findingSection('Security findings', [...view.security.exposed, ...view.security.internal], options), '');
72
+ if (report.roleAccess && report.roleAccess.roles.length > 0) {
73
+ out.push(...roleAccessSection(report.roleAccess.roles), '');
74
+ }
75
+ if (report.perf) {
76
+ out.push(...findingSection('Performance findings', report.perf.findings, options));
77
+ const { paths, stats, explain, diff } = report.perf;
78
+ const notes = [];
79
+ if (paths && paths.writeOnceShaped > 0) {
80
+ const acted = {
81
+ report: 'X1 still asks for an index on each of them',
82
+ demote: 'their X1 findings are demoted to `info`',
83
+ suppress: 'their X1 findings are suppressed'
84
+ }[paths.onWriteOncePointer];
85
+ notes.push(`Access paths: of ${paths.total} foreign keys, ${paths.read} are named by an RLS policy `
86
+ + `or a view, and ${paths.writeOnceShaped} across ${paths.tables} tables look like `
87
+ + `write-once provisioning pointers — ${acted}. A shape is not proof that nothing `
88
+ + 'queries the relation (`perf.paths.onWriteOncePointer` to change what X1 does).');
89
+ }
90
+ if (stats) {
91
+ notes.push(`Runtime statistics: ${stats.tables} tables, counters since ${stats.statsReset ?? 'server start'}`
92
+ + `${stats.scored ? '' : ' (advisory — `includeStats` is false)'}.`);
93
+ for (const note of stats.notes ?? [])
94
+ notes.push(note);
95
+ }
96
+ if (explain) {
97
+ notes.push(explain.unavailable
98
+ ?? `Planner proof: ${explain.confirmed} confirmed, ${explain.refuted} refuted, `
99
+ + `${explain.inconclusive} inconclusive of ${explain.probed} probed.`);
100
+ }
101
+ if (notes.length > 0)
102
+ out.push('', notes.map((n) => `_${n}_`).join(' \n'));
103
+ if (diff) {
104
+ out.push('', '### Performance vs baseline', '');
105
+ out.push(diff.added.length === 0
106
+ ? `No new perf debt (${diff.accepted.length} accepted, ${diff.removed.length} fixed).`
107
+ : `**${diff.added.length} new** since the baseline `
108
+ + `(${diff.accepted.length} accepted, ${diff.removed.length} fixed):`);
109
+ if (diff.added.length > 0)
110
+ out.push('', findingTable(diff.added));
111
+ }
112
+ out.push('');
113
+ }
114
+ return out.join('\n');
115
+ }
116
+ /**
117
+ * The other ways in, as one table. Secondary planes are advisory by
118
+ * construction — an internal role reaching internal tables is the schema
119
+ * working as designed — so they read as context under the headline rather
120
+ * than as a second verdict competing with it.
121
+ */
122
+ /**
123
+ * The other named scores. Same findings, different questions — which is the
124
+ * point: a team that gates on `anon-surface` is not being asked to care
125
+ * about the headline, and `raw` is there so nobody has to trust that the
126
+ * config was written in good faith.
127
+ */
128
+ function scorecardSection(view) {
129
+ const out = [
130
+ '### Scorecards',
131
+ '',
132
+ '_The same findings, scored by question. Nothing here filters the report — '
133
+ + 'a scorecard decides what a number is *about*, never what is reported._',
134
+ '',
135
+ '| Scorecard | Score | Grade | Findings | Question |',
136
+ '| --- | ---: | --- | ---: | --- |'
137
+ ];
138
+ for (const card of view.scorecards) {
139
+ out.push(`| \`${card.name}\` | ${card.score.value} | **${card.score.grade}** | ${card.findings} `
140
+ + `| ${card.description ?? card.title ?? ''} |`);
141
+ }
142
+ return out;
143
+ }
144
+ function planeSection(view) {
145
+ const out = [
146
+ '### Other access planes',
147
+ '',
148
+ '_Advisory: these are not the score above. The headline grades the declared API surface; '
149
+ + 'a plane grades what somebody reaches without going through it._',
150
+ '',
151
+ '| Plane | Kind | Reaches | Relations | Score | Grade |',
152
+ '| --- | --- | --- | ---: | ---: | --- |'
153
+ ];
154
+ for (const plane of view.planes)
155
+ out.push(planeRow(plane));
156
+ for (const plane of view.expandedPlanes) {
157
+ if (plane.skipped || plane.score.deductions.length === 0)
158
+ continue;
159
+ out.push('', `#### Plane \`${plane.name}\` by rule`, '', '| Rule | Findings | Points | Grade | Payoff |', '| --- | ---: | ---: | --- | ---: |', ...plane.score.deductions.map(deductionRow));
160
+ }
161
+ return out;
162
+ }
163
+ function planeRow(plane) {
164
+ const who = plane.roles && plane.roles.length > 0
165
+ ? plane.roles.map((r) => `\`${r}\``).join(', ')
166
+ : plane.schemas.map((s) => `\`${s}\``).join(', ') || '—';
167
+ if (plane.skipped) {
168
+ return `| \`${plane.name}\` | ${plane.kind} | ${who} | — | — | not graded — ${plane.skipped} |`;
169
+ }
170
+ const via = plane.reachedVia ? ` (via ${plane.reachedVia})` : '';
171
+ return `| \`${plane.name}\` | ${plane.kind} | ${who}${via} | ${plane.exposedTables} `
172
+ + `| **${plane.score.value}** | **${plane.score.grade}** |`;
173
+ }
174
+ /**
175
+ * The direct answer to "what can role X access?" — effective grants
176
+ * (direct, TO PUBLIC, inherited), classified by whether RLS mediates them.
177
+ */
178
+ function roleAccessSection(roles) {
179
+ const out = ['### Role access', ''];
180
+ for (const entry of roles) {
181
+ out.push(`\`${entry.role}\`: **${entry.accessibleTables}** relation(s) accessible — `
182
+ + `${entry.unmediated.length} unmediated (no RLS), ${entry.mediated} policy-mediated`
183
+ + `${entry.dead > 0 ? `, ${entry.dead} dead (RLS default-deny)` : ''}.`, '');
184
+ if (entry.unmediated.length > 0) {
185
+ out.push('| Relation | Privileges | Via |', '| --- | --- | --- |', ...entry.unmediated.map((r) => `| \`${r.schema}.${r.table}\` | ${r.privileges.join(', ')}`
186
+ + `${r.columns ? ` (${r.columns.join(', ')})` : ''} | ${r.via} |`), '');
187
+ }
188
+ }
189
+ return out;
190
+ }
191
+ function scoreTable(report, options) {
192
+ const cmp = report.comparison;
193
+ const rows = [];
194
+ if (report.score)
195
+ rows.push(scoreRow('Security', report.score, !!cmp, cmp?.security));
196
+ if (report.perf)
197
+ rows.push(scoreRow('Performance', report.perf.score, !!cmp, cmp?.perf));
198
+ if (rows.length === 0)
199
+ return [];
200
+ const deltaHeader = cmp ? ` Δ vs ${cmp.previous.ref ?? 'previous run'} |` : '';
201
+ return [
202
+ `| Dimension | Score | Grade |${deltaHeader} Top deductions |`,
203
+ `| --- | --- | --- |${cmp ? ' --- |' : ''} --- |`,
204
+ ...rows,
205
+ '',
206
+ ...ruleTable('Security', report.score, options),
207
+ ...ruleTable('Performance', report.perf?.score, options)
208
+ ];
209
+ }
210
+ function scoreRow(label, score, compared, delta) {
211
+ const top = score.deductions
212
+ .filter((d) => !d.unscored)
213
+ .slice(0, 3)
214
+ .map((d) => `\`${d.code}\` −${d.points} (×${d.count})`)
215
+ .join(', ');
216
+ const capped = score.cappedByUnknownExposure ? ' (capped)' : '';
217
+ // The column exists for the whole table or not at all: a dimension the
218
+ // previous run didn't have still needs its cell.
219
+ const deltaCell = compared ? ` ${delta ? scoreDeltaCell(delta) : '— (new)'} |` : '';
220
+ return `| ${label} | **${score.value}**${capped} | **${score.grade}** |${deltaCell} ${top || '—'} |`;
221
+ }
222
+ /**
223
+ * The movement, made legible at a glance: an arrow for the direction, the
224
+ * grade transition when it crossed a band, and the finding count either way —
225
+ * a score can hold still while findings move underneath it.
226
+ */
227
+ function scoreDeltaCell(d) {
228
+ const score = d.delta === 0 ? '⚪ no change' : `${movement(d.delta, 'higher', 1)} (from ${d.before})`;
229
+ const grade = d.gradeBefore === d.gradeAfter ? '' : ` · ${d.gradeBefore} → ${d.gradeAfter}`;
230
+ const findings = d.findingsAfter === d.findingsBefore
231
+ ? ''
232
+ : ` · ${d.findingsBefore} → ${d.findingsAfter} findings `
233
+ + `${movement(d.findingsAfter - d.findingsBefore, 'lower')}`;
234
+ return `${score}${grade}${findings}`;
235
+ }
236
+ /**
237
+ * A rule with no previous reading is not movement: the previous run simply did
238
+ * not report the code (a rule added since, or a dimension it never ran).
239
+ */
240
+ function ruleDeltaCell(r) {
241
+ return r.unmeasuredBefore ? '⚪ not measured before' : movement(r.delta, 'lower');
242
+ }
243
+ /**
244
+ * Rendered after the counts so the two tables can be read together: what the
245
+ * numbers are, then which way they moved.
246
+ */
247
+ function comparisonSection(cmp) {
248
+ const since = describeBaseline(cmp.previous);
249
+ if (cmp.unchanged)
250
+ return ['', `_No change since ${since}._`];
251
+ const out = [
252
+ '',
253
+ `<details open><summary>Changes since ${since}</summary>`,
254
+ '',
255
+ '🟢 improvement · 🔴 regression · ⚪ no change or no previous reading',
256
+ ''
257
+ ];
258
+ const severities = ['critical', 'high', 'medium', 'low', 'info'];
259
+ const moved = severities.filter((sev) => cmp.summary[sev].delta !== 0);
260
+ if (moved.length > 0) {
261
+ out.push(`| ${moved.map((sev) => `${SEV_ICON[sev]} ${sev}`).join(' | ')} |`, `| ${moved.map(() => '---').join(' | ')} |`, `| ${moved
262
+ .map((sev) => {
263
+ const s = cmp.summary[sev];
264
+ return `${s.before} → **${s.after}** ${movement(s.delta, 'lower')}`;
265
+ })
266
+ .join(' | ')} |`, '');
267
+ }
268
+ if (cmp.rules.length > 0) {
269
+ out.push('| Rule | Dimension | Before | After | Δ |', '| --- | --- | ---: | ---: | --- |', ...cmp.rules.map((r) => `| \`${r.code}\` | ${r.dimension} | ${r.unmeasuredBefore ? '—' : r.before} | `
270
+ + `${r.after} | ${ruleDeltaCell(r)} |`), '');
271
+ }
272
+ out.push('</details>');
273
+ return out;
274
+ }
275
+ /**
276
+ * A delta was asked for and none was trustworthy. Said out loud, because an
277
+ * absent delta is indistinguishable from "nothing changed" — and because the
278
+ * gates that do not read the comparison are still in force.
279
+ */
280
+ function noBaselineSection(reason) {
281
+ return [
282
+ '',
283
+ `> [!NOTE]`,
284
+ `> No delta baseline: ${reason}. The absolute score and the perf baseline still gate this run.`
285
+ ];
286
+ }
287
+ /**
288
+ * Per-rule breakdown. `Payoff` is what the dimension score becomes if that
289
+ * rule alone goes to zero — the number worth ranking work by, and not
290
+ * proportional to the finding count, because the curve is exponential.
291
+ */
292
+ /**
293
+ * One rule's row. Findings and fixes are different numbers when a rule fans
294
+ * out over a single repair, and points are charged on the second.
295
+ */
296
+ function deductionRow(d) {
297
+ const found = d.units === undefined ? `${d.count}` : `${d.count} (${d.units} fixes)`;
298
+ const points = d.capped ? `−${d.points} (capped)` : `−${d.points}`;
299
+ return d.unscored
300
+ ? `| \`${d.code}\` | ${found} | — | — | *unscored* |`
301
+ : `| \`${d.code}\` | ${found} | ${points} | **${d.grade}** | +${d.potential.toFixed(1)} |`;
302
+ }
303
+ function ruleTable(label, score, options) {
304
+ if (!score || score.deductions.length === 0)
305
+ return [];
306
+ const table = [
307
+ '| Rule | Findings | Points | Grade | Payoff |',
308
+ '| --- | ---: | ---: | --- | ---: |',
309
+ ...score.deductions.map(deductionRow)
310
+ ];
311
+ return options.verbose
312
+ ? [`### ${label} by rule`, '', ...table, '']
313
+ : [`<details><summary>${label} by rule</summary>`, '', ...table, '', '</details>', ''];
314
+ }
315
+ function countsTable(report) {
316
+ const s = report.summary;
317
+ return [
318
+ '| 🔴 critical | 🟠 high | 🟡 medium | 🔵 low | ⚪ info |',
319
+ '| --- | --- | --- | --- | --- |',
320
+ `| ${s.critical} | ${s.high} | ${s.medium} | ${s.low} | ${s.info} |`
321
+ ].join('\n');
322
+ }
323
+ function findingSection(heading, findings, options) {
324
+ const out = [`### ${heading}`, ''];
325
+ const exposed = findings.filter((f) => f.exposed !== false);
326
+ const internal = findings.filter((f) => f.exposed === false);
327
+ if (exposed.length === 0)
328
+ out.push('No findings.');
329
+ else
330
+ out.push(findingTable(exposed));
331
+ if (internal.length > 0) {
332
+ const table = findingTable(internal);
333
+ out.push('', options.verbose
334
+ ? table
335
+ : `<details><summary>${internal.length} internal `
336
+ + `advisor${internal.length === 1 ? 'y' : 'ies'} — not exposed via any API, `
337
+ + `excluded from the score</summary>\n\n${table}\n\n</details>`);
338
+ }
339
+ return out;
340
+ }
341
+ function findingTable(findings) {
342
+ const rows = findings.map((f) => {
343
+ const where = [f.schema, f.table].filter(Boolean).join('.') || '—';
344
+ const policy = f.policy ? ` \`${f.policy}\`` : '';
345
+ return `| ${SEV_ICON[f.severity]} ${f.severity} | \`${f.code}\` | ${where}${policy} | ${escapeCell(f.message)} |`;
346
+ });
347
+ return ['| Severity | Rule | Relation | Finding |', '| --- | --- | --- | --- |', ...rows].join('\n');
348
+ }
349
+ /** Keep a message inside its table cell: no pipes, no line breaks. */
350
+ function escapeCell(value) {
351
+ return value.replace(/\|/g, '\\|').replace(/\s*\n\s*/g, ' ');
352
+ }
@@ -0,0 +1,14 @@
1
+ import type { Report } from '../types';
2
+ import { type ViewConfig } from './view';
3
+ export interface RenderPrettyOptions {
4
+ color?: boolean;
5
+ /** Only render the exposure line, score, and severity summary — no per-finding lines. */
6
+ summary?: boolean;
7
+ /** Expand the internal (non-exposed) advisories instead of collapsing them to a count. */
8
+ verbose?: boolean;
9
+ /** Secondary planes to expand, by name or glob. Default: summarized in one line each. */
10
+ planes?: string[];
11
+ /** Everything else the view layer selects. Beats the flags above. */
12
+ view?: ViewConfig;
13
+ }
14
+ export declare function renderPretty(report: Report, options?: RenderPrettyOptions): string;