@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.
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,53 @@
1
+ import { Logger } from '@pgpmjs/logger';
2
+ import { extractFirst } from 'inquirerer';
3
+ import audit from './audit';
4
+ import baseline from './baseline';
5
+ import doctor from './doctor';
6
+ import evalCommand from './eval';
7
+ import printConfig from './print-config';
8
+ const log = new Logger('safegres');
9
+ const usage = `
10
+ safegres — Postgres security and performance auditor
11
+
12
+ Usage:
13
+ safegres <command> [OPTIONS]
14
+
15
+ Commands:
16
+ audit Audit grants, RLS flags, policy coverage, and anti-patterns
17
+ lint Alias for audit, for a package.json script
18
+ perf Audit index hygiene and policy cost (audit --perf)
19
+ baseline Choose the report a delta is measured against (CI)
20
+ doctor Diagnose environment, connection, and configuration
21
+ eval Grade the auditor against a corpus with known answers
22
+ print-config Show the resolved effective configuration
23
+ help Show this help message
24
+
25
+ Run \`safegres <command> --help\` for command-specific options.
26
+ `;
27
+ const commandMap = {
28
+ audit,
29
+ lint: audit,
30
+ perf: (argv, prompter, options) => audit({ ...argv, perf: true }, prompter, options),
31
+ baseline,
32
+ doctor,
33
+ eval: evalCommand,
34
+ 'print-config': printConfig
35
+ };
36
+ export const commands = async (argv, prompter, options) => {
37
+ const { first: command, newArgv } = extractFirst(argv);
38
+ if (!command && (argv.help || argv.h)) {
39
+ process.stdout.write(usage);
40
+ return;
41
+ }
42
+ if (!command || command === 'help') {
43
+ process.stdout.write(usage);
44
+ return;
45
+ }
46
+ const handler = commandMap[command];
47
+ if (!handler) {
48
+ log.error(`Unknown command: ${command}`);
49
+ process.stdout.write(usage);
50
+ process.exit(2);
51
+ }
52
+ await handler(newArgv, prompter, options);
53
+ };
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: ParsedArgs, _prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
3
+ export default _default;
@@ -0,0 +1,67 @@
1
+ import yanse from 'yanse';
2
+ import { doctor } from '../commands/doctor';
3
+ import { buildClient, configParamsFromArgv } from './shared';
4
+ const usage = `
5
+ safegres doctor — diagnose the environment, connection, and configuration
6
+
7
+ safegres doctor [OPTIONS]
8
+
9
+ Connection (same flags as \`safegres audit\`):
10
+ --connection <url> Full PostgreSQL connection string
11
+ --host / --port / --user / --password / --database
12
+
13
+ Configuration:
14
+ --config <path> Explicit config file
15
+ --preset <name> Apply a built-in preset
16
+ --rule <CODE=SETTING> Retune a rule (repeatable)
17
+
18
+ Options:
19
+ --no-color Disable ANSI colors
20
+ --help, -h Show this help message
21
+
22
+ Checks: config discovery & rule validation, pgsql-parser availability,
23
+ connection, catalog access (pg_policy), audit blind spots (BYPASSRLS),
24
+ and whether any tables actually have RLS enabled.
25
+ `;
26
+ const STATUS_LABEL = {
27
+ ok: 'OK ',
28
+ warn: 'WARN',
29
+ fail: 'FAIL'
30
+ };
31
+ export default async (argv, _prompter, _options) => {
32
+ if (argv.help || argv.h) {
33
+ process.stdout.write(usage);
34
+ return;
35
+ }
36
+ const colorEnabled = argv.color !== false;
37
+ const paint = (status, s) => {
38
+ if (!colorEnabled)
39
+ return s;
40
+ if (status === 'ok')
41
+ return yanse.green(s);
42
+ if (status === 'warn')
43
+ return yanse.yellow(s);
44
+ return yanse.bold(yanse.red(s));
45
+ };
46
+ let client = buildClient(argv);
47
+ try {
48
+ await client.connect();
49
+ }
50
+ catch {
51
+ client = null;
52
+ }
53
+ try {
54
+ const report = await doctor(client, configParamsFromArgv(argv));
55
+ for (const check of report.checks) {
56
+ process.stdout.write(`[${paint(check.status, STATUS_LABEL[check.status])}] ${check.name.padEnd(12)} ${check.detail}\n`);
57
+ }
58
+ process.stdout.write('\n');
59
+ process.stdout.write(report.ok ? 'doctor: all checks passed\n' : 'doctor: some checks failed\n');
60
+ if (!report.ok)
61
+ process.exit(1);
62
+ }
63
+ finally {
64
+ if (client)
65
+ await client.end();
66
+ }
67
+ };
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: ParsedArgs, _prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
3
+ export default _default;
@@ -0,0 +1,115 @@
1
+ import * as path from 'path';
2
+ import yanse from 'yanse';
3
+ import { runEval } from '../commands/eval';
4
+ import { configPathBase, loadConfig } from '../config/loader';
5
+ import { loadCorpus } from '../corpus';
6
+ import { buildClient, csvList } from './shared';
7
+ const usage = `
8
+ safegres eval — grade the auditor against a corpus with known answers
9
+
10
+ safegres eval [OPTIONS]
11
+
12
+ Deploys each corpus case into the connected database, audits it under a sealed
13
+ preset, and grades the report against the case's answer key: every expected
14
+ finding present (recall), nothing the case forbids (precision). Exits non-zero
15
+ if any case fails. Each case's schemas are dropped afterwards.
16
+
17
+ Connection (same flags as \`safegres audit\`):
18
+ --connection <url> Full PostgreSQL connection string
19
+ --host / --port / --user / --password / --database
20
+
21
+ Options:
22
+ --preset <name> Preset every case is graded under (default: recommended)
23
+ --corpus <dir> Corpus directory of <id>/{case.json,schema.sql}
24
+ --case <id> Run only these cases; id or id prefix, comma-separated
25
+ --list List the corpus without connecting to a database
26
+ --keep Leave the case schemas in the database
27
+ --json Emit the machine-readable result instead of a table
28
+ --no-color Disable ANSI colors
29
+ --help, -h Show this help message
30
+
31
+ Config: a discovered safegres config may set \`eval.corpus\`, \`eval.preset\` and
32
+ \`eval.cases\` — what to run. It cannot retune the rules: cases are always
33
+ graded by the named preset alone, or the corpus would be measuring itself.
34
+ `;
35
+ /**
36
+ * Discovery is used for *selection only* (which corpus, which preset, which
37
+ * cases). Grading always loads the preset sealed, so nothing in the working
38
+ * tree can change the answers.
39
+ */
40
+ function evalDefaults(configFile) {
41
+ try {
42
+ const loaded = loadConfig({ configFile });
43
+ const config = loaded.config.eval ?? {};
44
+ if (config.corpus === undefined)
45
+ return config;
46
+ // Like every other configured path: relative to the file that declared it,
47
+ // so a corpus committed next to the config is found from any cwd.
48
+ return { ...config, corpus: path.resolve(configPathBase(loaded).dirFor('eval.corpus'), config.corpus) };
49
+ }
50
+ catch {
51
+ return {};
52
+ }
53
+ }
54
+ function line(r, color) {
55
+ const paint = (s) => (!color ? s : r.passed ? yanse.green(s) : yanse.bold(yanse.red(s)));
56
+ const detail = r.passed
57
+ ? r.found.map((e) => e.code).join(' ')
58
+ : [
59
+ ...r.missed.map((e) => `missed ${e.code}${e.relation ? `@${e.relation}` : ''}`),
60
+ ...r.falsePositives.map((code) => `false positive ${code}`)
61
+ ].join(', ');
62
+ return ` ${paint(r.passed ? 'PASS' : 'FAIL')} ${r.id.padEnd(32)} ${r.dimension.padEnd(8)} `
63
+ + `${String(r.score).padStart(3)} (${r.grade.padEnd(2)}) ${detail}\n`;
64
+ }
65
+ function summary(report, color) {
66
+ const pct = (n) => `${Math.round(n * 100)}%`;
67
+ const ok = report.passed === report.total;
68
+ const headline = `${report.passed}/${report.total} cases passed`;
69
+ return `\n${color ? (ok ? yanse.green(headline) : yanse.bold(yanse.red(headline))) : headline}`
70
+ + ` · recall ${pct(report.recall)} · precision ${pct(report.precision)}\n`;
71
+ }
72
+ export default async (argv, _prompter, _options) => {
73
+ if (argv.help || argv.h) {
74
+ process.stdout.write(usage);
75
+ return;
76
+ }
77
+ const defaults = evalDefaults(typeof argv.config === 'string' ? argv.config : undefined);
78
+ const corpus = typeof argv.corpus === 'string' ? argv.corpus : defaults.corpus;
79
+ const preset = typeof argv.preset === 'string' ? argv.preset : (defaults.preset ?? 'recommended');
80
+ const cases = csvList(argv.case) ?? defaults.cases;
81
+ const color = argv.color !== false && argv.json !== true;
82
+ if (argv.list === true) {
83
+ for (const c of loadCorpus(corpus)) {
84
+ process.stdout.write(`${c.id.padEnd(32)} ${c.dimension.padEnd(8)} ${c.title}\n`);
85
+ }
86
+ return;
87
+ }
88
+ const { config } = loadConfig({ sealed: true, preset });
89
+ const client = buildClient(argv);
90
+ await client.connect();
91
+ try {
92
+ const report = await runEval(client, {
93
+ config,
94
+ preset,
95
+ corpus,
96
+ cases,
97
+ keep: argv.keep === true,
98
+ onResult: argv.json === true ? undefined : (r) => process.stdout.write(line(r, color))
99
+ });
100
+ if (argv.json === true) {
101
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
102
+ }
103
+ else {
104
+ process.stdout.write(summary(report, color));
105
+ for (const r of report.results.filter((x) => !x.passed)) {
106
+ process.stdout.write(`\n${r.id}: ${r.title}\n fix: ${r.fix}\n`);
107
+ }
108
+ }
109
+ if (report.passed !== report.total)
110
+ process.exit(1);
111
+ }
112
+ finally {
113
+ await client.end();
114
+ }
115
+ };
@@ -0,0 +1,3 @@
1
+ import { CLIOptions, Inquirerer, ParsedArgs } from 'inquirerer';
2
+ declare const _default: (argv: ParsedArgs, _prompter: Inquirerer, _options: CLIOptions) => Promise<void>;
3
+ export default _default;
@@ -0,0 +1,52 @@
1
+ import { loadConfig, safegresConfigLoader } from '../config/loader';
2
+ import { resolveRules } from '../config/resolve';
3
+ import { toJsonSchema } from '../config/schema';
4
+ import { RULES } from '../rules/registry';
5
+ import { configParamsFromArgv } from './shared';
6
+ const usage = `
7
+ safegres print-config — show the resolved effective configuration
8
+
9
+ safegres print-config [OPTIONS]
10
+
11
+ Options:
12
+ --config <path> Explicit config file
13
+ --preset <name> Apply a built-in preset
14
+ --rule <CODE=SETTING> Retune a rule (repeatable)
15
+ --explain Show per-key provenance (which layer set each value)
16
+ --schema Print the config JSON Schema instead, for an editor
17
+ --help, -h Show this help message
18
+ `;
19
+ export default async (argv, _prompter, _options) => {
20
+ if (argv.help || argv.h) {
21
+ process.stdout.write(usage);
22
+ return;
23
+ }
24
+ if (argv.schema === true) {
25
+ process.stdout.write(`${JSON.stringify(toJsonSchema(), null, 2)}\n`);
26
+ return;
27
+ }
28
+ const params = configParamsFromArgv(argv);
29
+ if (argv.explain === true) {
30
+ const loader = safegresConfigLoader();
31
+ const explained = loader.explainSync({
32
+ configFile: params.configFile,
33
+ overrides: params.overrides
34
+ });
35
+ for (const e of explained) {
36
+ process.stdout.write(`${e.path} = ${JSON.stringify(e.value)} (${e.source}: ${e.origin})\n`);
37
+ }
38
+ return;
39
+ }
40
+ const { config, filepath, isEmpty } = loadConfig(params);
41
+ const resolved = resolveRules(config);
42
+ const effectiveRules = {};
43
+ for (const rule of RULES) {
44
+ const r = resolved.rules.get(rule.code);
45
+ effectiveRules[rule.code] = r.enabled ? r.severity : 'off';
46
+ }
47
+ process.stdout.write(`${JSON.stringify({
48
+ source: filepath ?? (isEmpty ? '(no config file — defaults)' : undefined),
49
+ config,
50
+ effectiveRules
51
+ }, null, 2)}\n`);
52
+ };
@@ -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;
@@ -0,0 +1,112 @@
1
+ import * as path from 'path';
2
+ import { Client } from 'pg';
3
+ import { getPgEnvOptions } from 'pg-env';
4
+ export function csvList(value) {
5
+ if (typeof value !== 'string' || value.length === 0)
6
+ return undefined;
7
+ return value
8
+ .split(',')
9
+ .map((p) => p.trim())
10
+ .filter(Boolean);
11
+ }
12
+ /**
13
+ * Merge `--ignore-extensions` / `--audit-extension-owned` over the config's
14
+ * `extensions` block. Returns `undefined` when neither side says anything, so
15
+ * the introspection defaults apply.
16
+ */
17
+ export function extensionScopeFromArgv(argv, config) {
18
+ const ignore = csvList(argv['ignore-extensions']) ?? config.extensions?.ignore;
19
+ const skipOwned = argv['audit-extension-owned'] === true ? false : config.extensions?.skipOwned;
20
+ if (ignore === undefined && skipOwned === undefined)
21
+ return undefined;
22
+ return { ...(ignore !== undefined && { ignore }), ...(skipOwned !== undefined && { skipOwned }) };
23
+ }
24
+ export function buildClient(argv) {
25
+ if (typeof argv.connection === 'string' && argv.connection.length > 0) {
26
+ return new Client({ connectionString: argv.connection });
27
+ }
28
+ const overrides = {};
29
+ if (typeof argv.host === 'string')
30
+ overrides.host = argv.host;
31
+ if (typeof argv.port === 'number')
32
+ overrides.port = argv.port;
33
+ if (typeof argv.user === 'string')
34
+ overrides.user = argv.user;
35
+ if (typeof argv.password === 'string')
36
+ overrides.password = argv.password;
37
+ if (typeof argv.database === 'string')
38
+ overrides.database = argv.database;
39
+ return new Client(getPgEnvOptions(overrides));
40
+ }
41
+ /**
42
+ * Parse repeatable `--rule CODE=SETTING` flags into a RulesConfig, e.g.
43
+ * `--rule A3=off --rule A5=high --rule 'P*'=off`.
44
+ */
45
+ export function parseRuleFlags(value) {
46
+ if (value == null)
47
+ return undefined;
48
+ const entries = Array.isArray(value) ? value : [value];
49
+ const rules = {};
50
+ for (const entry of entries) {
51
+ if (typeof entry !== 'string')
52
+ continue;
53
+ const eq = entry.indexOf('=');
54
+ if (eq <= 0) {
55
+ throw new Error(`Invalid --rule "${entry}": expected CODE=off|<severity>.`);
56
+ }
57
+ const code = entry.slice(0, eq).trim();
58
+ const setting = entry.slice(eq + 1).trim();
59
+ rules[code] = setting;
60
+ }
61
+ return Object.keys(rules).length > 0 ? rules : undefined;
62
+ }
63
+ /** Did the caller name a database on the command line, rather than in the environment? */
64
+ function hasConnectionFlag(argv) {
65
+ return ['connection', 'database', 'host', 'port'].some((flag) => typeof argv[flag] === 'string' || typeof argv[flag] === 'number');
66
+ }
67
+ /**
68
+ * Flags win over the config file. A path from a config file is resolved
69
+ * against *the file that declared it* — which is not always the discovered
70
+ * one, since a file can extend another — so a CI job can run from any
71
+ * directory; a path on the command line stays relative to cwd, like every
72
+ * other command's arguments.
73
+ */
74
+ export function resolveRunPaths(argv, config, base) {
75
+ const dirFor = typeof base === 'string' ? () => base : (key) => base.dirFor(key);
76
+ const pick = (flag, key, configured) => typeof flag === 'string' ? flag : configured && path.resolve(dirFor(key), configured);
77
+ // A directory is the common case: one path, conventional names, no remembering
78
+ // which extension goes with which renderer. A named file still wins.
79
+ const dir = pick(argv.out, 'outputs.dir', config.outputs?.dir);
80
+ const inDir = (name) => dir && path.join(dir, name);
81
+ return {
82
+ pgpm: pick(argv.pgpm, 'source.pgpm', config.source?.pgpm),
83
+ // An explicit connection on the command line beats a configured source:
84
+ // pointing the same config at a database you already have is the whole
85
+ // reason to type one, and deploying a throwaway copy instead would ignore it.
86
+ usePgpm: argv.pgpm !== undefined || (config.source?.pgpm !== undefined && !hasConnectionFlag(argv)),
87
+ perfBaseline: pick(argv['perf-baseline'], 'perf.baseline', config.perf?.baseline),
88
+ callGraphBaseline: pick(argv.baseline, 'callGraph.baseline', config.callGraph?.baseline),
89
+ outputs: {
90
+ json: pick(argv['write-json'], 'outputs.json', config.outputs?.json) ?? inDir('safegres.json'),
91
+ markdown: pick(argv['write-markdown'], 'outputs.markdown', config.outputs?.markdown)
92
+ ?? inDir('safegres.md'),
93
+ sarif: pick(argv['write-sarif'], 'outputs.sarif', config.outputs?.sarif) ?? inDir('safegres.sarif'),
94
+ sarifSources: pick(argv['sarif-sources'], 'outputs.sarifSources', config.outputs?.sarifSources),
95
+ snapshot: pick(argv['write-snapshot'], 'outputs.snapshot', config.outputs?.snapshot),
96
+ githubComment: pick(argv['write-github-comment'], 'outputs.githubComment', config.outputs?.githubComment)
97
+ }
98
+ };
99
+ }
100
+ /** Build config-loading params from shared CLI flags. */
101
+ export function configParamsFromArgv(argv) {
102
+ const cliRules = parseRuleFlags(argv.rule);
103
+ const overrides = {};
104
+ if (cliRules)
105
+ overrides.rules = cliRules;
106
+ return {
107
+ configFile: typeof argv.config === 'string' ? argv.config : undefined,
108
+ preset: typeof argv.preset === 'string' ? argv.preset : undefined,
109
+ overrides: Object.keys(overrides).length > 0 ? overrides : undefined,
110
+ sealed: argv.sealed === true
111
+ };
112
+ }
package/esm/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/esm/cli.js ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ import { Logger } from '@pgpmjs/logger';
3
+ import { CLI, getPackageJson } from 'inquirerer';
4
+ import { commands } from './cli/commands';
5
+ const log = new Logger('safegres');
6
+ if (process.argv.includes('--version') || process.argv.includes('-v')) {
7
+ const pkg = getPackageJson(__dirname);
8
+ process.stdout.write(`${pkg.version}\n`);
9
+ process.exit(0);
10
+ }
11
+ const options = {
12
+ minimistOpts: {
13
+ alias: { v: 'version', h: 'help', q: 'summary' },
14
+ boolean: [
15
+ 'skip-ast',
16
+ 'color',
17
+ 'help',
18
+ 'version',
19
+ 'summary',
20
+ 'verbose',
21
+ 'call-graph',
22
+ 'fail-on-new-boundaries',
23
+ 'keep',
24
+ 'list',
25
+ 'json'
26
+ ],
27
+ string: [
28
+ 'baseline',
29
+ 'write-baseline',
30
+ 'compare',
31
+ 'compare-ref',
32
+ 'compare-sha',
33
+ 'compare-run-id',
34
+ 'compare-run-url',
35
+ 'compare-age',
36
+ 'compare-skipped',
37
+ 'write-snapshot',
38
+ 'connection',
39
+ 'host',
40
+ 'user',
41
+ 'password',
42
+ 'database',
43
+ 'schemas',
44
+ 'exclude-schemas',
45
+ 'ignore-extensions',
46
+ 'roles',
47
+ 'exclude-roles',
48
+ 'format',
49
+ 'fail-on',
50
+ 'out',
51
+ 'preset',
52
+ 'corpus',
53
+ 'case',
54
+ 'provider',
55
+ 'repo',
56
+ 'base',
57
+ 'head',
58
+ 'workflow',
59
+ 'artifact',
60
+ 'dir'
61
+ ]
62
+ }
63
+ };
64
+ new CLI(commands, options).run().catch((error) => {
65
+ log.error(error);
66
+ process.exit(1);
67
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Script A driver: pure-Postgres RLS audit.
3
+ *
4
+ * Ingests a catalog snapshot, runs every check, and returns a structured report.
5
+ */
6
+ import type { ExposureConfig, SafegresConfig } from '../config/types';
7
+ import { type IntrospectOptions, type QueryExecutor } from '../pg/introspect';
8
+ import type { Report } from '../types';
9
+ export interface AuditOptions extends IntrospectOptions {
10
+ /** If provided, bypass `pg_roles` enumeration. Otherwise enumerate roles dynamically. */
11
+ includeRoles?: string[];
12
+ /** Roles to drop after enumeration. */
13
+ excludeRoles?: string[];
14
+ /**
15
+ * Skip AST-level anti-pattern checks (P1, P5). Useful for very fast audits
16
+ * that only want grants + RLS-flag + coverage findings.
17
+ */
18
+ skipAstChecks?: boolean;
19
+ /**
20
+ * The exposed API surface. Overrides `config.exposure` when provided.
21
+ * Findings on non-exposed schemas contribute nothing to the score.
22
+ */
23
+ exposure?: ExposureConfig;
24
+ /**
25
+ * Build the unscored call-graph audit: trust boundaries (SECURITY DEFINER
26
+ * hops, RLS-bypass paths, auth-context mutations) reachable from the
27
+ * exposed entry points. Adds `report.callGraph`.
28
+ */
29
+ callGraph?: boolean;
30
+ /**
31
+ * Collect and score the performance dimension: index-hygiene rules (`X*`)
32
+ * on top of the policy-cost rules (P1/P1b) the audit already runs. Adds
33
+ * `report.perf` with its own score. Overrides `config.perf.enabled`.
34
+ */
35
+ perf?: boolean;
36
+ /**
37
+ * Collect runtime statistics (`pg_stat_user_tables`, `pg_stat_statements`)
38
+ * and run the `S*` rules. Implies `perf`. Overrides `config.perf.stats.enabled`.
39
+ */
40
+ stats?: boolean;
41
+ /**
42
+ * Probe perf findings with `EXPLAIN (GENERIC_PLAN)` and attach the plan as
43
+ * evidence, acknowledging findings the planner refutes. Implies `perf`.
44
+ * Overrides `config.perf.explain.enabled`.
45
+ */
46
+ explain?: boolean;
47
+ /**
48
+ * Merged safegres configuration (rules, overrides, scoring). Rule settings
49
+ * filter and retune findings; scoring settings drive the report score.
50
+ * Connection-independent option fields (`schemas`, `roles`, …) present on
51
+ * the config are used as fallbacks for the corresponding AuditOptions.
52
+ */
53
+ config?: SafegresConfig;
54
+ /**
55
+ * Record the run as sealed: produced under configuration the caller
56
+ * controls, with no local config file, rule overrides or baselines. The
57
+ * audit behaves identically — sealing is enforced by whoever assembles the
58
+ * config (the CLI's `--sealed`) — but the claim lands in
59
+ * `report.provenance` so a harness can require it.
60
+ */
61
+ sealed?: boolean;
62
+ /** The preset a sealed run was graded under, recorded in the provenance. */
63
+ preset?: string;
64
+ }
65
+ export declare function audit(client: QueryExecutor, options?: AuditOptions): Promise<Report>;