pr-checkmate 3.0.3 → 3.1.0

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 (380) hide show
  1. package/dist/{cli.js → cjs/cli.js} +30 -30
  2. package/dist/{config → cjs/config}/index.d.ts +2 -2
  3. package/dist/{config → cjs/config}/index.js +8 -7
  4. package/dist/{config → cjs/config}/loader.d.ts +1 -1
  5. package/dist/{config → cjs/config}/loader.js +8 -8
  6. package/dist/{core → cjs/core}/checks/dependencies/banned-imports.d.ts +1 -1
  7. package/dist/{core → cjs/core}/checks/dependencies/banned-imports.js +10 -10
  8. package/dist/{core → cjs/core}/checks/dependencies/circular-deps.d.ts +1 -1
  9. package/dist/{core → cjs/core}/checks/dependencies/circular-deps.js +27 -27
  10. package/dist/{core → cjs/core}/checks/dependencies/dependency-check.d.ts +1 -1
  11. package/dist/{core → cjs/core}/checks/dependencies/dependency-check.js +17 -17
  12. package/dist/{core → cjs/core}/checks/dependencies/grype-scan.d.ts +1 -1
  13. package/dist/{core → cjs/core}/checks/dependencies/grype-scan.js +18 -18
  14. package/dist/{core → cjs/core}/checks/dependencies/license-check.d.ts +1 -1
  15. package/dist/{core → cjs/core}/checks/dependencies/license-check.js +12 -12
  16. package/dist/{core → cjs/core}/checks/dependencies/npm-audit.d.ts +1 -1
  17. package/dist/{core → cjs/core}/checks/dependencies/npm-audit.js +14 -14
  18. package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.d.ts +1 -1
  19. package/dist/{core → cjs/core}/checks/dependencies/outdated-deps.js +14 -14
  20. package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.d.ts +1 -1
  21. package/dist/{core → cjs/core}/checks/dependencies/vuln-scan.js +14 -14
  22. package/dist/{core → cjs/core}/checks/findings.d.ts +1 -1
  23. package/dist/{core → cjs/core}/checks/findings.js +16 -16
  24. package/dist/{core → cjs/core}/checks/git/custom-rules.d.ts +1 -1
  25. package/dist/{core → cjs/core}/checks/git/custom-rules.js +19 -19
  26. package/dist/{core → cjs/core}/checks/git/diff-smell.d.ts +2 -2
  27. package/dist/{core → cjs/core}/checks/git/diff-smell.js +13 -13
  28. package/dist/{core → cjs/core}/checks/git/large-files.d.ts +1 -1
  29. package/dist/{core → cjs/core}/checks/git/large-files.js +15 -15
  30. package/dist/{core → cjs/core}/checks/git/leftover-debug.d.ts +1 -1
  31. package/dist/{core → cjs/core}/checks/git/leftover-debug.js +13 -13
  32. package/dist/{core → cjs/core}/checks/git/lockfile-drift.d.ts +1 -1
  33. package/dist/{core → cjs/core}/checks/git/lockfile-drift.js +12 -12
  34. package/dist/{core → cjs/core}/checks/git/merge-conflict.d.ts +1 -1
  35. package/dist/{core → cjs/core}/checks/git/merge-conflict.js +15 -15
  36. package/dist/{core → cjs/core}/checks/git/missing-tests.d.ts +1 -1
  37. package/dist/{core → cjs/core}/checks/git/missing-tests.js +15 -15
  38. package/dist/{core → cjs/core}/checks/git/todo-fixme.d.ts +1 -1
  39. package/dist/{core → cjs/core}/checks/git/todo-fixme.js +11 -11
  40. package/dist/{core → cjs/core}/checks/languages/cpp-format.d.ts +1 -1
  41. package/dist/{core → cjs/core}/checks/languages/cpp-format.js +18 -18
  42. package/dist/{core → cjs/core}/checks/languages/external-checks.d.ts +9 -9
  43. package/dist/{core → cjs/core}/checks/languages/external-checks.js +10 -10
  44. package/dist/{core → cjs/core}/checks/languages/external-runner.d.ts +2 -2
  45. package/dist/{core → cjs/core}/checks/languages/external-runner.js +21 -21
  46. package/dist/{core → cjs/core}/checks/languages/go-format.d.ts +1 -1
  47. package/dist/cjs/core/checks/languages/go-format.js +202 -0
  48. package/dist/cjs/core/checks/languages/lint.d.ts +2 -0
  49. package/dist/{core → cjs/core}/checks/languages/lint.js +21 -21
  50. package/dist/{core → cjs/core}/checks/languages/prettier.d.ts +1 -1
  51. package/dist/{core → cjs/core}/checks/languages/prettier.js +18 -18
  52. package/dist/{core → cjs/core}/checks/languages/python-format.d.ts +1 -1
  53. package/dist/{core → cjs/core}/checks/languages/python-format.js +14 -14
  54. package/dist/{core → cjs/core}/checks/languages/python-lint.d.ts +1 -1
  55. package/dist/{core → cjs/core}/checks/languages/python-lint.js +13 -13
  56. package/dist/{core → cjs/core}/checks/languages/python-typecheck.d.ts +1 -1
  57. package/dist/{core → cjs/core}/checks/languages/python-typecheck.js +29 -29
  58. package/dist/{core → cjs/core}/checks/languages/typecheck.d.ts +1 -1
  59. package/dist/{core → cjs/core}/checks/languages/typecheck.js +13 -13
  60. package/dist/{core → cjs/core}/checks/pr/commitlint.d.ts +1 -1
  61. package/dist/{core → cjs/core}/checks/pr/commitlint.js +12 -12
  62. package/dist/{core → cjs/core}/checks/pr/pr-body.d.ts +1 -1
  63. package/dist/{core → cjs/core}/checks/pr/pr-body.js +8 -8
  64. package/dist/{core → cjs/core}/checks/pr/pr-size-check.d.ts +1 -1
  65. package/dist/{core → cjs/core}/checks/pr/pr-size-check.js +10 -10
  66. package/dist/{core → cjs/core}/checks/pr/pr-title-lint.d.ts +1 -1
  67. package/dist/{core → cjs/core}/checks/pr/pr-title-lint.js +8 -8
  68. package/dist/{core → cjs/core}/checks/quality/case-collision.d.ts +1 -1
  69. package/dist/{core → cjs/core}/checks/quality/case-collision.js +7 -7
  70. package/dist/{core → cjs/core}/checks/quality/config-validation.d.ts +1 -1
  71. package/dist/{core → cjs/core}/checks/quality/config-validation.js +9 -9
  72. package/dist/{core → cjs/core}/checks/quality/coverage.d.ts +1 -1
  73. package/dist/{core → cjs/core}/checks/quality/coverage.js +4 -4
  74. package/dist/{core → cjs/core}/checks/quality/dead-code.d.ts +1 -1
  75. package/dist/{core → cjs/core}/checks/quality/dead-code.js +23 -23
  76. package/dist/{core → cjs/core}/checks/quality/duplicate-check.d.ts +1 -1
  77. package/dist/{core → cjs/core}/checks/quality/duplicate-check.js +22 -22
  78. package/dist/{core → cjs/core}/checks/quality/license-header.d.ts +1 -1
  79. package/dist/{core → cjs/core}/checks/quality/license-header.js +16 -16
  80. package/dist/{core → cjs/core}/checks/quality/markdown-lint.d.ts +1 -1
  81. package/dist/{core → cjs/core}/checks/quality/markdown-lint.js +17 -17
  82. package/dist/{core → cjs/core}/checks/quality/package-size.d.ts +1 -1
  83. package/dist/{core → cjs/core}/checks/quality/package-size.js +12 -12
  84. package/dist/{core → cjs/core}/checks/quality/spellcheck.d.ts +2 -2
  85. package/dist/{core → cjs/core}/checks/quality/spellcheck.js +18 -18
  86. package/dist/{core → cjs/core}/checks/quality/symlinks.d.ts +1 -1
  87. package/dist/{core → cjs/core}/checks/quality/symlinks.js +8 -8
  88. package/dist/{core → cjs/core}/checks/quality/yaml-lint.d.ts +1 -1
  89. package/dist/{core → cjs/core}/checks/quality/yaml-lint.js +12 -12
  90. package/dist/{core → cjs/core}/checks/security/diff-security.d.ts +1 -1
  91. package/dist/{core → cjs/core}/checks/security/diff-security.js +15 -15
  92. package/dist/{core → cjs/core}/checks/security/dockerfile-security.d.ts +1 -1
  93. package/dist/{core → cjs/core}/checks/security/dockerfile-security.js +16 -16
  94. package/dist/{core → cjs/core}/checks/security/migration-safety.d.ts +1 -1
  95. package/dist/{core → cjs/core}/checks/security/migration-safety.js +17 -17
  96. package/dist/{core → cjs/core}/checks/security/security.d.ts +1 -1
  97. package/dist/{core → cjs/core}/checks/security/security.js +21 -21
  98. package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.d.ts +1 -1
  99. package/dist/{core → cjs/core}/checks/security/sensitive-file-guard.js +14 -14
  100. package/dist/{core → cjs/core}/checks/security/workflow-security.d.ts +2 -2
  101. package/dist/{core → cjs/core}/checks/security/workflow-security.js +14 -14
  102. package/dist/{core → cjs/core}/checks/tool-install.d.ts +1 -1
  103. package/dist/{core → cjs/core}/checks/tool-install.js +2 -2
  104. package/dist/{core → cjs/core}/context.d.ts +1 -1
  105. package/dist/{core → cjs/core}/context.js +16 -16
  106. package/dist/cjs/core/index.d.ts +4 -0
  107. package/dist/{core → cjs/core}/index.js +7 -7
  108. package/dist/{core → cjs/core}/install/cache.js +2 -2
  109. package/dist/{core → cjs/core}/install/doctor.d.ts +4 -4
  110. package/dist/{core → cjs/core}/install/doctor.js +34 -34
  111. package/dist/{core → cjs/core}/install/ensure.d.ts +2 -2
  112. package/dist/{core → cjs/core}/install/ensure.js +15 -14
  113. package/dist/{core → cjs/core}/install/lock.js +4 -4
  114. package/dist/{core → cjs/core}/install/prepare.d.ts +4 -4
  115. package/dist/{core → cjs/core}/install/prepare.js +13 -13
  116. package/dist/{core → cjs/core}/install/profiles.d.ts +2 -2
  117. package/dist/{core → cjs/core}/install/reuse.d.ts +1 -1
  118. package/dist/{core → cjs/core}/install/reuse.js +4 -4
  119. package/dist/{core → cjs/core}/registry.d.ts +1 -1
  120. package/dist/cjs/core/registry.js +112 -0
  121. package/dist/{core → cjs/core}/reporters.d.ts +1 -1
  122. package/dist/{core → cjs/core}/reporters.js +28 -28
  123. package/dist/{core → cjs/core}/run-checks.d.ts +2 -2
  124. package/dist/{core → cjs/core}/run-checks.js +31 -31
  125. package/dist/{core → cjs/core}/targets.d.ts +1 -1
  126. package/dist/{core → cjs/core}/targets.js +20 -20
  127. package/dist/{core → cjs/core}/types.d.ts +3 -3
  128. package/dist/cjs/index.d.ts +12 -0
  129. package/dist/{index.js → cjs/index.js} +18 -18
  130. package/dist/{init.js → cjs/init.js} +68 -56
  131. package/dist/{interfaces → cjs/interfaces}/index.d.ts +3 -3
  132. package/dist/cjs/package.json +1 -0
  133. package/dist/{scripts → cjs/scripts}/copy-configs.js +22 -7
  134. package/dist/{scripts → cjs/scripts}/generate-install-manifests.js +2 -2
  135. package/dist/{scripts → cjs/scripts}/publish-github.js +4 -4
  136. package/dist/{utils → cjs/utils}/detect-language.js +12 -12
  137. package/dist/cjs/utils/execa.js +46 -0
  138. package/dist/{utils → cjs/utils}/git.js +2 -2
  139. package/dist/{utils → cjs/utils}/http.js +2 -2
  140. package/dist/cjs/utils/index.d.ts +15 -0
  141. package/dist/{utils → cjs/utils}/index.js +13 -13
  142. package/dist/{utils → cjs/utils}/own-deps.d.ts +2 -0
  143. package/dist/{utils → cjs/utils}/own-deps.js +1 -0
  144. package/dist/{utils → cjs/utils}/package-version.js +2 -1
  145. package/dist/{utils → cjs/utils}/resolve-bin.js +2 -1
  146. package/dist/{utils → cjs/utils}/update-notifier.js +4 -4
  147. package/dist/esm/cli.d.ts +2 -0
  148. package/dist/esm/cli.js +137 -0
  149. package/dist/esm/config/constants.d.ts +153 -0
  150. package/dist/esm/config/constants.js +360 -0
  151. package/dist/esm/config/index.d.ts +40 -0
  152. package/dist/esm/config/index.js +60 -0
  153. package/dist/esm/config/loader.d.ts +6 -0
  154. package/dist/esm/config/loader.js +191 -0
  155. package/dist/esm/config/pr-checkmate-workflow-docker.yml +79 -0
  156. package/dist/esm/config/pr-checkmate-workflow.yml +92 -0
  157. package/dist/esm/core/checks/dependencies/banned-imports.d.ts +2 -0
  158. package/dist/esm/core/checks/dependencies/banned-imports.js +70 -0
  159. package/dist/esm/core/checks/dependencies/circular-deps.d.ts +2 -0
  160. package/dist/esm/core/checks/dependencies/circular-deps.js +155 -0
  161. package/dist/esm/core/checks/dependencies/dependency-check.d.ts +43 -0
  162. package/dist/esm/core/checks/dependencies/dependency-check.js +174 -0
  163. package/dist/esm/core/checks/dependencies/grype-scan.d.ts +22 -0
  164. package/dist/esm/core/checks/dependencies/grype-scan.js +112 -0
  165. package/dist/esm/core/checks/dependencies/license-check.d.ts +2 -0
  166. package/dist/esm/core/checks/dependencies/license-check.js +61 -0
  167. package/dist/esm/core/checks/dependencies/npm-audit.d.ts +6 -0
  168. package/dist/esm/core/checks/dependencies/npm-audit.js +80 -0
  169. package/dist/esm/core/checks/dependencies/outdated-deps.d.ts +2 -0
  170. package/dist/esm/core/checks/dependencies/outdated-deps.js +66 -0
  171. package/dist/esm/core/checks/dependencies/vuln-scan.d.ts +2 -0
  172. package/dist/esm/core/checks/dependencies/vuln-scan.js +54 -0
  173. package/dist/esm/core/checks/findings.d.ts +299 -0
  174. package/dist/esm/core/checks/findings.js +701 -0
  175. package/dist/esm/core/checks/git/custom-rules.d.ts +2 -0
  176. package/dist/esm/core/checks/git/custom-rules.js +106 -0
  177. package/dist/esm/core/checks/git/diff-smell.d.ts +19 -0
  178. package/dist/esm/core/checks/git/diff-smell.js +69 -0
  179. package/dist/esm/core/checks/git/large-files.d.ts +2 -0
  180. package/dist/esm/core/checks/git/large-files.js +112 -0
  181. package/dist/esm/core/checks/git/leftover-debug.d.ts +2 -0
  182. package/dist/esm/core/checks/git/leftover-debug.js +89 -0
  183. package/dist/esm/core/checks/git/lockfile-drift.d.ts +2 -0
  184. package/dist/esm/core/checks/git/lockfile-drift.js +114 -0
  185. package/dist/esm/core/checks/git/merge-conflict.d.ts +2 -0
  186. package/dist/esm/core/checks/git/merge-conflict.js +117 -0
  187. package/dist/esm/core/checks/git/missing-tests.d.ts +2 -0
  188. package/dist/esm/core/checks/git/missing-tests.js +105 -0
  189. package/dist/esm/core/checks/git/todo-fixme.d.ts +7 -0
  190. package/dist/esm/core/checks/git/todo-fixme.js +80 -0
  191. package/dist/esm/core/checks/languages/cpp-format.d.ts +7 -0
  192. package/dist/esm/core/checks/languages/cpp-format.js +91 -0
  193. package/dist/esm/core/checks/languages/external-checks.d.ts +77 -0
  194. package/dist/esm/core/checks/languages/external-checks.js +197 -0
  195. package/dist/esm/core/checks/languages/external-runner.d.ts +119 -0
  196. package/dist/esm/core/checks/languages/external-runner.js +138 -0
  197. package/dist/esm/core/checks/languages/go-format.d.ts +8 -0
  198. package/dist/{core → esm/core}/checks/languages/go-format.js +29 -35
  199. package/dist/esm/core/checks/languages/lint.d.ts +2 -0
  200. package/dist/esm/core/checks/languages/lint.js +92 -0
  201. package/dist/esm/core/checks/languages/prettier.d.ts +2 -0
  202. package/dist/esm/core/checks/languages/prettier.js +85 -0
  203. package/dist/esm/core/checks/languages/python-format.d.ts +7 -0
  204. package/dist/esm/core/checks/languages/python-format.js +61 -0
  205. package/dist/esm/core/checks/languages/python-lint.d.ts +9 -0
  206. package/dist/esm/core/checks/languages/python-lint.js +55 -0
  207. package/dist/esm/core/checks/languages/python-typecheck.d.ts +14 -0
  208. package/dist/esm/core/checks/languages/python-typecheck.js +184 -0
  209. package/dist/esm/core/checks/languages/ruff-shared.d.ts +10 -0
  210. package/dist/esm/core/checks/languages/ruff-shared.js +35 -0
  211. package/dist/esm/core/checks/languages/typecheck.d.ts +2 -0
  212. package/dist/esm/core/checks/languages/typecheck.js +61 -0
  213. package/dist/esm/core/checks/pr/commitlint.d.ts +2 -0
  214. package/dist/esm/core/checks/pr/commitlint.js +102 -0
  215. package/dist/esm/core/checks/pr/pr-body.d.ts +2 -0
  216. package/dist/esm/core/checks/pr/pr-body.js +43 -0
  217. package/dist/esm/core/checks/pr/pr-size-check.d.ts +2 -0
  218. package/dist/esm/core/checks/pr/pr-size-check.js +42 -0
  219. package/dist/esm/core/checks/pr/pr-title-lint.d.ts +2 -0
  220. package/dist/esm/core/checks/pr/pr-title-lint.js +31 -0
  221. package/dist/esm/core/checks/quality/case-collision.d.ts +8 -0
  222. package/dist/esm/core/checks/quality/case-collision.js +39 -0
  223. package/dist/esm/core/checks/quality/config-validation.d.ts +11 -0
  224. package/dist/esm/core/checks/quality/config-validation.js +188 -0
  225. package/dist/esm/core/checks/quality/coverage.d.ts +2 -0
  226. package/dist/esm/core/checks/quality/coverage.js +62 -0
  227. package/dist/esm/core/checks/quality/dead-code.d.ts +2 -0
  228. package/dist/esm/core/checks/quality/dead-code.js +124 -0
  229. package/dist/esm/core/checks/quality/duplicate-check.d.ts +2 -0
  230. package/dist/esm/core/checks/quality/duplicate-check.js +141 -0
  231. package/dist/esm/core/checks/quality/license-header.d.ts +7 -0
  232. package/dist/esm/core/checks/quality/license-header.js +81 -0
  233. package/dist/esm/core/checks/quality/markdown-lint.d.ts +2 -0
  234. package/dist/esm/core/checks/quality/markdown-lint.js +104 -0
  235. package/dist/esm/core/checks/quality/package-size.d.ts +36 -0
  236. package/dist/esm/core/checks/quality/package-size.js +196 -0
  237. package/dist/esm/core/checks/quality/spellcheck.d.ts +77 -0
  238. package/dist/esm/core/checks/quality/spellcheck.js +296 -0
  239. package/dist/esm/core/checks/quality/symlinks.d.ts +16 -0
  240. package/dist/esm/core/checks/quality/symlinks.js +57 -0
  241. package/dist/esm/core/checks/quality/yaml-lint.d.ts +20 -0
  242. package/dist/esm/core/checks/quality/yaml-lint.js +116 -0
  243. package/dist/esm/core/checks/security/diff-security.d.ts +2 -0
  244. package/dist/esm/core/checks/security/diff-security.js +354 -0
  245. package/dist/esm/core/checks/security/dockerfile-security.d.ts +2 -0
  246. package/dist/esm/core/checks/security/dockerfile-security.js +98 -0
  247. package/dist/esm/core/checks/security/migration-safety.d.ts +2 -0
  248. package/dist/esm/core/checks/security/migration-safety.js +137 -0
  249. package/dist/esm/core/checks/security/security.d.ts +63 -0
  250. package/dist/esm/core/checks/security/security.js +201 -0
  251. package/dist/esm/core/checks/security/sensitive-file-guard.d.ts +2 -0
  252. package/dist/esm/core/checks/security/sensitive-file-guard.js +160 -0
  253. package/dist/esm/core/checks/security/workflow-security.d.ts +12 -0
  254. package/dist/esm/core/checks/security/workflow-security.js +100 -0
  255. package/dist/esm/core/checks/tool-install.d.ts +102 -0
  256. package/dist/esm/core/checks/tool-install.js +66 -0
  257. package/dist/esm/core/commands.d.ts +27 -0
  258. package/dist/esm/core/commands.js +89 -0
  259. package/dist/esm/core/context.d.ts +62 -0
  260. package/dist/esm/core/context.js +241 -0
  261. package/dist/esm/core/index.d.ts +4 -0
  262. package/dist/esm/core/index.js +4 -0
  263. package/dist/esm/core/install/cache.d.ts +58 -0
  264. package/dist/esm/core/install/cache.js +142 -0
  265. package/dist/esm/core/install/doctor.d.ts +35 -0
  266. package/dist/esm/core/install/doctor.js +164 -0
  267. package/dist/esm/core/install/ensure.d.ts +77 -0
  268. package/dist/esm/core/install/ensure.js +269 -0
  269. package/dist/esm/core/install/lock.d.ts +34 -0
  270. package/dist/esm/core/install/lock.js +92 -0
  271. package/dist/esm/core/install/merge.d.ts +47 -0
  272. package/dist/esm/core/install/merge.js +85 -0
  273. package/dist/esm/core/install/prepare.d.ts +76 -0
  274. package/dist/esm/core/install/prepare.js +142 -0
  275. package/dist/esm/core/install/profiles.d.ts +78 -0
  276. package/dist/esm/core/install/profiles.js +192 -0
  277. package/dist/esm/core/install/reuse.d.ts +41 -0
  278. package/dist/esm/core/install/reuse.js +100 -0
  279. package/dist/esm/core/registry.d.ts +6 -0
  280. package/dist/esm/core/registry.js +109 -0
  281. package/dist/esm/core/reporters.d.ts +18 -0
  282. package/dist/esm/core/reporters.js +266 -0
  283. package/dist/esm/core/run-checks.d.ts +33 -0
  284. package/dist/esm/core/run-checks.js +293 -0
  285. package/dist/esm/core/targets.d.ts +140 -0
  286. package/dist/esm/core/targets.js +213 -0
  287. package/dist/esm/core/types.d.ts +195 -0
  288. package/dist/esm/core/types.js +38 -0
  289. package/dist/esm/index.d.ts +12 -0
  290. package/dist/esm/index.js +15 -0
  291. package/dist/esm/init.d.ts +38 -0
  292. package/dist/esm/init.js +421 -0
  293. package/dist/esm/interfaces/index.d.ts +432 -0
  294. package/dist/esm/interfaces/index.js +2 -0
  295. package/dist/esm/package.json +1 -0
  296. package/dist/esm/scripts/copy-configs.d.ts +1 -0
  297. package/dist/esm/scripts/copy-configs.js +64 -0
  298. package/dist/esm/scripts/generate-install-manifests.d.ts +39 -0
  299. package/dist/esm/scripts/generate-install-manifests.js +115 -0
  300. package/dist/esm/scripts/publish-github.d.ts +1 -0
  301. package/dist/esm/scripts/publish-github.js +45 -0
  302. package/dist/esm/utils/ci.d.ts +11 -0
  303. package/dist/esm/utils/ci.js +40 -0
  304. package/dist/esm/utils/detect-language.d.ts +48 -0
  305. package/dist/esm/utils/detect-language.js +234 -0
  306. package/dist/esm/utils/direct-deps.d.ts +21 -0
  307. package/dist/esm/utils/direct-deps.js +220 -0
  308. package/dist/esm/utils/execa.d.ts +22 -0
  309. package/dist/{utils → esm/utils}/execa.js +1 -4
  310. package/dist/esm/utils/git.d.ts +14 -0
  311. package/dist/esm/utils/git.js +21 -0
  312. package/dist/esm/utils/glob.d.ts +24 -0
  313. package/dist/esm/utils/glob.js +40 -0
  314. package/dist/esm/utils/http.d.ts +59 -0
  315. package/dist/esm/utils/http.js +115 -0
  316. package/dist/esm/utils/index.d.ts +15 -0
  317. package/dist/esm/utils/index.js +26 -0
  318. package/dist/esm/utils/logger.d.ts +65 -0
  319. package/dist/esm/utils/logger.js +157 -0
  320. package/dist/esm/utils/own-deps.d.ts +16 -0
  321. package/dist/esm/utils/own-deps.js +107 -0
  322. package/dist/esm/utils/package-version.d.ts +4 -0
  323. package/dist/esm/utils/package-version.js +38 -0
  324. package/dist/esm/utils/pool.d.ts +49 -0
  325. package/dist/esm/utils/pool.js +113 -0
  326. package/dist/esm/utils/resolve-bin.d.ts +67 -0
  327. package/dist/esm/utils/resolve-bin.js +156 -0
  328. package/dist/esm/utils/result-collector.d.ts +33 -0
  329. package/dist/esm/utils/result-collector.js +44 -0
  330. package/dist/esm/utils/update-notifier.d.ts +19 -0
  331. package/dist/esm/utils/update-notifier.js +108 -0
  332. package/install-manifests/core/package-lock.json +4 -4
  333. package/install-manifests/core/package.json +1 -1
  334. package/install-manifests/cpp/package-lock.json +4 -4
  335. package/install-manifests/cpp/package.json +1 -1
  336. package/package.json +16 -14
  337. package/dist/core/checks/languages/lint.d.ts +0 -2
  338. package/dist/core/index.d.ts +0 -4
  339. package/dist/core/registry.js +0 -112
  340. package/dist/index.d.ts +0 -12
  341. package/dist/utils/index.d.ts +0 -15
  342. /package/dist/{cli.d.ts → cjs/cli.d.ts} +0 -0
  343. /package/dist/{config → cjs/config}/constants.d.ts +0 -0
  344. /package/dist/{config → cjs/config}/constants.js +0 -0
  345. /package/dist/{config → cjs/config}/pr-checkmate-workflow-docker.yml +0 -0
  346. /package/dist/{config → cjs/config}/pr-checkmate-workflow.yml +0 -0
  347. /package/dist/{core → cjs/core}/checks/languages/ruff-shared.d.ts +0 -0
  348. /package/dist/{core → cjs/core}/checks/languages/ruff-shared.js +0 -0
  349. /package/dist/{core → cjs/core}/commands.d.ts +0 -0
  350. /package/dist/{core → cjs/core}/commands.js +0 -0
  351. /package/dist/{core → cjs/core}/install/cache.d.ts +0 -0
  352. /package/dist/{core → cjs/core}/install/lock.d.ts +0 -0
  353. /package/dist/{core → cjs/core}/install/merge.d.ts +0 -0
  354. /package/dist/{core → cjs/core}/install/merge.js +0 -0
  355. /package/dist/{core → cjs/core}/install/profiles.js +0 -0
  356. /package/dist/{core → cjs/core}/types.js +0 -0
  357. /package/dist/{init.d.ts → cjs/init.d.ts} +0 -0
  358. /package/dist/{interfaces → cjs/interfaces}/index.js +0 -0
  359. /package/dist/{scripts → cjs/scripts}/copy-configs.d.ts +0 -0
  360. /package/dist/{scripts → cjs/scripts}/generate-install-manifests.d.ts +0 -0
  361. /package/dist/{scripts → cjs/scripts}/publish-github.d.ts +0 -0
  362. /package/dist/{utils → cjs/utils}/ci.d.ts +0 -0
  363. /package/dist/{utils → cjs/utils}/ci.js +0 -0
  364. /package/dist/{utils → cjs/utils}/detect-language.d.ts +0 -0
  365. /package/dist/{utils → cjs/utils}/direct-deps.d.ts +0 -0
  366. /package/dist/{utils → cjs/utils}/direct-deps.js +0 -0
  367. /package/dist/{utils → cjs/utils}/execa.d.ts +0 -0
  368. /package/dist/{utils → cjs/utils}/git.d.ts +0 -0
  369. /package/dist/{utils → cjs/utils}/glob.d.ts +0 -0
  370. /package/dist/{utils → cjs/utils}/glob.js +0 -0
  371. /package/dist/{utils → cjs/utils}/http.d.ts +0 -0
  372. /package/dist/{utils → cjs/utils}/logger.d.ts +0 -0
  373. /package/dist/{utils → cjs/utils}/logger.js +0 -0
  374. /package/dist/{utils → cjs/utils}/package-version.d.ts +0 -0
  375. /package/dist/{utils → cjs/utils}/pool.d.ts +0 -0
  376. /package/dist/{utils → cjs/utils}/pool.js +0 -0
  377. /package/dist/{utils → cjs/utils}/resolve-bin.d.ts +0 -0
  378. /package/dist/{utils → cjs/utils}/result-collector.d.ts +0 -0
  379. /package/dist/{utils → cjs/utils}/result-collector.js +0 -0
  380. /package/dist/{utils → cjs/utils}/update-notifier.d.ts +0 -0
