pr-checkmate 1.23.23 → 2.0.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 (101) hide show
  1. package/README.md +68 -15
  2. package/cspell.json +3 -8
  3. package/dist/cli.js +37 -62
  4. package/dist/config/constants.d.ts +21 -3
  5. package/dist/config/constants.js +33 -6
  6. package/dist/config/pr-checkmate-workflow.yml +33 -327
  7. package/dist/core/checks/dependencies/banned-imports.js +23 -24
  8. package/dist/core/checks/dependencies/circular-deps.js +1 -0
  9. package/dist/core/checks/dependencies/dependency-check.js +1 -0
  10. package/dist/core/checks/dependencies/grype-scan.js +1 -0
  11. package/dist/core/checks/dependencies/npm-audit.js +6 -1
  12. package/dist/core/checks/dependencies/vuln-scan.js +1 -0
  13. package/dist/core/checks/findings.d.ts +198 -19
  14. package/dist/core/checks/findings.js +474 -22
  15. package/dist/core/checks/git/custom-rules.js +21 -16
  16. package/dist/core/checks/git/diff-smell.d.ts +17 -0
  17. package/dist/core/checks/git/diff-smell.js +43 -24
  18. package/dist/core/checks/git/large-files.js +14 -2
  19. package/dist/core/checks/git/leftover-debug.js +23 -14
  20. package/dist/core/checks/git/lockfile-drift.js +2 -1
  21. package/dist/core/checks/git/merge-conflict.js +19 -8
  22. package/dist/core/checks/git/missing-tests.js +22 -6
  23. package/dist/core/checks/git/todo-fixme.js +10 -9
  24. package/dist/core/checks/languages/shellcheck.d.ts +8 -0
  25. package/dist/core/checks/languages/shellcheck.js +55 -0
  26. package/dist/core/checks/languages/typecheck.js +1 -0
  27. package/dist/core/checks/pr/pr-size-check.js +2 -1
  28. package/dist/core/checks/quality/config-validation.d.ts +14 -4
  29. package/dist/core/checks/quality/config-validation.js +119 -17
  30. package/dist/core/checks/quality/dead-code.js +1 -0
  31. package/dist/core/checks/quality/duplicate-check.js +1 -0
  32. package/dist/core/checks/quality/license-header.js +12 -2
  33. package/dist/core/checks/quality/spellcheck.d.ts +50 -0
  34. package/dist/core/checks/quality/spellcheck.js +141 -13
  35. package/dist/core/checks/quality/symlinks.d.ts +16 -0
  36. package/dist/core/checks/quality/symlinks.js +62 -0
  37. package/dist/core/checks/quality/yaml-lint.js +22 -9
  38. package/dist/core/checks/security/diff-security.js +111 -28
  39. package/dist/core/checks/security/dockerfile-security.js +23 -20
  40. package/dist/core/checks/security/migration-safety.js +19 -17
  41. package/dist/core/checks/security/sensitive-file-guard.js +37 -5
  42. package/dist/core/checks/security/workflow-security.d.ts +10 -0
  43. package/dist/core/checks/security/workflow-security.js +48 -26
  44. package/dist/core/commands.d.ts +27 -0
  45. package/dist/core/commands.js +91 -0
  46. package/dist/core/context.d.ts +12 -3
  47. package/dist/core/context.js +118 -16
  48. package/dist/core/install/cache.d.ts +39 -0
  49. package/dist/core/install/cache.js +99 -0
  50. package/dist/core/install/doctor.d.ts +35 -0
  51. package/dist/core/install/doctor.js +145 -0
  52. package/dist/core/install/ensure.d.ts +60 -0
  53. package/dist/core/install/ensure.js +169 -0
  54. package/dist/core/install/lock.d.ts +33 -0
  55. package/dist/core/install/lock.js +99 -0
  56. package/dist/core/install/profiles.d.ts +64 -0
  57. package/dist/core/install/profiles.js +170 -0
  58. package/dist/core/registry.js +4 -0
  59. package/dist/core/reporters.d.ts +13 -2
  60. package/dist/core/reporters.js +145 -104
  61. package/dist/core/run-checks.js +91 -14
  62. package/dist/core/targets.js +26 -4
  63. package/dist/core/types.d.ts +49 -1
  64. package/dist/init.d.ts +29 -14
  65. package/dist/init.js +204 -262
  66. package/dist/interfaces/index.d.ts +130 -0
  67. package/dist/scripts/generate-install-manifests.d.ts +39 -0
  68. package/dist/scripts/generate-install-manifests.js +121 -0
  69. package/dist/scripts/publish-github.js +18 -4
  70. package/dist/utils/detect-language.d.ts +37 -4
  71. package/dist/utils/detect-language.js +113 -19
  72. package/dist/utils/http.d.ts +59 -0
  73. package/dist/utils/http.js +119 -0
  74. package/dist/utils/logger.d.ts +52 -6
  75. package/dist/utils/logger.js +125 -33
  76. package/dist/utils/pool.d.ts +49 -0
  77. package/dist/utils/pool.js +124 -0
  78. package/dist/utils/update-notifier.d.ts +9 -0
  79. package/dist/utils/update-notifier.js +57 -3
  80. package/eslint.config.mjs +14 -2
  81. package/install-manifests/commitlint/package-lock.json +1028 -0
  82. package/install-manifests/commitlint/package.json +9 -0
  83. package/install-manifests/core/package-lock.json +1335 -0
  84. package/install-manifests/core/package.json +11 -0
  85. package/install-manifests/cpp/package-lock.json +29 -0
  86. package/install-manifests/cpp/package.json +8 -0
  87. package/install-manifests/duplicate/package-lock.json +113 -0
  88. package/install-manifests/duplicate/package.json +8 -0
  89. package/install-manifests/js/package-lock.json +5099 -0
  90. package/install-manifests/js/package.json +26 -0
  91. package/install-manifests/markdown/package-lock.json +1281 -0
  92. package/install-manifests/markdown/package.json +8 -0
  93. package/install-manifests/python/package-lock.json +21 -0
  94. package/install-manifests/python/package.json +8 -0
  95. package/install-manifests/spellcheck/package-lock.json +1047 -0
  96. package/install-manifests/spellcheck/package.json +8 -0
  97. package/package.json +13 -28
  98. package/pr-checkmate.schema.json +1070 -96
  99. package/src/config/cspell.json +3 -8
  100. package/src/config/pr-checkmate-workflow.yml +33 -327
  101. package/src/config/pr-checkmate.schema.json +1070 -96
