@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,19 @@
1
+ /**
2
+ * `safegres doctor` — diagnose the environment before/alongside an audit:
3
+ * connection health, catalog visibility, audit blind spots, parser
4
+ * availability, and configuration problems.
5
+ */
6
+ import { type LoadConfigParams } from '../config/loader';
7
+ import { type QueryExecutor } from '../pg/introspect';
8
+ export type DoctorStatus = 'ok' | 'warn' | 'fail';
9
+ export interface DoctorCheck {
10
+ name: string;
11
+ status: DoctorStatus;
12
+ detail: string;
13
+ }
14
+ export interface DoctorReport {
15
+ checks: DoctorCheck[];
16
+ ok: boolean;
17
+ }
18
+ export type DoctorOptions = LoadConfigParams;
19
+ export declare function doctor(client: QueryExecutor | null, options?: DoctorOptions): Promise<DoctorReport>;
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * `safegres doctor` — diagnose the environment before/alongside an audit:
4
+ * connection health, catalog visibility, audit blind spots, parser
5
+ * availability, and configuration problems.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.doctor = doctor;
9
+ const parse_1 = require("../ast/parse");
10
+ const loader_1 = require("../config/loader");
11
+ const resolve_1 = require("../config/resolve");
12
+ const exposure_1 = require("../pg/exposure");
13
+ const introspect_1 = require("../pg/introspect");
14
+ async function doctor(client, options = {}) {
15
+ const checks = [];
16
+ let exposureConfig;
17
+ let publicRead = [];
18
+ // --- configuration ---
19
+ try {
20
+ const loaded = (0, loader_1.loadConfig)(options);
21
+ exposureConfig = loaded.config.exposure;
22
+ publicRead = loaded.config.public?.read ?? [];
23
+ if (loaded.isEmpty) {
24
+ checks.push({
25
+ name: 'config',
26
+ status: 'ok',
27
+ detail: 'no config file found — using built-in defaults (safegres:recommended behavior)'
28
+ });
29
+ }
30
+ else {
31
+ checks.push({ name: 'config', status: 'ok', detail: `loaded ${loaded.filepath}` });
32
+ }
33
+ try {
34
+ const resolved = (0, resolve_1.resolveRules)(loaded.config);
35
+ const disabled = [...resolved.rules.entries()].filter(([, r]) => !r.enabled).map(([c]) => c);
36
+ checks.push({
37
+ name: 'rules',
38
+ status: 'ok',
39
+ detail: disabled.length > 0
40
+ ? `${resolved.rules.size - disabled.length} enabled, ${disabled.length} disabled (${disabled.join(', ')})`
41
+ : `all ${resolved.rules.size} rules enabled`
42
+ });
43
+ }
44
+ catch (err) {
45
+ checks.push({ name: 'rules', status: 'fail', detail: err.message });
46
+ }
47
+ }
48
+ catch (err) {
49
+ checks.push({ name: 'config', status: 'fail', detail: err.message });
50
+ }
51
+ // --- SQL parser ---
52
+ try {
53
+ await (0, parse_1.parsePolicyExpression)('true');
54
+ checks.push({ name: 'parser', status: 'ok', detail: 'pgsql-parser is available (AST rules can run)' });
55
+ }
56
+ catch (err) {
57
+ checks.push({
58
+ name: 'parser',
59
+ status: 'warn',
60
+ detail: `pgsql-parser unavailable — AST rules (A7, P1, P1b, P5) will be skipped: ${err.message}`
61
+ });
62
+ }
63
+ // --- database ---
64
+ if (!client) {
65
+ checks.push({
66
+ name: 'connection',
67
+ status: 'fail',
68
+ detail: 'could not connect — check PG* env vars or --connection'
69
+ });
70
+ return finish(checks);
71
+ }
72
+ const exec = (0, introspect_1.asExecutor)(client);
73
+ try {
74
+ const { rows } = await exec.query('SELECT version() AS version, current_user AS usr, current_database() AS db');
75
+ checks.push({
76
+ name: 'connection',
77
+ status: 'ok',
78
+ detail: `${rows[0].db} as ${rows[0].usr} — ${rows[0].version.split(' on ')[0]}`
79
+ });
80
+ }
81
+ catch (err) {
82
+ checks.push({ name: 'connection', status: 'fail', detail: err.message });
83
+ return finish(checks);
84
+ }
85
+ try {
86
+ const { rows } = await exec.query('SELECT count(*)::text AS n FROM pg_policy');
87
+ checks.push({ name: 'catalog', status: 'ok', detail: `pg_policy readable (${rows[0].n} policies)` });
88
+ }
89
+ catch (err) {
90
+ checks.push({
91
+ name: 'catalog',
92
+ status: 'fail',
93
+ detail: `cannot read pg_policy — the audit needs catalog access: ${err.message}`
94
+ });
95
+ }
96
+ try {
97
+ const { rows } = await exec.query('SELECT rolsuper AS super, rolbypassrls AS bypass FROM pg_roles WHERE rolname = current_user');
98
+ const { super: isSuper, bypass } = rows[0] ?? { super: false, bypass: false };
99
+ if (isSuper || bypass) {
100
+ checks.push({
101
+ name: 'privileges',
102
+ status: 'ok',
103
+ detail: `current role ${isSuper ? 'is superuser' : 'has BYPASSRLS'} — full catalog visibility`
104
+ });
105
+ }
106
+ else {
107
+ checks.push({
108
+ name: 'privileges',
109
+ status: 'warn',
110
+ detail: 'current role is not superuser and lacks BYPASSRLS — policies/grants on tables it cannot see will be missing from the audit'
111
+ });
112
+ }
113
+ }
114
+ catch (err) {
115
+ checks.push({ name: 'privileges', status: 'warn', detail: err.message });
116
+ }
117
+ try {
118
+ const { rows } = await exec.query(`SELECT count(*)::text AS n FROM pg_class c
119
+ JOIN pg_namespace n ON n.oid = c.relnamespace
120
+ WHERE c.relkind IN ('r','p') AND c.relrowsecurity
121
+ AND n.nspname NOT IN ('pg_catalog','information_schema')`);
122
+ const n = Number(rows[0].n);
123
+ checks.push({
124
+ name: 'rls',
125
+ status: n > 0 ? 'ok' : 'warn',
126
+ detail: n > 0
127
+ ? `${n} table(s) have RLS enabled`
128
+ : 'no tables with RLS enabled — nothing for coverage/anti-pattern rules to audit'
129
+ });
130
+ }
131
+ catch (err) {
132
+ checks.push({ name: 'rls', status: 'warn', detail: err.message });
133
+ }
134
+ // --- exposure surface ---
135
+ try {
136
+ const exposure = await (0, exposure_1.resolveExposure)(exec, exposureConfig);
137
+ if (exposure.known) {
138
+ checks.push({
139
+ name: 'exposure',
140
+ status: 'ok',
141
+ detail: `${exposure.schemas.length} exposed schema(s) via ${exposure.source}${exposure.roles && exposure.roles.length > 0 ? ` (api roles: ${exposure.roles.join(', ')})` : ''}`
142
+ });
143
+ }
144
+ else {
145
+ checks.push({
146
+ name: 'exposure',
147
+ status: 'warn',
148
+ detail: 'no exposure surface configured — the audit assumes the whole database is reachable and caps the score. Declare `exposure.schemas` or use `exposure.resolver: "constructive"`.'
149
+ });
150
+ }
151
+ }
152
+ catch (err) {
153
+ checks.push({ name: 'exposure', status: 'warn', detail: err.message });
154
+ }
155
+ // --- declared public surface ---
156
+ if (publicRead.length > 0) {
157
+ try {
158
+ const { rows } = await exec.query(`SELECT n.nspname || '.' || c.relname AS qualified
159
+ FROM pg_class c
160
+ JOIN pg_namespace n ON n.oid = c.relnamespace
161
+ WHERE c.relkind IN ('r','p')
162
+ AND n.nspname NOT IN ('pg_catalog','information_schema')`);
163
+ const qualified = rows.map((r) => r.qualified);
164
+ const stale = publicRead.filter((p) => !qualified.some((q) => (0, resolve_1.matchTablePattern)(p, q)));
165
+ checks.push({
166
+ name: 'public',
167
+ status: stale.length > 0 ? 'warn' : 'ok',
168
+ detail: stale.length > 0
169
+ ? `stale \`public.read\` pattern(s) match no table: ${stale.join(', ')}`
170
+ : `${publicRead.length} \`public.read\` pattern(s), all match at least one table`
171
+ });
172
+ }
173
+ catch (err) {
174
+ checks.push({ name: 'public', status: 'warn', detail: err.message });
175
+ }
176
+ }
177
+ return finish(checks);
178
+ }
179
+ function finish(checks) {
180
+ return { checks, ok: checks.every((c) => c.status !== 'fail') };
181
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `safegres eval` — grade the auditor against a corpus with known answers.
3
+ *
4
+ * The audit answers "what is wrong with this database". Eval answers the
5
+ * question one level up: *is the auditor right?* It deploys each corpus case
6
+ * into a live database, audits it under a sealed preset, and grades the report
7
+ * against the case's answer key — recall (every expected finding present) and
8
+ * precision (nothing the case forbids).
9
+ *
10
+ * That makes it three things with one implementation: safegres's own
11
+ * calibration check, a harness an agent can be scored against (fix the case,
12
+ * re-run, require the findings to disappear), and a demonstration that the
13
+ * rules mean what the docs say.
14
+ */
15
+ import type { Grade, SafegresConfig } from '../config/types';
16
+ import { type CaseResult, type CorpusCase } from '../corpus';
17
+ import { type QueryExecutor } from '../pg/introspect';
18
+ export interface EvalOptions {
19
+ /**
20
+ * The configuration cases are graded under. Normally a sealed preset: the
21
+ * corpus measures the rules, so a local config file editing them would be
22
+ * measuring the wrong thing.
23
+ */
24
+ config?: SafegresConfig;
25
+ /** The preset name, recorded in each report's provenance. */
26
+ preset?: string;
27
+ /** Corpus directory. Defaults to the corpus shipped with the package. */
28
+ corpus?: string;
29
+ /** Case ids (or id prefixes) to run. Defaults to all of them. */
30
+ cases?: string[];
31
+ /** Skip the role bootstrap — for a database that already has the roles. */
32
+ skipBootstrap?: boolean;
33
+ /** Leave each case's schemas in the database instead of dropping them. */
34
+ keep?: boolean;
35
+ /** Called as each case finishes, for streaming progress. */
36
+ onResult?: (result: EvalCaseResult) => void;
37
+ }
38
+ export interface EvalCaseResult extends CaseResult {
39
+ title: string;
40
+ dimension: CorpusCase['dimension'];
41
+ /** The score on the case's own dimension, after its flaw is accounted for. */
42
+ score: number;
43
+ grade: Grade;
44
+ /** The answer key, so a failing case reads as an instruction. */
45
+ fix: string;
46
+ }
47
+ export interface EvalReport {
48
+ generatedAt: string;
49
+ /** The preset every case was graded under. */
50
+ preset?: string;
51
+ /** Configuration fingerprint shared by every case's report. */
52
+ fingerprint?: string;
53
+ sealed: boolean;
54
+ total: number;
55
+ passed: number;
56
+ /** Expected findings produced / expected findings total. */
57
+ recall: number;
58
+ /** Cases that produced no forbidden finding / cases total. */
59
+ precision: number;
60
+ results: EvalCaseResult[];
61
+ }
62
+ /**
63
+ * Deploy, audit and grade every selected case. Each case owns its schemas —
64
+ * its SQL drops them first — so cases neither see nor disturb each other, and
65
+ * the database is left as it was found unless `keep` says otherwise.
66
+ */
67
+ export declare function runEval(client: QueryExecutor, options?: EvalOptions): Promise<EvalReport>;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * `safegres eval` — grade the auditor against a corpus with known answers.
4
+ *
5
+ * The audit answers "what is wrong with this database". Eval answers the
6
+ * question one level up: *is the auditor right?* It deploys each corpus case
7
+ * into a live database, audits it under a sealed preset, and grades the report
8
+ * against the case's answer key — recall (every expected finding present) and
9
+ * precision (nothing the case forbids).
10
+ *
11
+ * That makes it three things with one implementation: safegres's own
12
+ * calibration check, a harness an agent can be scored against (fix the case,
13
+ * re-run, require the findings to disappear), and a demonstration that the
14
+ * rules mean what the docs say.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.runEval = runEval;
18
+ const corpus_1 = require("../corpus");
19
+ const introspect_1 = require("../pg/introspect");
20
+ const audit_1 = require("./audit");
21
+ function selectCases(all, ids) {
22
+ if (!ids || ids.length === 0)
23
+ return all;
24
+ const selected = all.filter((c) => ids.some((id) => c.id === id || c.id.startsWith(id)));
25
+ if (selected.length === 0) {
26
+ throw new Error(`No corpus case matches ${ids.join(', ')}. Available: ${all.map((c) => c.id).join(', ')}`);
27
+ }
28
+ return selected;
29
+ }
30
+ /**
31
+ * Deploy, audit and grade every selected case. Each case owns its schemas —
32
+ * its SQL drops them first — so cases neither see nor disturb each other, and
33
+ * the database is left as it was found unless `keep` says otherwise.
34
+ */
35
+ async function runEval(client, options = {}) {
36
+ const exec = (0, introspect_1.asExecutor)(client);
37
+ const cases = selectCases((0, corpus_1.loadCorpus)(options.corpus), options.cases);
38
+ if (!options.skipBootstrap)
39
+ await exec.query((0, corpus_1.corpusBootstrap)());
40
+ const results = [];
41
+ let fingerprint;
42
+ let sealed = false;
43
+ for (const c of cases) {
44
+ await exec.query(c.sql);
45
+ try {
46
+ const report = await (0, audit_1.audit)(exec, {
47
+ config: options.config,
48
+ exposure: c.exposure,
49
+ schemas: c.exposure.schemas,
50
+ perf: true,
51
+ sealed: true,
52
+ ...(options.preset ? { preset: options.preset } : {})
53
+ });
54
+ fingerprint ??= report.provenance?.fingerprint;
55
+ sealed = report.provenance?.sealed ?? false;
56
+ const score = c.dimension === 'perf' ? report.perf?.score : report.score;
57
+ const result = {
58
+ ...(0, corpus_1.gradeCase)(report, c),
59
+ title: c.title,
60
+ dimension: c.dimension,
61
+ score: score?.value ?? 100,
62
+ grade: score?.grade ?? 'A+',
63
+ fix: c.fix
64
+ };
65
+ results.push(result);
66
+ options.onResult?.(result);
67
+ }
68
+ finally {
69
+ if (!options.keep) {
70
+ for (const schema of c.exposure.schemas ?? []) {
71
+ await exec.query(`DROP SCHEMA IF EXISTS ${quoteIdent(schema)} CASCADE`);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ const expected = results.reduce((n, r) => n + r.found.length + r.missed.length, 0);
77
+ const found = results.reduce((n, r) => n + r.found.length, 0);
78
+ const clean = results.filter((r) => r.falsePositives.length === 0).length;
79
+ return {
80
+ generatedAt: new Date().toISOString(),
81
+ ...(options.preset ? { preset: options.preset } : {}),
82
+ ...(fingerprint ? { fingerprint } : {}),
83
+ sealed,
84
+ total: results.length,
85
+ passed: results.filter((r) => r.passed).length,
86
+ recall: expected === 0 ? 1 : found / expected,
87
+ precision: results.length === 0 ? 1 : clean / results.length,
88
+ results
89
+ };
90
+ }
91
+ function quoteIdent(name) {
92
+ return `"${name.replace(/"/g, '""')}"`;
93
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Provenance: proving *which rules* produced a score.
3
+ *
4
+ * Every knob that moves the number — a rule's severity, an override, a perf
5
+ * ignore, the exposed surface, the scoring weights — is deliberate and useful
6
+ * to a developer declaring intent in CI. To an evaluation harness scoring an
7
+ * agent, the same knobs are the cheapest way to win: turn off the rule, or
8
+ * re-baseline the debt, and the score goes up without the database changing.
9
+ *
10
+ * So a report carries a fingerprint of the configuration it was produced
11
+ * under. Two runs with the same fingerprint were graded by the same rules and
12
+ * are comparable; a different fingerprint means the ruler changed, and a
13
+ * harness can reject the run instead of believing the number.
14
+ *
15
+ * The fingerprint covers the *resolved* rules rather than the config text, so
16
+ * it is invariant to how the same posture was expressed (preset vs. explicit
17
+ * rules, key order, whitespace) and sensitive to anything that changes it.
18
+ */
19
+ import type { SafegresConfig } from './types';
20
+ /** Everything about a run that a comparison must be able to trust. */
21
+ export interface Provenance {
22
+ /** The safegres version that produced the report. */
23
+ version: string;
24
+ /** `sha256:<hex>` over the resolved, score-relevant configuration. */
25
+ fingerprint: string;
26
+ /**
27
+ * True when the run refused local configuration: no discovered config file,
28
+ * no rule overrides, no baselines. An evaluation harness should require it.
29
+ */
30
+ sealed: boolean;
31
+ /** The preset the sealed run was graded under, when one was named. */
32
+ preset?: string;
33
+ }
34
+ /**
35
+ * `sha256:<hex>` over the resolved scoring surface and the safegres version.
36
+ * The version participates because a rule's *meaning* can change without its
37
+ * configuration changing, and two scores from different analyzers are no more
38
+ * comparable than two scores from different rule sets.
39
+ */
40
+ export declare function configFingerprint(config: SafegresConfig, version: string): string;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ /**
3
+ * Provenance: proving *which rules* produced a score.
4
+ *
5
+ * Every knob that moves the number — a rule's severity, an override, a perf
6
+ * ignore, the exposed surface, the scoring weights — is deliberate and useful
7
+ * to a developer declaring intent in CI. To an evaluation harness scoring an
8
+ * agent, the same knobs are the cheapest way to win: turn off the rule, or
9
+ * re-baseline the debt, and the score goes up without the database changing.
10
+ *
11
+ * So a report carries a fingerprint of the configuration it was produced
12
+ * under. Two runs with the same fingerprint were graded by the same rules and
13
+ * are comparable; a different fingerprint means the ruler changed, and a
14
+ * harness can reject the run instead of believing the number.
15
+ *
16
+ * The fingerprint covers the *resolved* rules rather than the config text, so
17
+ * it is invariant to how the same posture was expressed (preset vs. explicit
18
+ * rules, key order, whitespace) and sensitive to anything that changes it.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.configFingerprint = configFingerprint;
22
+ const crypto_1 = require("crypto");
23
+ const resolve_1 = require("./resolve");
24
+ /**
25
+ * A canonical JSON encoding: object keys sorted at every depth, so two configs
26
+ * that mean the same thing hash the same regardless of how they were written.
27
+ */
28
+ function canonical(value) {
29
+ if (Array.isArray(value))
30
+ return value.map(canonical);
31
+ if (value && typeof value === 'object') {
32
+ const entries = Object.entries(value)
33
+ .filter(([, v]) => v !== undefined)
34
+ .sort(([a], [b]) => a.localeCompare(b));
35
+ return Object.fromEntries(entries.map(([k, v]) => [k, canonical(v)]));
36
+ }
37
+ return value;
38
+ }
39
+ /**
40
+ * The score-relevant projection of a config. Deliberately *not* the whole
41
+ * config: connection parameters, output formats and renderer options cannot
42
+ * move the number, and hashing them would make every run look incomparable.
43
+ */
44
+ function scoringSurface(config) {
45
+ const { rules } = (0, resolve_1.resolveRules)(config);
46
+ return {
47
+ rules: [...rules.entries()]
48
+ .sort(([a], [b]) => a.localeCompare(b))
49
+ .map(([code, rule]) => [code, rule.enabled, rule.severity, canonical(rule.options ?? null)]),
50
+ overrides: (config.overrides ?? []).map((o) => canonical(o)),
51
+ scoring: canonical(config.scoring ?? {}),
52
+ publicRead: [...(config.public?.read ?? [])].sort(),
53
+ perfIgnore: [...(config.perf?.ignore ?? [])].sort(),
54
+ exposure: canonical({
55
+ ...config.exposure,
56
+ // An adapter is code, not data: identify it by name and let the version
57
+ // field carry the rest.
58
+ adapters: (config.exposure?.adapters ?? []).map((a) => typeof a === 'string' ? a : a.name)
59
+ })
60
+ };
61
+ }
62
+ /**
63
+ * `sha256:<hex>` over the resolved scoring surface and the safegres version.
64
+ * The version participates because a rule's *meaning* can change without its
65
+ * configuration changing, and two scores from different analyzers are no more
66
+ * comparable than two scores from different rule sets.
67
+ */
68
+ function configFingerprint(config, version) {
69
+ const payload = JSON.stringify({ version, config: scoringSurface(config) });
70
+ return `sha256:${(0, crypto_1.createHash)('sha256').update(payload).digest('hex')}`;
71
+ }
@@ -0,0 +1,44 @@
1
+ import { type ConfigLoader, type ExplainedValue, type LoadResult } from 'confstash';
2
+ import type { SafegresConfig } from './types';
3
+ export type { ConfigLoader, ExplainedValue, LoadResult };
4
+ /**
5
+ * The safegres config loader. Discovers `safegres.config.{ts,js,mjs,cjs}`,
6
+ * `.safegresrc{,.json,.yaml,.yml,.js}`, `safegres.json`, or the `"safegres"`
7
+ * package.json key by walking up from cwd; resolves `extends` against the
8
+ * built-in presets (or files / npm packages).
9
+ */
10
+ export declare function safegresConfigLoader(): ConfigLoader<SafegresConfig>;
11
+ export interface LoadConfigParams {
12
+ cwd?: string;
13
+ /** Explicit config file (skips discovery). */
14
+ configFile?: string;
15
+ /** Preset applied when no `extends` handling is needed from a file (CLI --preset). */
16
+ preset?: string;
17
+ /** Highest-precedence partial config (parsed CLI flags). */
18
+ overrides?: Partial<SafegresConfig>;
19
+ /**
20
+ * Grade under a built-in preset alone: skip config-file discovery entirely,
21
+ * so nothing in the working tree can move the score. For an evaluation
22
+ * harness, where the configuration is part of what is being tested.
23
+ */
24
+ sealed?: boolean;
25
+ }
26
+ /**
27
+ * Where a configured *path* should resolve from. A repository that splits its
28
+ * config into a shared base and a per-job file has two directories in play,
29
+ * and `ci/baseline.json` written in the base means the base's `ci/`, whichever
30
+ * file inherited it.
31
+ */
32
+ export interface ConfigPathBase {
33
+ /** Directory to resolve a value declared at this dotted key against. */
34
+ dirFor(key: string): string;
35
+ }
36
+ /** Load and merge the effective safegres config. */
37
+ export declare function loadConfig(params?: LoadConfigParams): LoadResult<SafegresConfig>;
38
+ /**
39
+ * Resolve each configured path against the file that declared it, so an
40
+ * inherited `perf.baseline` keeps pointing at the base file's directory.
41
+ * Values that came from a preset or from CLI overrides have no directory of
42
+ * their own and fall back to the discovered config file, then to `cwd`.
43
+ */
44
+ export declare function configPathBase(result: LoadResult<SafegresConfig>, cwd?: string): ConfigPathBase;