@@ -0,0 +1,354 @@
1
+ import { DIFF_SECURITY_IGNORE_DEFAULTS } from '../../../config/index.js';
2
+ import { logger } from '../../../utils/index.js';
3
+ import { skip } from '../../types.js';
4
+ import { clientFindingOptions, emptyBuckets, mergeSeverityBuckets, reportSeverityBuckets, scanDiffPatterns, reviewLines, DEFAULT_DATAFLOW_WINDOW, } from '../findings.js';
5
+ const MD5_LABEL = 'MD5 (weak hash — use sha256 or stronger)';
6
+ const SHA1_LABEL = 'SHA-1 (weak hash — use sha256 or stronger)';
7
+ const SECURITY_PATTERNS = [
8
+ {
9
+ pattern: /^\+(?!\+).*dangerouslySetInnerHTML\s*=/,
10
+ label: 'dangerouslySetInnerHTML (XSS risk)',
11
+ view: 'code',
12
+ severity: 'error',
13
+ },
14
+ {
15
+ pattern: /^\+(?!\+).*\.innerHTML\s*=/,
16
+ label: 'innerHTML assignment (XSS risk)',
17
+ view: 'code',
18
+ severity: 'warn',
19
+ },
20
+ {
21
+ pattern: /^\+(?!\+).*document\.write\s*\(/,
22
+ label: 'document.write() (XSS risk)',
23
+ view: 'code',
24
+ severity: 'error',
25
+ },
26
+ {
27
+ // Matched against the string-blanked view, so unrelated quoting on the line
28
+ // cannot disable the rule. The old lookahead `(?![^'"`]*['"`])` meant "no
29
+ // quote anywhere ahead", which silently skipped `eval(x + "y")` and
30
+ // ``eval(`${p}`)`` — see ticket 058.
31
+ pattern: /^\+(?!\+).*\beval\s*\(/,
32
+ label: 'eval() (code injection risk)',
33
+ severity: 'error',
34
+ view: 'code',
35
+ },
36
+ {
37
+ pattern: /^\+(?!\+).*\bnew\s+Function\s*\(/,
38
+ label: 'new Function() (code injection risk)',
39
+ severity: 'error',
40
+ view: 'code',
41
+ },
42
+ {
43
+ // Both the property form (`o.__proto__ =`, `{ __proto__: … }`) and the
44
+ // computed form (`o['__proto__'] =`). The latter is the one that survives a
45
+ // grep for `.__proto__`, and the one an attacker-supplied key arrives through.
46
+ // The rule matches its own source, hence the opt-out on the line itself.
47
+ pattern: /^\+(?!\+).*(?:__proto__\s*[=:[]|\[\s*['"]__proto__['"]\s*\])/, // pr-checkmate-ignore
48
+ label: '__proto__ mutation (prototype pollution)',
49
+ severity: 'error',
50
+ },
51
+ {
52
+ pattern: /^\+(?!\+).*(?:\.constructor\.prototype\b|\[\s*['"]constructor['"]\s*\]\s*\[\s*['"]prototype['"]\s*\])/,
53
+ label: 'constructor.prototype access (prototype pollution)',
54
+ severity: 'warn',
55
+ },
56
+ {
57
+ pattern: /^\+(?!\+).*createHash\s*\(\s*['"]md5['"]/,
58
+ label: MD5_LABEL,
59
+ severity: 'warn',
60
+ },
61
+ {
62
+ pattern: /^\+(?!\+).*createHash\s*\(\s*['"]sha1['"]/,
63
+ label: SHA1_LABEL,
64
+ severity: 'warn',
65
+ },
66
+ {
67
+ pattern: /^\+(?!\+).*\bcreateDecipher\s*\(/,
68
+ label: 'deprecated createDecipher() — use createDecipheriv()',
69
+ view: 'code',
70
+ severity: 'warn',
71
+ },
72
+ {
73
+ pattern: /^\+(?!\+).*\bcreateCipher\s*\(/,
74
+ label: 'deprecated createCipher() — use createCipheriv()',
75
+ view: 'code',
76
+ severity: 'warn',
77
+ },
78
+ {
79
+ pattern: /^\+(?!\+).*cors\s*\(\s*\{[^}]*origin\s*:\s*['"]\*['"]/,
80
+ label: "CORS wildcard origin: '*' (allows any domain)",
81
+ severity: 'warn',
82
+ },
83
+ {
84
+ pattern: /^\+(?!\+).*['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/,
85
+ label: "Access-Control-Allow-Origin: '*' header (CORS wildcard)",
86
+ severity: 'warn',
87
+ },
88
+ {
89
+ pattern: /^\+(?!\+).*(fetch|axios\.get|axios\.post|axios\.put|axios\.delete|http\.get|http\.request)\s*\(\s*['"]http:\/\//,
90
+ label: 'Insecure HTTP (non-HTTPS) in external call',
91
+ severity: 'warn',
92
+ },
93
+ {
94
+ pattern: /^\+(?!\+).*(exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/,
95
+ label: 'exec/spawn with template literal (command injection risk)',
96
+ severity: 'error',
97
+ },
98
+ {
99
+ pattern: /^\+(?!\+).*(exec|execSync)\s*\(\s*['"][^'"]*['"\s]*\+/,
100
+ label: 'exec/spawn with string concatenation (command injection risk)',
101
+ severity: 'error',
102
+ },
103
+ {
104
+ pattern: /^\+(?!\+).*\b(query|execute|raw)\s*\(\s*`[^`]*\$\{/,
105
+ label: 'SQL query with template literal interpolation (SQL injection risk)',
106
+ severity: 'error',
107
+ },
108
+ {
109
+ // A quoted string that contains a whole SQL keyword, concatenated with a
110
+ // variable — the real injection shape. Word boundaries + the quote context
111
+ // stop identifiers like `insertions + deletions` from false-positiving.
112
+ pattern: /^\+(?!\+).*['"`][^'"`]*\b(SELECT|INSERT|UPDATE|DELETE|WHERE)\b[^'"`]*['"`]\s*\+\s*\w/i,
113
+ label: 'SQL string concatenation (SQL injection risk)',
114
+ severity: 'error',
115
+ },
116
+ ];
117
+ /** Python-specific dangerous constructs, scanned in *.py diffs. */
118
+ const PYTHON_SECURITY_PATTERNS = [
119
+ {
120
+ pattern: /^\+(?!\+).*\beval\s*\(/,
121
+ label: 'eval() (code injection risk)',
122
+ severity: 'error',
123
+ view: 'code',
124
+ },
125
+ {
126
+ pattern: /^\+(?!\+).*\bexec\s*\(/,
127
+ label: 'exec() (code injection risk)',
128
+ severity: 'error',
129
+ view: 'code',
130
+ },
131
+ {
132
+ pattern: /^\+(?!\+).*\bos\.system\s*\(/,
133
+ label: 'os.system() (command injection risk)',
134
+ severity: 'error',
135
+ },
136
+ {
137
+ pattern: /^\+(?!\+).*\bsubprocess\.\w+\([^)]*shell\s*=\s*True/,
138
+ label: 'subprocess with shell=True (command injection risk)',
139
+ severity: 'error',
140
+ },
141
+ {
142
+ pattern: /^\+(?!\+).*\bpickle\.loads?\s*\(/,
143
+ label: 'pickle load (insecure deserialization)',
144
+ severity: 'error',
145
+ },
146
+ {
147
+ pattern: /^\+(?!\+).*\byaml\.load\s*\((?![^)]*Safe)/,
148
+ label: 'yaml.load without SafeLoader (unsafe deserialization)',
149
+ severity: 'warn',
150
+ },
151
+ {
152
+ pattern: /^\+(?!\+).*\bhashlib\.md5\s*\(/,
153
+ label: MD5_LABEL,
154
+ severity: 'warn',
155
+ },
156
+ {
157
+ pattern: /^\+(?!\+).*\bhashlib\.sha1\s*\(/,
158
+ label: SHA1_LABEL,
159
+ severity: 'warn',
160
+ },
161
+ {
162
+ pattern: /^\+(?!\+).*\bverify\s*=\s*False\b/,
163
+ label: 'TLS verification disabled (verify=False)',
164
+ severity: 'warn',
165
+ },
166
+ {
167
+ pattern: /^\+(?!\+).*['"][^'"]*\b(SELECT|INSERT|UPDATE|DELETE)\b[^'"]*['"]\s*%\s*/i,
168
+ label: 'SQL string formatting (SQL injection risk)',
169
+ severity: 'error',
170
+ },
171
+ ];
172
+ /** Go-specific dangerous constructs, scanned in *.go diffs. */
173
+ const GO_SECURITY_PATTERNS = [
174
+ {
175
+ pattern: /^\+(?!\+).*\bmd5\.New\s*\(/,
176
+ label: MD5_LABEL,
177
+ severity: 'warn',
178
+ },
179
+ {
180
+ pattern: /^\+(?!\+).*\bsha1\.New\s*\(/,
181
+ label: SHA1_LABEL,
182
+ severity: 'warn',
183
+ },
184
+ {
185
+ pattern: /^\+(?!\+).*InsecureSkipVerify\s*:\s*true/,
186
+ label: 'InsecureSkipVerify: true (TLS verification disabled)',
187
+ severity: 'error',
188
+ },
189
+ {
190
+ pattern: /^\+(?!\+).*\bexec\.Command\s*\([^)]*\+/,
191
+ label: 'exec.Command with string concatenation (command injection risk)',
192
+ severity: 'warn',
193
+ },
194
+ {
195
+ pattern: /^\+(?!\+).*\bfmt\.Sprintf\s*\([^)]*\b(SELECT|INSERT|UPDATE|DELETE)\b/i,
196
+ label: 'SQL built with fmt.Sprintf (SQL injection risk)',
197
+ severity: 'warn',
198
+ },
199
+ { pattern: /^\+(?!\+).*"crypto\/des"/, label: 'DES (weak cipher)', severity: 'warn' },
200
+ ];
201
+ /** Kotlin/Java-specific dangerous constructs, scanned in *.kt/*.kts/*.java diffs. */
202
+ const KOTLIN_SECURITY_PATTERNS = [
203
+ {
204
+ pattern: /^\+(?!\+).*\bRuntime\.getRuntime\(\)\.exec\s*\(/,
205
+ label: 'Runtime.exec() (command injection risk)',
206
+ severity: 'error',
207
+ },
208
+ {
209
+ pattern: /^\+(?!\+).*\bMessageDigest\.getInstance\s*\(\s*"(MD5|SHA-1)"/,
210
+ label: 'weak hash (MD5/SHA-1 via MessageDigest — use SHA-256+)',
211
+ severity: 'warn',
212
+ },
213
+ {
214
+ pattern: /^\+(?!\+).*\bCipher\.getInstance\s*\(\s*"(DES|.*ECB)/,
215
+ label: 'weak cipher (DES / ECB mode)',
216
+ severity: 'warn',
217
+ },
218
+ {
219
+ pattern: /^\+(?!\+).*ALLOW_ALL_HOSTNAME_VERIFIER/,
220
+ label: 'ALLOW_ALL_HOSTNAME_VERIFIER (TLS hostname verification disabled)',
221
+ severity: 'error',
222
+ },
223
+ {
224
+ pattern: /^\+(?!\+).*\bObjectInputStream\b/,
225
+ label: 'ObjectInputStream (insecure deserialization risk)',
226
+ severity: 'warn',
227
+ },
228
+ {
229
+ pattern: /^\+(?!\+).*"[^"]*\b(SELECT|INSERT|UPDATE|DELETE)\b[^"]*"\s*\+\s*\w/i,
230
+ label: 'SQL string concatenation (SQL injection risk)',
231
+ severity: 'error',
232
+ },
233
+ ];
234
+ const JS_GLOBS = ['*.ts', '*.tsx', '*.js', '*.jsx', '*.mjs', '*.cjs'];
235
+ /**
236
+ * Compile the client's `extraPatterns` into the same shape as the built-ins, so
237
+ * a project rule gets identical treatment: comment stripping, the code/raw view,
238
+ * grouping, sampling and severity.
239
+ *
240
+ * A malformed regex is reported and dropped rather than thrown: one bad entry in
241
+ * a config file must not take down the whole security scan.
242
+ */
243
+ function compileExtraPatterns(ctx) {
244
+ const extra = ctx.config.diffSecurity?.extraPatterns ?? [];
245
+ return extra.flatMap(rule => {
246
+ try {
247
+ // `g`/`y` are stripped: both carry lastIndex state across .test() calls,
248
+ // which would make a rule match every other line.
249
+ const flags = (rule.flags ?? '').replace(/[gy]/g, '');
250
+ return [
251
+ {
252
+ // Anchored on the added-line marker the same way the built-ins are, so
253
+ // a client writes the body of the rule, not the diff plumbing.
254
+ pattern: new RegExp(`^\\+(?!\\+).*(?:${rule.pattern})`, flags),
255
+ label: rule.label,
256
+ severity: rule.severity ?? 'warn',
257
+ view: rule.view ?? 'raw',
258
+ },
259
+ ];
260
+ }
261
+ catch (err) {
262
+ logger.warn(`[Diff Security]: ⚠️ ignoring extraPattern "${rule.label}" — invalid regex: ${err}`);
263
+ return [];
264
+ }
265
+ });
266
+ }
267
+ /**
268
+ * Built-ins minus anything the client switched off by label. `disablePatterns`
269
+ * differs from `ignore`: the rule never runs at all, rather than running and
270
+ * having its findings dropped afterwards.
271
+ */
272
+ function activePatterns(patterns, disabled) {
273
+ if (disabled.length === 0)
274
+ return patterns;
275
+ const lowered = disabled.map(d => d.toLowerCase());
276
+ return patterns.filter(p => !lowered.some(d => p.label.toLowerCase().includes(d)));
277
+ }
278
+ export const diffSecurityCheck = {
279
+ name: 'Diff Security',
280
+ phase: 'informational',
281
+ // No `requiresDiff`: a dangerous call is dangerous whether it arrived in this
282
+ // PR or three years ago, so with no diff range the whole tree is reviewed
283
+ // instead of the check dropping out (ticket 067).
284
+ applies(ctx) {
285
+ return ctx.config.diffSecurity?.enabled !== false;
286
+ },
287
+ async run(ctx) {
288
+ try {
289
+ const cfg = ctx.config.diffSecurity ?? {};
290
+ const found = emptyBuckets();
291
+ const scanOpts = {
292
+ comments: cfg.commentHandling ?? 'language',
293
+ // Setting `ignorePaths` REPLACES the test-path defaults rather than adding
294
+ // to them, matching `duplicate.ignore` and `deadCode.ignoreFiles`. A client
295
+ // who wants their tests scanned says so by listing something else here.
296
+ ignorePaths: cfg.ignorePaths ?? DIFF_SECURITY_IGNORE_DEFAULTS,
297
+ // This check owns the cross-line heuristic, so it is the one that turns it
298
+ // on. `0` from the client switches it off.
299
+ dataflowWindow: cfg.dataflowWindow ?? DEFAULT_DATAFLOW_WINDOW,
300
+ };
301
+ const extra = compileExtraPatterns(ctx);
302
+ const disabled = cfg.disablePatterns ?? [];
303
+ const scanInto = (stdout, patterns) => {
304
+ mergeSeverityBuckets(found, scanDiffPatterns(stdout, activePatterns(patterns, disabled), scanOpts));
305
+ };
306
+ /**
307
+ * Feed one language's sources through the patterns, from the diff when
308
+ * there is one and from the files themselves otherwise.
309
+ *
310
+ * Through {@link reviewLines}, like the four other checks that need both
311
+ * modes. This used to be its body copied inline, on the assumption that a
312
+ * closure was needed to carry `patterns` — it is not, that is what `onChunk`
313
+ * is for, and the copy meant `fullScanBehaviour` and the `null`/`[]`
314
+ * distinction lived in two places, one of them a blocking security check
315
+ * (ticket 079).
316
+ */
317
+ const review = (globs, patterns) => reviewLines(ctx, globs, stdout => scanInto(stdout, patterns));
318
+ // JS/TS patterns always run; language-specific sets scan their own globs
319
+ // only when that language is present, so a Python repo gets Python rules.
320
+ // Client `extraPatterns` run against every scanned language, since a
321
+ // project rule is not tied to the built-in language split.
322
+ const sets = [[JS_GLOBS, [...SECURITY_PATTERNS, ...extra]]];
323
+ if (ctx.languages.includes('python')) {
324
+ sets.push([['*.py'], [...PYTHON_SECURITY_PATTERNS, ...extra]]);
325
+ }
326
+ if (ctx.languages.includes('go')) {
327
+ sets.push([['*.go'], [...GO_SECURITY_PATTERNS, ...extra]]);
328
+ }
329
+ if (ctx.languages.includes('kotlin')) {
330
+ sets.push([
331
+ ['*.kt', '*.kts', '*.java'],
332
+ [...KOTLIN_SECURITY_PATTERNS, ...extra],
333
+ ]);
334
+ }
335
+ for (const [globs, patterns] of sets) {
336
+ // One failed set fails the check. A partial answer is worse than none
337
+ // here: three of five language sets scanned, reported as a pass, reads
338
+ // as a clean repository (ticket 072).
339
+ if (!(await review(globs, patterns)))
340
+ return skip('git unavailable');
341
+ }
342
+ return reportSeverityBuckets(found.errors, found.warnings, {
343
+ prefix: 'Diff Security',
344
+ errorSummary: n => `${n} issue(s)`,
345
+ warningSummary: n => `${n} warning(s)`,
346
+ ...clientFindingOptions(ctx, cfg),
347
+ });
348
+ }
349
+ catch (err) {
350
+ logger.warn(`[Diff Security]: ⚠️ Could not analyze diff\n${err}`);
351
+ return skip('diff unavailable');
352
+ }
353
+ },
354
+ };
@@ -0,0 +1,2 @@
1
+ import { Check } from '../../types.js';
2
+ export declare const dockerfileSecurityCheck: Check;
@@ -0,0 +1,98 @@
1
+ import { execa } from '../../../utils/execa.js';
2
+ import { logger, matchesAnyGlob } from '../../../utils/index.js';
3
+ import { resolveTargetFiles } from '../../targets.js';
4
+ import { pass, skip } from '../../types.js';
5
+ import { clientFindingOptions, reportSeverityBuckets, scanDiffPatterns, scanTrackedFiles, } from '../findings.js';
6
+ const DOCKERFILE_GLOBS = ['**/Dockerfile', '**/Dockerfile.*', '**/*.Dockerfile'];
7
+ /** Common Dockerfile security smells, matched on added diff lines. */
8
+ const DOCKER_PATTERNS = [
9
+ {
10
+ pattern: /^\+(?!\+)\s*FROM\s+\S+:latest\b/i,
11
+ label: 'FROM …:latest (pin the base image to a version/digest)',
12
+ severity: 'warn',
13
+ },
14
+ {
15
+ pattern: /^\+(?!\+)\s*USER\s+root\b/i,
16
+ label: 'USER root (run the container as a non-root user)',
17
+ severity: 'warn',
18
+ },
19
+ {
20
+ pattern: /^\+(?!\+).*\b(?:curl|wget)\b[^|]*\|\s*(?:sudo\s+)?(?:sh|bash)\b/i,
21
+ label: 'piping a download straight to a shell (curl/wget … | sh)',
22
+ severity: 'warn',
23
+ },
24
+ {
25
+ pattern: /^\+(?!\+)\s*ADD\s+https?:\/\//i,
26
+ label: 'ADD from a URL (prefer COPY, or verify a checksum)',
27
+ severity: 'warn',
28
+ },
29
+ {
30
+ // The `_FILE`/`_PATH` exclusion is not a loophole, it is the thing this rule
31
+ // is trying to steer people towards: `ENV DB_PASSWORD_FILE=/run/secrets/db`
32
+ // names a location, holds no secret, and is how Docker and Kubernetes tell
33
+ // you to do it. Flagging the correct practice alongside the wrong one is how
34
+ // a rule gets switched off — and it teaches obscuring the variable name,
35
+ // which makes the next real secret harder to spot, not easier.
36
+ pattern: /^\+(?!\+)\s*(?:ENV|ARG)\s+\w*(?:PASSWORD|SECRET|TOKEN|API_?KEY|ACCESS_KEY)\w*(?<!_FILE)(?<!_PATH)(?<!_FILEPATH)\s*[=\s]/i,
37
+ label: 'secret baked into ENV/ARG (use build secrets / runtime injection)',
38
+ severity: 'warn',
39
+ },
40
+ {
41
+ pattern: /^\+(?!\+).*(?:--no-check-certificate|--insecure)\b/,
42
+ label: 'insecure download flag (--insecure / --no-check-certificate)',
43
+ severity: 'warn',
44
+ },
45
+ {
46
+ pattern: /^\+(?!\+)\s*RUN\s+.*\bsudo\b/,
47
+ label: 'sudo inside RUN (unnecessary and risky in a container build)',
48
+ severity: 'warn',
49
+ },
50
+ ];
51
+ export const dockerfileSecurityCheck = {
52
+ name: 'Dockerfile Security',
53
+ phase: 'informational',
54
+ // No `requiresDiff`: a secret baked into an ENV line is baked in whether the
55
+ // line is new or inherited (ticket 067).
56
+ applies(ctx) {
57
+ return ctx.config.dockerfileSecurity?.enabled !== false;
58
+ },
59
+ async run(ctx) {
60
+ const files = await resolveTargetFiles(ctx, ['*']);
61
+ if (files === null)
62
+ return skip('git unavailable');
63
+ const dockerfiles = files.filter(f => matchesAnyGlob(f, DOCKERFILE_GLOBS));
64
+ if (dockerfiles.length === 0)
65
+ return pass();
66
+ try {
67
+ const cfg = ctx.config.dockerfileSecurity ?? {};
68
+ let stdout = '';
69
+ if (ctx.baseSha) {
70
+ stdout = (await execa('git', ['diff', '--unified=0', ctx.baseSha, ctx.headSha ?? 'HEAD', '--', ...dockerfiles], { cwd: ctx.cwd })).stdout;
71
+ }
72
+ else if (ctx.config.run?.fullScanBehaviour !== 'skip') {
73
+ await scanTrackedFiles(ctx, dockerfiles, asDiff => {
74
+ stdout += `${asDiff}\n`;
75
+ });
76
+ }
77
+ // This check runs `git diff` itself rather than going through
78
+ // `diffAddedLines`, so the `pr-checkmate-ignore` opt-out is applied here.
79
+ const { errors, warnings } = scanDiffPatterns(stdout, DOCKER_PATTERNS, {
80
+ skipIgnored: true,
81
+ // Dockerfiles have no extension to key off, and `#` is their comment
82
+ // marker — the `hash` reading, not the language-detected one.
83
+ comments: 'legacy',
84
+ ignorePaths: cfg.ignorePaths,
85
+ });
86
+ return reportSeverityBuckets(errors, warnings, {
87
+ prefix: 'Dockerfile Security',
88
+ errorSummary: n => `${n} issue(s)`,
89
+ warningSummary: n => `${n} warning(s)`,
90
+ ...clientFindingOptions(ctx, cfg),
91
+ });
92
+ }
93
+ catch (err) {
94
+ logger.warn(`[Dockerfile Security]: ⚠️ Could not analyze diff\n${err}`);
95
+ return skip('diff unavailable');
96
+ }
97
+ },
98
+ };
@@ -0,0 +1,2 @@
1
+ import { Check } from '../../types.js';
2
+ export declare const migrationSafetyCheck: Check;
@@ -0,0 +1,137 @@
1
+ import { execa } from '../../../utils/execa.js';
2
+ import { logger, matchesAnyGlob } from '../../../utils/index.js';
3
+ import { resolveTargetFiles } from '../../targets.js';
4
+ import { pass, skip } from '../../types.js';
5
+ import { bucketTotal, reportCountedFindings, scanTrackedFiles, stripInlineComment, } from '../findings.js';
6
+ /**
7
+ * Paths treated as database migrations. A client overrides via
8
+ * `migrationSafety.paths` (REPLACES this list).
9
+ */
10
+ const DEFAULT_MIGRATION_GLOBS = [
11
+ '**/migrations/**',
12
+ '**/migrate/**',
13
+ '**/db/migrate/**', // Rails
14
+ '**/versions/**', // Alembic
15
+ '**/*.sql',
16
+ ];
17
+ /** Destructive / locking operations, matched on added diff lines. */
18
+ const DDL_PATTERNS = [
19
+ { pattern: /^\+(?!\+).*\bDROP\s+TABLE\b/i, label: 'DROP TABLE — irreversible data loss' },
20
+ { pattern: /^\+(?!\+).*\bDROP\s+COLUMN\b/i, label: 'DROP COLUMN — irreversible data loss' },
21
+ { pattern: /^\+(?!\+).*\bTRUNCATE\b/i, label: 'TRUNCATE — irreversible data loss' },
22
+ {
23
+ pattern: /^\+(?!\+).*\bRENAME\s+(?:COLUMN|TABLE)\b/i,
24
+ label: 'RENAME — breaks code still reading the old name',
25
+ },
26
+ { pattern: /^\+(?!\+).*\bDROP\s+(?:CONSTRAINT|INDEX)\b/i, label: 'DROP CONSTRAINT/INDEX' },
27
+ {
28
+ pattern: /^\+(?!\+).*\bALTER\s+COLUMN\b.*\bSET\s+NOT\s+NULL\b/i,
29
+ label: 'SET NOT NULL — locks the table, rejects existing NULL rows',
30
+ },
31
+ // Alembic (Python) operations.
32
+ { pattern: /^\+(?!\+).*\bop\.drop_column\b/, label: 'op.drop_column — irreversible data loss' },
33
+ { pattern: /^\+(?!\+).*\bop\.drop_table\b/, label: 'op.drop_table — irreversible data loss' },
34
+ { pattern: /^\+(?!\+).*\bop\.drop_constraint\b/, label: 'op.drop_constraint' },
35
+ ];
36
+ const NOT_NULL_NO_DEFAULT = 'ADD COLUMN … NOT NULL without DEFAULT — fails/locks on a non-empty table';
37
+ /**
38
+ * A new NOT NULL column with no DEFAULT: the classic migration that breaks on a
39
+ * populated table. Split out because it's a conjunction (ADD COLUMN + NOT NULL,
40
+ * and NO DEFAULT on the line), not a single keyword.
41
+ */
42
+ function isAddNotNullNoDefault(line) {
43
+ return (/^\+(?!\+)/.test(line) &&
44
+ /\bADD\s+COLUMN\b/i.test(line) &&
45
+ /\bNOT\s+NULL\b/i.test(line) &&
46
+ !/\bDEFAULT\b/i.test(line));
47
+ }
48
+ /**
49
+ * Drop the comment from an added migration line, keeping the leading `+` so the
50
+ * patterns stay anchored on it.
51
+ *
52
+ * This check does its own matching rather than going through `scanDiffPatterns`,
53
+ * and it inherited none of the comment handling — so a commented-out statement
54
+ * was reported as destructive. `-- DROP TABLE users;` does nothing, and calling
55
+ * it "irreversible data loss" is noise on the most alarming label the product
56
+ * prints. Found by ticket 062's corpus.
57
+ *
58
+ * Only the two markers that are unambiguous in the files this check looks at:
59
+ * `--` in SQL and `#` in Python/Ruby migrations. `--` is required to be preceded
60
+ * by whitespace or the line start, which keeps it away from an identifier like
61
+ * `a--b` and from most string contents; `stripInlineComment` handles `#` with the
62
+ * string awareness it already has.
63
+ */
64
+ function withoutComment(line) {
65
+ // The diff marker is split off first: `+-- DROP TABLE` puts `--` immediately
66
+ // after the `+`, where a boundary rule looking for whitespace or line-start
67
+ // does not see it — which is exactly the shape a commented-out statement takes.
68
+ const marker = line.startsWith('+') ? '+' : '';
69
+ const body = stripInlineComment(line.slice(marker.length), 'hash').replace(/(^|\s)--.*$/, '$1');
70
+ return marker + body;
71
+ }
72
+ /** Bucket dangerous added lines by risk label, honouring the opt-out directive. */
73
+ function scan(stdout, findings) {
74
+ for (const line of stdout.split('\n')) {
75
+ if (line.includes('pr-checkmate-ignore'))
76
+ continue;
77
+ // The sample keeps the ORIGINAL line: the reader needs to see what was
78
+ // written, comment and all, even though the match ran on the code.
79
+ const code = withoutComment(line);
80
+ const sample = () => line.slice(1).trim().substring(0, 120);
81
+ for (const { pattern, label } of DDL_PATTERNS) {
82
+ if (pattern.test(code))
83
+ (findings[label] ?? (findings[label] = [])).push(sample());
84
+ }
85
+ if (isAddNotNullNoDefault(code)) {
86
+ (findings[NOT_NULL_NO_DEFAULT] ?? (findings[NOT_NULL_NO_DEFAULT] = [])).push(sample());
87
+ }
88
+ }
89
+ }
90
+ export const migrationSafetyCheck = {
91
+ name: 'Migration Safety',
92
+ phase: 'informational',
93
+ // No `requiresDiff`: a destructive migration is destructive whenever it was
94
+ // written (ticket 067). Over a whole repository this becomes an inventory of
95
+ // the irreversible migrations already in the history, which is worth having.
96
+ applies(ctx) {
97
+ return ctx.config.migrationSafety?.enabled !== false;
98
+ },
99
+ async run(ctx) {
100
+ // Not sourcePath-scoped: migrations commonly live outside `src` (db/, alembic/).
101
+ // ignoreDirs still applies via resolveTargetFiles.
102
+ const files = await resolveTargetFiles(ctx, ['*']);
103
+ if (files === null)
104
+ return skip('git unavailable');
105
+ const globs = ctx.config.migrationSafety?.paths ?? DEFAULT_MIGRATION_GLOBS;
106
+ const migrationFiles = files.filter(f => matchesAnyGlob(f, globs));
107
+ if (migrationFiles.length === 0)
108
+ return pass();
109
+ try {
110
+ let stdout = '';
111
+ if (ctx.baseSha) {
112
+ stdout = (await execa('git', ['diff', '--unified=0', ctx.baseSha, ctx.headSha ?? 'HEAD', '--', ...migrationFiles], { cwd: ctx.cwd })).stdout;
113
+ }
114
+ else if (ctx.config.run?.fullScanBehaviour !== 'skip') {
115
+ await scanTrackedFiles(ctx, migrationFiles, asDiff => {
116
+ stdout += `${asDiff}\n`;
117
+ });
118
+ }
119
+ const findings = {};
120
+ scan(stdout, findings);
121
+ if (bucketTotal(findings) === 0)
122
+ return pass();
123
+ return reportCountedFindings(findings, ctx, {
124
+ prefix: 'Migration Safety',
125
+ severity: ctx.config.migrationSafety?.severity,
126
+ sampleLimit: ctx.config.log?.sampleLimit ?? 2,
127
+ // The labels carry an explanatory tail ("… — rewrites every row"); the
128
+ // summary is a one-line tally, so only the name of the risk fits.
129
+ summaryLabel: label => label.split(' — ')[0],
130
+ });
131
+ }
132
+ catch (err) {
133
+ logger.warn(`[Migration Safety]: ⚠️ Could not analyze diff\n${err}`);
134
+ return skip('diff unavailable');
135
+ }
136
+ },
137
+ };
@@ -0,0 +1,63 @@
1
+ import { Check } from '../../types.js';
2
+ /**
3
+ * A HOME the scanner can actually write to.
4
+ *
5
+ * The bundled wrapper caches the gitleaks binary in `os.homedir()/.gitleaks-cache`
6
+ * and offers no way to move it — the path is hardcoded. So in any environment
7
+ * where HOME is not writable it crashes before scanning a single commit. That is
8
+ * not exotic: it is what the container does under `--user "$(id -u):$(id -g)"`,
9
+ * the invocation our own entrypoint and docs recommend, where HOME is `/`.
10
+ *
11
+ * Redirecting to the temp directory costs nothing that was available anyway — if
12
+ * HOME cannot be written to, there was no `~/.gitconfig` of ours to lose either.
13
+ */
14
+ /**
15
+ * How many secrets the scan actually found.
16
+ *
17
+ * The row used to read `❌ Security Scan: potential secrets detected` whether the
18
+ * number was one or thirty-nine, and that is not a cosmetic gap. It is the reason
19
+ * a real regression nearly shipped: an allowlist entry removed six genuine
20
+ * `Generic API Key` findings from a client repository, 39 → 33, and the A/B sweep
21
+ * that compares report rows across 28 repositories saw two identical lines
22
+ * (ticket 085). A check that finds things has to say how many, or nothing can
23
+ * tell whether it started finding fewer.
24
+ *
25
+ * Read from gitleaks' JSON report rather than counted out of its console output —
26
+ * the same lesson as ticket 078, where the clone count was parsed from an English
27
+ * sentence and would have reported zero on a repository full of duplication.
28
+ *
29
+ * @returns The count, or `null` when the report could not be read — in which case
30
+ * the caller keeps its old wording rather than claiming a number it does not have.
31
+ */
32
+ export declare function countFindings(reportPath: string): number | null;
33
+ /**
34
+ * How the outcome names what was found.
35
+ *
36
+ * Its own function so both halves are reachable without running the scanner. The
37
+ * corpus for this check deliberately does not: the wrapper downloads a gitleaks
38
+ * binary on first use, and a unit suite that reaches the network is the thing the
39
+ * `installer` seam in `ensure.ts` exists to avoid. What broke here was the wording
40
+ * — a row that read the same for one secret and for thirty-nine — and the wording
41
+ * is testable on its own.
42
+ *
43
+ * `null` keeps the old sentence rather than inventing a number: a report we could
44
+ * not read is not a reason to claim a count.
45
+ */
46
+ export declare function secretsSummary(found: number | null): string;
47
+ /**
48
+ * Whether the wrapper died instead of reporting, judged from its stderr.
49
+ *
50
+ * The wrapper is a Node script, and Node exits **1** on an unhandled exception —
51
+ * the same code gitleaks itself uses for "secrets found". Left undistinguished,
52
+ * a scanner that never ran is reported as `potential secrets detected`, pointing
53
+ * at a report file that was never written. A gate accusing a clean repository is
54
+ * the same class of failure as one that stays quiet about a real leak, and this
55
+ * is the only signal available to tell them apart.
56
+ */
57
+ export declare function looksLikeCrash(stderr: string): boolean;
58
+ /**
59
+ * Secret scanning via the bundled gitleaks package. Language-agnostic — runs on
60
+ * every repo (Node, Python, C++, mobile). Secrets found → fail (blocking).
61
+ * Tooling/infra errors → warn, so a scanner hiccup never blocks an unrelated PR.
62
+ */
63
+ export declare const securityCheck: Check;