@@ -1,353 +1,59 @@
1
- name: PR Checkmate Quality Checks
1
+ name: PR CheckMate
2
2
 
3
3
  on:
4
4
  pull_request:
5
5
  branches: [main, master, develop]
6
6
  types: [opened, synchronize, reopened]
7
7
 
8
+ # Least privilege. `pull-requests: write` is what lets the run upsert its summary
9
+ # comment on the PR; drop it and the checks still run, they just report to the log.
8
10
  permissions:
9
- contents: write
11
+ contents: read
10
12
  pull-requests: write
11
13
 
12
14
  jobs:
13
- pr-checkmate-all:
14
- name: PR Checkmate All Checks
15
+ pr-checkmate:
16
+ name: PR CheckMate
15
17
  runs-on: ubuntu-latest
16
18
  steps:
17
19
  - name: Checkout code
18
- uses: actions/checkout@v4
20
+ uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
19
21
  with:
20
- ref: ${{ github.head_ref }}
22
+ # Required, not optional. Without the full history the PR base commit is
23
+ # not in the clone, no diff range can be built, and every diff-based
24
+ # check — Diff Security, Workflow Security, Dockerfile Security,
25
+ # Sensitive Files and a dozen others — skips itself. The run then says
26
+ # `Scan Scope: … set fetch-depth: 0`, which is this line.
21
27
  fetch-depth: 0
22
28
 
23
29
  - name: Setup Node.js
24
- uses: actions/setup-node@v4
30
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
25
31
  with:
26
32
  node-version: 24
33
+ cache: 'npm'
27
34
 
28
35
  - name: Install dependencies
29
36
  run: npm ci
30
37
 
31
- - name: Run PR Checkmate All Checks
32
- run: npx pr-checkmate all
33
- continue-on-error: true
38
+ # PR CheckMate fetches only the tooling this repository turns out to need
39
+ # (`npx pr-checkmate doctor` prints what and why). Without this step that
40
+ # tooling is fetched again on every run: the download shrinks, the wait
41
+ # does not. The key carries the pr-checkmate version, so an upgrade fetches
42
+ # afresh instead of reusing tooling meant for the previous one.
43
+ - name: Cache PR CheckMate tooling
44
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
45
+ with:
46
+ path: ~/.cache/pr-checkmate
47
+ key: pr-checkmate-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
48
+ restore-keys: |
49
+ pr-checkmate-${{ runner.os }}-
34
50
 
35
- - name: Auto-commit formatting changes
36
- run: |
37
- git config user.name "github-actions[bot]"
38
- git config user.email "github-actions[bot]@users.noreply.github.com"
39
- git add -A
40
- if ! git diff --cached --quiet; then
41
- git commit -m "style: auto-format code with Prettier"
42
- git push origin HEAD:${{ github.head_ref }}
43
- echo "Formatting changes committed and pushed"
44
- else
45
- echo "No formatting changes needed"
46
- fi
51
+ # One job runs the whole registry. Splitting it per check would repeat the
52
+ # checkout and install for every one of them, and the selection of what runs
53
+ # belongs in pr-checkmate.json (`severity`), not in copied YAML.
54
+ - name: Run PR CheckMate
47
55
  env:
56
+ # Not injected automatically: without this the run cannot authenticate,
57
+ # and the summary comment silently never reaches the PR.
48
58
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49
-
50
- lint:
51
- name: ESLint
52
- runs-on: ubuntu-latest
53
- steps:
54
- - name: Checkout code
55
- uses: actions/checkout@v4
56
-
57
- - name: Setup Node.js
58
- uses: actions/setup-node@v4
59
- with:
60
- node-version: 24
61
-
62
- - name: Install dependencies
63
- run: npm ci
64
-
65
- - name: Run ESLint
66
- run: npx pr-checkmate lint
67
- continue-on-error: true
68
-
69
- prettier:
70
- name: Prettier
71
- runs-on: ubuntu-latest
72
- steps:
73
- - name: Checkout code
74
- uses: actions/checkout@v4
75
-
76
- - name: Setup Node.js
77
- uses: actions/setup-node@v4
78
- with:
79
- node-version: 24
80
-
81
- - name: Install dependencies
82
- run: npm ci
83
-
84
- - name: Run Prettier
85
- run: npx pr-checkmate prettier
86
- continue-on-error: true
87
-
88
- spellcheck:
89
- name: Spellcheck
90
- runs-on: ubuntu-latest
91
- steps:
92
- - name: Checkout code
93
- uses: actions/checkout@v4
94
-
95
- - name: Setup Node.js
96
- uses: actions/setup-node@v4
97
- with:
98
- node-version: 24
99
-
100
- - name: Install dependencies
101
- run: npm ci
102
-
103
- - name: Run Spellcheck
104
- run: npx pr-checkmate spellcheck
105
- continue-on-error: true
106
-
107
- security:
108
- name: Security Scan
109
- runs-on: ubuntu-latest
110
- steps:
111
- - name: Checkout code
112
- uses: actions/checkout@v4
113
- with:
114
- fetch-depth: 0
115
-
116
- - name: Setup Node.js
117
- uses: actions/setup-node@v4
118
- with:
119
- node-version: 24
120
-
121
- - name: Install dependencies
122
- run: npm ci
123
-
124
- - name: Run Security Scan
125
- run: npx pr-checkmate security
126
- continue-on-error: true
127
-
128
- dependency-check:
129
- name: Dependency Check
130
- runs-on: ubuntu-latest
131
- steps:
132
- - name: Checkout code
133
- uses: actions/checkout@v4
134
- with:
135
- fetch-depth: 0
136
-
137
- - name: Setup Node.js
138
- uses: actions/setup-node@v4
139
- with:
140
- node-version: 24
141
-
142
- - name: Install dependencies
143
- run: npm ci
144
-
145
- - name: Run Dependency Check
146
- run: npx pr-checkmate dependencies
147
- continue-on-error: true
148
-
149
- circular-deps:
150
- name: Circular Dependencies
151
- runs-on: ubuntu-latest
152
- steps:
153
- - name: Checkout code
154
- uses: actions/checkout@v4
155
-
156
- - name: Setup Node.js
157
- uses: actions/setup-node@v4
158
- with:
159
- node-version: 24
160
-
161
- - name: Install dependencies
162
- run: npm ci
163
-
164
- - name: Run Circular Dependency Check
165
- run: npx pr-checkmate circular
166
- continue-on-error: true
167
-
168
- license-check:
169
- name: License Check
170
- runs-on: ubuntu-latest
171
- steps:
172
- - name: Checkout code
173
- uses: actions/checkout@v4
174
-
175
- - name: Setup Node.js
176
- uses: actions/setup-node@v4
177
- with:
178
- node-version: 24
179
-
180
- - name: Install dependencies
181
- run: npm ci
182
-
183
- - name: Run License Check
184
- run: npx pr-checkmate license
185
- continue-on-error: true
186
-
187
- pr-size:
188
- name: PR Size
189
- runs-on: ubuntu-latest
190
- steps:
191
- - name: Checkout code
192
- uses: actions/checkout@v4
193
- with:
194
- fetch-depth: 0
195
-
196
- - name: Setup Node.js
197
- uses: actions/setup-node@v4
198
- with:
199
- node-version: 24
200
-
201
- - name: Install dependencies
202
- run: npm ci
203
-
204
- - name: Check PR Size
205
- run: npx pr-checkmate pr-size
206
- continue-on-error: true
207
-
208
- pr-title:
209
- name: PR Title
210
- runs-on: ubuntu-latest
211
- steps:
212
- - name: Checkout code
213
- uses: actions/checkout@v4
214
-
215
- - name: Setup Node.js
216
- uses: actions/setup-node@v4
217
- with:
218
- node-version: 24
219
-
220
- - name: Install dependencies
221
- run: npm ci
222
-
223
- - name: Check PR Title
224
- run: npx pr-checkmate pr-title
225
- continue-on-error: true
226
-
227
- outdated-deps:
228
- name: Outdated Dependencies
229
- runs-on: ubuntu-latest
230
- steps:
231
- - name: Checkout code
232
- uses: actions/checkout@v4
233
-
234
- - name: Setup Node.js
235
- uses: actions/setup-node@v4
236
- with:
237
- node-version: 24
238
-
239
- - name: Install dependencies
240
- run: npm ci
241
-
242
- - name: Check Outdated Dependencies
243
- run: npx pr-checkmate outdated
244
- continue-on-error: true
245
-
246
- markdown-lint:
247
- name: Markdown Lint
248
- runs-on: ubuntu-latest
249
- steps:
250
- - name: Checkout code
251
- uses: actions/checkout@v4
252
- with:
253
- fetch-depth: 0
254
-
255
- - name: Setup Node.js
256
- uses: actions/setup-node@v4
257
- with:
258
- node-version: 24
259
-
260
- - name: Install dependencies
261
- run: npm ci
262
-
263
- - name: Run Markdown Lint
264
- run: npx pr-checkmate markdown
265
- continue-on-error: true
266
-
267
- typecheck:
268
- name: TypeScript Type Check
269
- runs-on: ubuntu-latest
270
- steps:
271
- - name: Checkout code
272
- uses: actions/checkout@v4
273
- with:
274
- ref: ${{ github.head_ref }}
275
- fetch-depth: 0
276
-
277
- - name: Setup Node.js
278
- uses: actions/setup-node@v4
279
- with:
280
- node-version: 24
281
-
282
- - name: Install dependencies
283
- run: npm ci
284
-
285
- - name: Run TypeScript Type Check
286
- run: npx pr-checkmate typecheck
287
- continue-on-error: true
288
-
289
- diff-smell:
290
- name: Diff Code Smell
291
- runs-on: ubuntu-latest
292
- steps:
293
- - name: Checkout code
294
- uses: actions/checkout@v4
295
- with:
296
- ref: ${{ github.head_ref }}
297
- fetch-depth: 0
298
-
299
- - name: Setup Node.js
300
- uses: actions/setup-node@v4
301
- with:
302
- node-version: 24
303
-
304
- - name: Install dependencies
305
- run: npm ci
306
-
307
- - name: Scan Diff for Code Smells
308
- run: npx pr-checkmate diff-smell
309
- continue-on-error: true
310
-
311
- pr-body:
312
- name: PR Description
313
- runs-on: ubuntu-latest
314
- steps:
315
- - name: Checkout code
316
- uses: actions/checkout@v4
317
- with:
318
- ref: ${{ github.head_ref }}
319
- fetch-depth: 0
320
-
321
- - name: Setup Node.js
322
- uses: actions/setup-node@v4
323
- with:
324
- node-version: 24
325
-
326
- - name: Install dependencies
327
- run: npm ci
328
-
329
- - name: Check PR Description
330
- run: npx pr-checkmate pr-body
331
- continue-on-error: true
332
-
333
- duplicate-check:
334
- name: Duplicate Code
335
- runs-on: ubuntu-latest
336
- steps:
337
- - name: Checkout code
338
- uses: actions/checkout@v4
339
- with:
340
- ref: ${{ github.head_ref }}
341
- fetch-depth: 0
342
-
343
- - name: Setup Node.js
344
- uses: actions/setup-node@v4
345
- with:
346
- node-version: 24
347
-
348
- - name: Install dependencies
349
- run: npm ci
350
-
351
- - name: Check for Duplicate Code
352
- run: npx pr-checkmate duplicate
353
- continue-on-error: true
59
+ run: npx pr-checkmate all
@@ -27,41 +27,40 @@ function compileBans(ctx) {
27
27
  exports.bannedImportsCheck = {
28
28
  name: 'Banned Imports',
29
29
  phase: 'informational',
30
+ // No `requiresDiff`: a banned import is banned wherever it is, not only where
31
+ // it was just introduced (ticket 067).
30
32
  applies(ctx) {
31
- return (ctx.config.bannedImports?.length ?? 0) > 0 && Boolean(ctx.baseSha);
33
+ return (ctx.config.bannedImports?.length ?? 0) > 0;
32
34
  },
33
35
  async run(ctx) {
34
- var _a;
35
36
  const bans = compileBans(ctx);
36
37
  if (bans.length === 0)
37
38
  return (0, types_1.pass)('no banned imports configured');
38
39
  try {
39
- const stdout = await (0, findings_1.diffAddedLines)(ctx, ['*']);
40
40
  const errors = {};
41
41
  const warnings = {};
42
- for (const raw of stdout.split('\n')) {
43
- if (!raw.startsWith('+') || raw.startsWith('+++'))
44
- continue;
45
- const content = raw.slice(1);
46
- for (const ban of bans) {
47
- if (ban.re.test(content)) {
48
- const bucket = ban.severity === 'error' ? errors : warnings;
49
- (bucket[_a = ban.message] ?? (bucket[_a] = [])).push(content.trim().substring(0, 100));
42
+ await (0, findings_1.reviewLines)(ctx, ['*'], stdout => {
43
+ var _a;
44
+ for (const raw of stdout.split('\n')) {
45
+ if (!raw.startsWith('+') || raw.startsWith('+++'))
46
+ continue;
47
+ const content = raw.slice(1);
48
+ for (const ban of bans) {
49
+ if (ban.re.test(content)) {
50
+ const bucket = ban.severity === 'error' ? errors : warnings;
51
+ (bucket[_a = ban.message] ?? (bucket[_a] = [])).push(content.trim().substring(0, 100));
52
+ }
50
53
  }
51
54
  }
52
- }
53
- const totalErrors = (0, findings_1.bucketTotal)(errors);
54
- const totalWarnings = (0, findings_1.bucketTotal)(warnings);
55
- if (totalErrors === 0 && totalWarnings === 0)
56
- return (0, types_1.pass)();
57
- (0, findings_1.logFindings)(errors, { prefix: PREFIX, isError: true, sampleLimit: 3 });
58
- (0, findings_1.logFindings)(warnings, { prefix: PREFIX, sampleLimit: 3 });
59
- const parts = [];
60
- if (totalErrors > 0)
61
- parts.push(`${totalErrors} banned (error)`);
62
- if (totalWarnings > 0)
63
- parts.push(`${totalWarnings} banned (warn)`);
64
- return totalErrors > 0 ? (0, types_1.fail)(parts.join(', ')) : (0, types_1.warn)(parts.join(', '));
55
+ });
56
+ // A ban configured as "error" blocks the run, regardless of phase — that
57
+ // is the default `failOn`, and the client can still relax it per repo.
58
+ return (0, findings_1.reportSeverityBuckets)(errors, warnings, {
59
+ prefix: PREFIX,
60
+ errorSummary: n => `${n} banned (error)`,
61
+ warningSummary: n => `${n} banned (warn)`,
62
+ ...(0, findings_1.clientFindingOptions)(ctx),
63
+ });
65
64
  }
66
65
  catch (err) {
67
66
  utils_1.logger.warn(`[Banned Imports]: ⚠️ Could not analyze diff\n${err}`);
@@ -73,6 +73,7 @@ function readReport(reportPath) {
73
73
  exports.circularDepsCheck = {
74
74
  name: 'Circular Deps',
75
75
  phase: 'blocking',
76
+ weight: 'heavy',
76
77
  applies(ctx) {
77
78
  if (ctx.config.circularDeps?.enabled === false)
78
79
  return false;
@@ -102,6 +102,7 @@ function filesUsing(issues, name) {
102
102
  exports.dependencyCheck = {
103
103
  name: 'Dependencies',
104
104
  phase: 'blocking',
105
+ weight: 'heavy',
105
106
  applies(ctx) {
106
107
  if (ctx.config.dependency?.enabled === false)
107
108
  return false;
@@ -45,6 +45,7 @@ function severityRank(severity) {
45
45
  exports.grypeScanCheck = {
46
46
  name: 'Grype Scan',
47
47
  phase: 'informational',
48
+ weight: 'heavy',
48
49
  applies(ctx) {
49
50
  return ctx.config.grypeScan?.enabled !== false;
50
51
  },
@@ -37,7 +37,12 @@ exports.npmAuditCheck = {
37
37
  return node_fs_1.default.existsSync(node_path_1.default.join(ctx.cwd, 'package.json'));
38
38
  },
39
39
  async run(ctx) {
40
- const auditLevel = ctx.config.security?.['npm-audit']?.auditLevel ?? 'moderate';
40
+ // `high`, not `moderate`. A moderate CVE in a direct dependency often has no
41
+ // fix available, and blocking on it stops the team shipping anything at all —
42
+ // indefinitely, for a risk they have usually already accepted. A gate that
43
+ // cannot be satisfied gets switched off, and then the high ones stop blocking
44
+ // too. Clients who want the stricter line set `security.npm-audit.auditLevel`.
45
+ const auditLevel = ctx.config.security?.['npm-audit']?.auditLevel ?? 'high';
41
46
  const ignore = new Set((ctx.config.security?.['npm-audit']?.ignore ?? []).map(name => name.toLowerCase()));
42
47
  const ownName = getOwnPackageName();
43
48
  const { stdout } = await (0, execa_1.execa)('npm', ['audit', '--json'], { cwd: ctx.cwd, reject: false });
@@ -19,6 +19,7 @@ const DEFAULT_TIMEOUT_MS = 120000;
19
19
  exports.vulnScanCheck = {
20
20
  name: 'Vuln Scan',
21
21
  phase: 'informational',
22
+ weight: 'heavy',
22
23
  applies(ctx) {
23
24
  return ctx.config.vulnScan?.enabled === true;
24
25
  },