pr-checkmate 3.2.2 → 3.2.3
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.
- package/dist/cjs/config/pr-checkmate.template.json +393 -0
- package/dist/cjs/init.d.ts +8 -0
- package/dist/cjs/init.js +48 -1
- package/dist/cjs/scripts/copy-configs.js +9 -0
- package/dist/esm/config/pr-checkmate.template.json +393 -0
- package/dist/esm/init.d.ts +8 -0
- package/dist/esm/init.js +47 -1
- package/dist/esm/scripts/copy-configs.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/Mybono/pr_checkmate_public/main/pr-checkmate.schema.json",
|
|
3
|
+
"//": "PR CheckMate configuration template. Place this file at your repository root as 'pr-checkmate.json'. Every value below is the built-in DEFAULT — delete any block you do not want to change, because the file is deep-merged with the defaults. Keys starting with '//' are comments and are ignored. Full per-check reference: https://github.com/Mybono/pr_checkmate_public",
|
|
4
|
+
"//excludePaths": "FILES AND FOLDERS NO CHECK EVER LOOKS AT, as globs: \"src/generated/**\" for a whole folder, \"vendor/legacy.ts\" for one file. Applied where every check gets its file list, so the rule is written once rather than per check. Use this before reaching for a per-check ignore; use 'ignoreDirs' only when you mean a directory NAME wherever it appears.",
|
|
5
|
+
"excludePaths": [],
|
|
6
|
+
"//1-scope": "WHERE CHECKS LOOK. 'sourcePath' may be a string or an array. 'ignoreDirs' REPLACES the default ignore list rather than extending it, so copy the defaults you still want — the defaults cover build output, dependency and report directories, plus generated 'graphify-out'. Test directories are deliberately NOT in it: test code is still linted, type-checked and formatted, and is excluded per-check where it is noise (see 'duplicate', 'deadCode', 'diffSecurity' and the bundled cspell ignores).",
|
|
7
|
+
"sourcePath": ".",
|
|
8
|
+
"//2-severity": "UNIVERSAL ON/OFF SWITCH, keyed by a check's DISPLAY NAME (see //check-names below). 'off' removes the check before it runs; 'error' promotes a warning to a failure; 'warn' demotes a failure to a warning. This works for every check, including those with no 'enabled' flag of their own.",
|
|
9
|
+
"severity": {},
|
|
10
|
+
"//check-names": [
|
|
11
|
+
"Banned Imports",
|
|
12
|
+
"Circular Deps",
|
|
13
|
+
"Dependencies",
|
|
14
|
+
"Grype Scan",
|
|
15
|
+
"License Check",
|
|
16
|
+
"NPM Audit",
|
|
17
|
+
"Outdated Deps",
|
|
18
|
+
"Vuln Scan",
|
|
19
|
+
"Custom Rules",
|
|
20
|
+
"Diff Smells",
|
|
21
|
+
"Large Files",
|
|
22
|
+
"Leftover Debug",
|
|
23
|
+
"Lockfile Drift",
|
|
24
|
+
"Merge Conflict",
|
|
25
|
+
"Missing Tests",
|
|
26
|
+
"TODO/FIXME",
|
|
27
|
+
"ESLint",
|
|
28
|
+
"TypeScript",
|
|
29
|
+
"Prettier",
|
|
30
|
+
"Ruff Lint",
|
|
31
|
+
"Ruff Format",
|
|
32
|
+
"Python Types",
|
|
33
|
+
"C++ Format",
|
|
34
|
+
"SwiftLint",
|
|
35
|
+
"ktlint",
|
|
36
|
+
"Go Vet",
|
|
37
|
+
"Go Format",
|
|
38
|
+
"Clippy",
|
|
39
|
+
"Rustfmt",
|
|
40
|
+
"C# Format",
|
|
41
|
+
"RuboCop",
|
|
42
|
+
"PHP CS Fixer",
|
|
43
|
+
"Commitlint",
|
|
44
|
+
"PR Body",
|
|
45
|
+
"PR Size",
|
|
46
|
+
"PR Title",
|
|
47
|
+
"Case Collision",
|
|
48
|
+
"Config Validation",
|
|
49
|
+
"Coverage",
|
|
50
|
+
"Dead Code",
|
|
51
|
+
"Duplicate Code",
|
|
52
|
+
"License Header",
|
|
53
|
+
"Markdown",
|
|
54
|
+
"Spellcheck",
|
|
55
|
+
"YAML Lint",
|
|
56
|
+
"Broken Symlinks",
|
|
57
|
+
"ShellCheck",
|
|
58
|
+
"Security Scan",
|
|
59
|
+
"Diff Security",
|
|
60
|
+
"Dockerfile Security",
|
|
61
|
+
"Migration Safety",
|
|
62
|
+
"Sensitive Files",
|
|
63
|
+
"Workflow Security"
|
|
64
|
+
],
|
|
65
|
+
"//3-security": "Secret scanning and dependency vulnerabilities.",
|
|
66
|
+
"security": {
|
|
67
|
+
"gitleaks": {
|
|
68
|
+
"enabled": true
|
|
69
|
+
},
|
|
70
|
+
"npm-audit": {
|
|
71
|
+
"enabled": true,
|
|
72
|
+
"//auditLevel": "info | low | moderate | high | critical. Only DIRECT dependencies at or above this level block. Default 'high': a moderate CVE often has no fix available, and blocking on it stops releases indefinitely for a risk most teams have already accepted. Set 'moderate' for a stricter line.",
|
|
73
|
+
"auditLevel": "high",
|
|
74
|
+
"//ignore": "Package names that never block, but are still reported as warnings.",
|
|
75
|
+
"ignore": []
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"//diffSecurity": "'ignorePaths' skips whole files by glob; setting it REPLACES the test-path defaults shown here, which exist because a security test's job is to contain the exact constructs this check hunts for. 'ignore' silences a finding LABEL everywhere instead. 'dataflowWindow' is how many added lines a value stays tainted for, so `const q = `...${x}`` on one line and `db.query(q)` on the next are still connected — a heuristic with no scopes and no reassignment tracking, so it only ever advises; 0 switches it off.",
|
|
79
|
+
"diffSecurity": {
|
|
80
|
+
"enabled": true,
|
|
81
|
+
"ignore": [],
|
|
82
|
+
"dataflowWindow": 10,
|
|
83
|
+
"ignorePaths": [
|
|
84
|
+
"**/__tests__/**",
|
|
85
|
+
"**/__mocks__/**",
|
|
86
|
+
"**/*.test.*",
|
|
87
|
+
"**/*.spec.*",
|
|
88
|
+
"**/test/**",
|
|
89
|
+
"**/tests/**"
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"workflowSecurity": {
|
|
93
|
+
"enabled": true,
|
|
94
|
+
"ignore": []
|
|
95
|
+
},
|
|
96
|
+
"dockerfileSecurity": {
|
|
97
|
+
"enabled": true,
|
|
98
|
+
"ignore": []
|
|
99
|
+
},
|
|
100
|
+
"//sensitiveFileGuard": "Flags .env files, private keys, CI config and lockfiles. 'ignorePaths' excuses ONE file by glob (a .pem test fixture); 'ignore' silences a whole CATEGORY and would excuse the next real key too — reach for ignorePaths first.",
|
|
101
|
+
"sensitiveFileGuard": {
|
|
102
|
+
"enabled": true,
|
|
103
|
+
"ignorePaths": []
|
|
104
|
+
},
|
|
105
|
+
"migrationSafety": {
|
|
106
|
+
"enabled": true,
|
|
107
|
+
"severity": "warn",
|
|
108
|
+
"//paths": "Globs treated as migrations. Setting this REPLACES the defaults listed here.",
|
|
109
|
+
"paths": ["**/migrations/**", "**/migrate/**", "**/db/migrate/**", "**/versions/**", "**/*.sql"]
|
|
110
|
+
},
|
|
111
|
+
"//4-dependencies": "Manifest, licence, and vulnerability checks.",
|
|
112
|
+
"dependency": {
|
|
113
|
+
"enabled": true,
|
|
114
|
+
"//ignore": "Dependency names, or globs over the whole name (\"eslint-plugin-*\"), that knip should ignore. Only applied when non-empty, and never when the repo ships its own knip config — that file stays the source of truth.",
|
|
115
|
+
"ignore": []
|
|
116
|
+
},
|
|
117
|
+
"circularDeps": {
|
|
118
|
+
"//": "Circular imports (dpdm, bundled — nothing needed on the runner). Uses the project's own dpdm when it has one. When the analyzer cannot run, the check SKIPS rather than passing or failing.",
|
|
119
|
+
"enabled": true,
|
|
120
|
+
"//severity": "Advisory by default: most repos carry long-standing cycles through barrel files. Set 'error' to gate merges on them.",
|
|
121
|
+
"severity": "warn",
|
|
122
|
+
"//ignore": "Globs over repo-relative paths to keep out of the analysis (generated or vendored code).",
|
|
123
|
+
"ignore": [],
|
|
124
|
+
"//timeoutMs": "Cap on the analysis. On timeout the check skips rather than fails.",
|
|
125
|
+
"timeoutMs": 120000
|
|
126
|
+
},
|
|
127
|
+
"outdatedDeps": {
|
|
128
|
+
"enabled": true,
|
|
129
|
+
"ignore": [],
|
|
130
|
+
"//timeoutMs": "Cap on 'npm outdated'. On timeout the check skips rather than fails.",
|
|
131
|
+
"timeoutMs": 30000
|
|
132
|
+
},
|
|
133
|
+
"licenseCheck": {
|
|
134
|
+
"//": "GPL/LGPL/AGPL in PRODUCTION dependencies fail the run. Both lists below are APPENDED to the defaults.",
|
|
135
|
+
"allowPackages": [],
|
|
136
|
+
"allowLicenses": []
|
|
137
|
+
},
|
|
138
|
+
"vulnScan": {
|
|
139
|
+
"//": "osv-scanner, cross-ecosystem. OPT-IN: must be exactly true. Requires osv-scanner on the runner.",
|
|
140
|
+
"enabled": false
|
|
141
|
+
},
|
|
142
|
+
"grypeScan": {
|
|
143
|
+
"//": "Anchore grype, cross-ecosystem. ON by default but skips when grype is absent from the runner.",
|
|
144
|
+
"enabled": true,
|
|
145
|
+
"minSeverity": "medium",
|
|
146
|
+
"//ignore": "Suppress by CVE/GHSA id or by package name.",
|
|
147
|
+
"ignore": [],
|
|
148
|
+
"//timeoutMs": "Cap on the grype scan. On timeout the check skips rather than fails. The scan never walks 'ignoreDirs' (node_modules, dist, …), which is what keeps it quick.",
|
|
149
|
+
"timeoutMs": 120000,
|
|
150
|
+
"//ci": "Optional per-environment overrides (enabled, minSeverity, ignore, timeoutMs): 'ci' applies on CI builds, 'local' elsewhere. Example: \"local\": { \"enabled\": false }"
|
|
151
|
+
},
|
|
152
|
+
"//bannedImports": "Packages that must not be ADDED. Empty means the check is inert. severity defaults to 'warn'; use 'error' to fail the run.",
|
|
153
|
+
"bannedImports": [],
|
|
154
|
+
"//5-git-and-pr": "Checks on the diff and on pull-request metadata.",
|
|
155
|
+
"mergeConflict": {
|
|
156
|
+
"enabled": true,
|
|
157
|
+
"severity": "error"
|
|
158
|
+
},
|
|
159
|
+
"//packageSize": "Growth of the published npm package vs the last release. Advisory — a bigger tarball is usually earned. Only runs where package.json names a non-private package.",
|
|
160
|
+
"packageSize": {
|
|
161
|
+
"enabled": true,
|
|
162
|
+
"maxGrowthPercent": 20,
|
|
163
|
+
"compareWith": "latest"
|
|
164
|
+
},
|
|
165
|
+
"diffSmell": {
|
|
166
|
+
"enabled": true
|
|
167
|
+
},
|
|
168
|
+
"leftoverDebug": {
|
|
169
|
+
"enabled": true,
|
|
170
|
+
"severity": "warn"
|
|
171
|
+
},
|
|
172
|
+
"todoFixme": {
|
|
173
|
+
"enabled": true,
|
|
174
|
+
"severity": "warn",
|
|
175
|
+
"//requireTicket": "When true, a TODO must reference a ticket id — '#123' or 'PROJ-456'.",
|
|
176
|
+
"requireTicket": false,
|
|
177
|
+
"keywords": ["TODO", "FIXME", "XXX", "HACK"]
|
|
178
|
+
},
|
|
179
|
+
"lockfileDrift": {
|
|
180
|
+
"enabled": true,
|
|
181
|
+
"severity": "warn"
|
|
182
|
+
},
|
|
183
|
+
"largeFiles": {
|
|
184
|
+
"enabled": true,
|
|
185
|
+
"severity": "warn",
|
|
186
|
+
"maxSizeKb": 500,
|
|
187
|
+
"//allow": "Globs exempted from the size limit. APPENDED to a built-in lockfile allow-list.",
|
|
188
|
+
"allow": []
|
|
189
|
+
},
|
|
190
|
+
"missingTests": {
|
|
191
|
+
"enabled": true,
|
|
192
|
+
"severity": "warn",
|
|
193
|
+
"//ignore": "Globs that never require an accompanying test. Setting this REPLACES the defaults, which cover *.d.ts, index files and *.config.*.",
|
|
194
|
+
"ignore": [
|
|
195
|
+
"**/*.d.ts",
|
|
196
|
+
"**/index.ts",
|
|
197
|
+
"**/index.tsx",
|
|
198
|
+
"**/index.js",
|
|
199
|
+
"**/index.jsx",
|
|
200
|
+
"**/*.config.*"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
"caseCollision": {
|
|
204
|
+
"enabled": true
|
|
205
|
+
},
|
|
206
|
+
"//customRules": "Your own regex rules run against added diff lines. Each needs 'name' and 'pattern'; optional 'message', 'severity' (error|warn), 'include', 'exclude', 'flags'.",
|
|
207
|
+
"customRules": [],
|
|
208
|
+
"prBody": {
|
|
209
|
+
"enabled": true,
|
|
210
|
+
"minLength": 20,
|
|
211
|
+
"requireTicket": true
|
|
212
|
+
},
|
|
213
|
+
"prSize": {
|
|
214
|
+
"enabled": true,
|
|
215
|
+
"maxFiles": 50,
|
|
216
|
+
"maxLines": 1000
|
|
217
|
+
},
|
|
218
|
+
"commitlint": {
|
|
219
|
+
"enabled": true,
|
|
220
|
+
"types": [
|
|
221
|
+
"feat",
|
|
222
|
+
"fix",
|
|
223
|
+
"docs",
|
|
224
|
+
"chore",
|
|
225
|
+
"ci",
|
|
226
|
+
"refactor",
|
|
227
|
+
"perf",
|
|
228
|
+
"style",
|
|
229
|
+
"revert",
|
|
230
|
+
"test",
|
|
231
|
+
"build"
|
|
232
|
+
],
|
|
233
|
+
"//ignores": "Regex sources for titles to skip, e.g. release PRs.",
|
|
234
|
+
"ignores": ["^Release\\b", "^chore\\(release\\):"]
|
|
235
|
+
},
|
|
236
|
+
"//6-quality": "Cross-language quality gates.",
|
|
237
|
+
"yamlLint": {
|
|
238
|
+
"enabled": true,
|
|
239
|
+
"severity": "error",
|
|
240
|
+
"ignore": []
|
|
241
|
+
},
|
|
242
|
+
"symlinks": {
|
|
243
|
+
"//": "Whole-repo scan for tracked symlinks whose target does not exist.",
|
|
244
|
+
"enabled": true,
|
|
245
|
+
"//severity": "Advisory by default. Set 'error' to gate merges on a broken link.",
|
|
246
|
+
"severity": "warn",
|
|
247
|
+
"//ignore": "Globs for links intentionally left broken (e.g. a fixture testing another tool's own broken-symlink handling).",
|
|
248
|
+
"ignore": []
|
|
249
|
+
},
|
|
250
|
+
"typecheck": {
|
|
251
|
+
"enabled": true
|
|
252
|
+
},
|
|
253
|
+
"duplicate": {
|
|
254
|
+
"enabled": true,
|
|
255
|
+
"minLines": 5,
|
|
256
|
+
"minTokens": 50,
|
|
257
|
+
"//ignore": "Test and mock paths are excluded by default because test setup legitimately repeats.",
|
|
258
|
+
"ignore": [
|
|
259
|
+
"**/__tests__/**",
|
|
260
|
+
"**/__mocks__/**",
|
|
261
|
+
"**/*.test.*",
|
|
262
|
+
"**/*.spec.*",
|
|
263
|
+
"**/test/**",
|
|
264
|
+
"**/tests/**"
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
"deadCode": {
|
|
268
|
+
"enabled": true,
|
|
269
|
+
"//ignoreFiles": "REGEX sources (not globs), matched against reported file paths. Setting this REPLACES the defaults.",
|
|
270
|
+
"ignoreFiles": [
|
|
271
|
+
"/__tests__/",
|
|
272
|
+
"/__mocks__/",
|
|
273
|
+
"/__mock__/",
|
|
274
|
+
"/tests?/",
|
|
275
|
+
"\\.test\\.",
|
|
276
|
+
"\\.spec\\."
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
"coverage": {
|
|
280
|
+
"//": "OPT-IN: must be exactly true. Reads an existing coverage summary; it does not run your tests.",
|
|
281
|
+
"enabled": false,
|
|
282
|
+
"severity": "warn",
|
|
283
|
+
"//reportPath": "Path or array of paths to a coverage summary.",
|
|
284
|
+
"reportPath": []
|
|
285
|
+
},
|
|
286
|
+
"licenseHeader": {
|
|
287
|
+
"//": "OPT-IN: must be exactly true. Requires a header matching 'pattern' within the first 'lines' lines of each changed source file.",
|
|
288
|
+
"enabled": false,
|
|
289
|
+
"pattern": "",
|
|
290
|
+
"lines": 10
|
|
291
|
+
},
|
|
292
|
+
"configValidation": {
|
|
293
|
+
"enabled": true
|
|
294
|
+
},
|
|
295
|
+
"//7-linters": "ESLint, Prettier, cspell and markdownlint. 'rules' blocks are MERGED with the defaults; 'ignorePatterns' and 'ignorePaths' are APPENDED.",
|
|
296
|
+
"eslint": {
|
|
297
|
+
"rules": {},
|
|
298
|
+
"ignorePatterns": []
|
|
299
|
+
},
|
|
300
|
+
"prettier": {
|
|
301
|
+
"rules": {}
|
|
302
|
+
},
|
|
303
|
+
"cspell": {
|
|
304
|
+
"//": "Only \"enabled\" always applies. The rest configures the cspell config pr-checkmate generates, so it is ignored when the repository has its own cspell.json — that file wins.",
|
|
305
|
+
"//enabled": "Set false to turn the Spellcheck check off entirely.",
|
|
306
|
+
"enabled": true,
|
|
307
|
+
"//words": "Project vocabulary that should not be reported as misspelled. Appended to the bundled list.",
|
|
308
|
+
"words": [],
|
|
309
|
+
"//ignorePaths": "Globs to skip, APPENDED to the bundled list — which already covers CHANGELOG.md (assembled from commit subjects, so its typos are unfixable), test and mock paths, lockfiles and minified bundles. Anchored to the repository root, so a pattern never matches a directory ABOVE the checkout.",
|
|
310
|
+
"ignorePaths": [],
|
|
311
|
+
"ignoreRegExpList": [],
|
|
312
|
+
"//dictionaries": "Extra cspell dictionaries to enable, on top of the bundled fr, ru, uk, he, es. Unknown names are ignored.",
|
|
313
|
+
"dictionaries": [],
|
|
314
|
+
"//language": "Locales to spellcheck against. Omit it to keep the bundled \"en,ru,uk,he,fr,es\" — a value here REPLACES that list, so \"en\" alone reports every non-English word as a typo."
|
|
315
|
+
},
|
|
316
|
+
"markdownlint": {
|
|
317
|
+
"rules": {},
|
|
318
|
+
"//ignores": "APPENDED to the built-in list: node_modules, dist, coverage, graphify-out, .claude and CHANGELOG.md.",
|
|
319
|
+
"ignores": []
|
|
320
|
+
},
|
|
321
|
+
"//7b-install": "WHICH TOOLING IS FETCHED. The package ships ~233 MB and no repository needs all of it. \"adaptive\" (default) fetches only what this repository turns out to need; \"eager\" fetches everything up front, which is what a closed network or a prebuilt image wants and is also the exact previous behaviour; \"manual\" fetches nothing because the tools are already on the runner. A missing tool never fails silently: the affected checks skip with a reason in the report, or fail the run outright with onMissingTool: \"error\".",
|
|
322
|
+
"install": {
|
|
323
|
+
"strategy": "adaptive",
|
|
324
|
+
"//profiles": "Extra profiles beyond what detection concluded, for generated code or a monorepo layout detection cannot see through. Names: core, js, python, cpp, spellcheck, markdown, commitlint, duplicate.",
|
|
325
|
+
"profiles": [],
|
|
326
|
+
"//excludeProfiles": "Never install these, even when the language is detected. Wins over 'profiles'.",
|
|
327
|
+
"excludeProfiles": [],
|
|
328
|
+
"//minFilesPerLanguage": "Source files a language needs before its toolchain is worth downloading. Separate from detect.minFiles: running a check that then skips is free, downloading a toolchain is not.",
|
|
329
|
+
"minFilesPerLanguage": 1,
|
|
330
|
+
"//reuseLocal": "compatible | always | off. Run the tool the REPOSITORY already has instead of our copy. \"compatible\" (default) does so when the major matches ours, or when the tool reads the repository's own config — a legacy .eslintrc can only be read by the ESLint it was written for, and a tsconfig.json by its own compiler. \"always\" reuses across a major gap at your own risk: our generated flat config does not load in ESLint 8. \"off\" always uses our pinned copy, for reproducibility.",
|
|
331
|
+
"reuseLocal": "compatible",
|
|
332
|
+
"//onMissingTool": "auto | skip | error. In a closed contour a silent skip is not acceptable — use 'error'.",
|
|
333
|
+
"onMissingTool": "auto",
|
|
334
|
+
"//offline": "Forbid every network install at run time. Pre-warm with: npx pr-checkmate install --all",
|
|
335
|
+
"offline": false,
|
|
336
|
+
"//cacheDir": "Where fetched tooling is kept; the path includes the pr-checkmate version. Cache it in CI or the tooling is fetched on every run.",
|
|
337
|
+
"cacheDir": "~/.cache/pr-checkmate",
|
|
338
|
+
"//deny": "Packages never fetched, whatever profile asks for them.",
|
|
339
|
+
"deny": [],
|
|
340
|
+
"//prewarm": "NOT YET IMPLEMENTED — accepted and ignored. Warming the cache needs a postinstall hook, and there is nothing to warm while every profile's tooling ships inside the package. Documented as inert rather than quietly doing nothing.",
|
|
341
|
+
"prewarm": true
|
|
342
|
+
},
|
|
343
|
+
"//8-languages": "Language is auto-detected. A check skips when its language is absent, and runner-dependency tools skip when the binary is missing — so leaving everything enabled is safe. TypeScript and JavaScript have no block of their own: configure them through 'eslint', 'prettier' and 'typecheck' above.",
|
|
344
|
+
"//detect": "HOW that auto-detection reads the tree, when 'languages' is not set explicitly. Generated reports, vendored code and marker files are already excluded; these knobs are for the cases the built-in rules get wrong in your repo. 'minFiles' is how many source files a language needs to count (a marker file such as pyproject.toml includes it regardless). 'excludePaths' ADDS to the built-in exclusions rather than replacing them. 'disable' drops a language outright.",
|
|
345
|
+
"detect": {
|
|
346
|
+
"minFiles": 1,
|
|
347
|
+
"excludePaths": [],
|
|
348
|
+
"disable": []
|
|
349
|
+
},
|
|
350
|
+
"python": {
|
|
351
|
+
"enabled": true,
|
|
352
|
+
"//typeChecker": "mypy | pyright — pins one checker. Leave unset: the runner's own mypy is used when it has one, our bundled pyright otherwise.",
|
|
353
|
+
"typecheck": true,
|
|
354
|
+
"ruff": {
|
|
355
|
+
"lint": true,
|
|
356
|
+
"format": true
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"cpp": {
|
|
360
|
+
"enabled": true,
|
|
361
|
+
"clangFormat": {
|
|
362
|
+
"style": "LLVM"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"swift": {
|
|
366
|
+
"enabled": true
|
|
367
|
+
},
|
|
368
|
+
"kotlin": {
|
|
369
|
+
"enabled": true
|
|
370
|
+
},
|
|
371
|
+
"go": {
|
|
372
|
+
"enabled": true
|
|
373
|
+
},
|
|
374
|
+
"rust": {
|
|
375
|
+
"enabled": true
|
|
376
|
+
},
|
|
377
|
+
"csharp": {
|
|
378
|
+
"enabled": true
|
|
379
|
+
},
|
|
380
|
+
"ruby": {
|
|
381
|
+
"enabled": true
|
|
382
|
+
},
|
|
383
|
+
"php": {
|
|
384
|
+
"enabled": true
|
|
385
|
+
},
|
|
386
|
+
"shellcheck": {
|
|
387
|
+
"//": "Needs the `shellcheck` binary on the runner; skips when absent.",
|
|
388
|
+
"enabled": true,
|
|
389
|
+
"//minSeverity": "error | warning | info | style. Omit to keep ShellCheck's own default (every level).",
|
|
390
|
+
"//ignore": "ShellCheck codes to suppress, e.g. \"SC2086\".",
|
|
391
|
+
"ignore": []
|
|
392
|
+
}
|
|
393
|
+
}
|
package/dist/cjs/init.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ export declare function setupWorkflow(root: string, mode: GateMode): void;
|
|
|
30
30
|
* heart about what should block.
|
|
31
31
|
*/
|
|
32
32
|
export declare const BLOCKING_BY_DEFAULT: readonly ["Security Scan", "Sensitive Files", "Diff Security", "Workflow Security", "Merge Conflict", "NPM Audit", "License Check", "Dependencies", "TypeScript", "ESLint", "YAML Lint"];
|
|
33
|
+
/**
|
|
34
|
+
* Every option the template documents that the file does not already carry, at
|
|
35
|
+
* its default. Without this, options such as `vulnScan` (off by default) or
|
|
36
|
+
* `licenseCheck` exist only in the docs, and nobody edits what they cannot see.
|
|
37
|
+
* Comment keys travel with the option they describe, section headers with the
|
|
38
|
+
* first option after them.
|
|
39
|
+
*/
|
|
40
|
+
export declare function templateExtras(existing: Record<string, unknown>): Record<string, unknown>;
|
|
33
41
|
export declare function buildInitialConfig(sourcePath: string, languages: string[]): Record<string, unknown>;
|
|
34
42
|
/**
|
|
35
43
|
* Initialize (or refresh) pr-checkmate configuration in the current project.
|
package/dist/cjs/init.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.BLOCKING_BY_DEFAULT = void 0;
|
|
7
7
|
exports.setupWorkflow = setupWorkflow;
|
|
8
|
+
exports.templateExtras = templateExtras;
|
|
8
9
|
exports.buildInitialConfig = buildInitialConfig;
|
|
9
10
|
exports.init = init;
|
|
10
11
|
const fs_1 = __importDefault(require("fs"));
|
|
@@ -270,8 +271,46 @@ const HOW_TO = [
|
|
|
270
271
|
`Every option, annotated, with its default: ${index_js_1.FULL_CONFIG_URL}`,
|
|
271
272
|
`Docs: ${index_js_1.DOCS_URL}`,
|
|
272
273
|
].join(' ');
|
|
274
|
+
// Written out at its defaults so the options are visible and editable in the file
|
|
275
|
+
// instead of having to be looked up. Same trade as `max-len`: the values stop
|
|
276
|
+
// tracking the package, which is the price of being able to see them.
|
|
277
|
+
const GRYPE_SCAN_SEED = {
|
|
278
|
+
'//': 'Anchore grype, cross-ecosystem. ON by default but skips when grype is absent from the runner. Only direct dependencies are reported.',
|
|
279
|
+
enabled: true,
|
|
280
|
+
minSeverity: 'medium',
|
|
281
|
+
'//ignore': 'Suppress by CVE/GHSA id or by package name.',
|
|
282
|
+
ignore: [],
|
|
283
|
+
'//timeoutMs': 'Cap on the scan. On timeout the check skips rather than fails.',
|
|
284
|
+
timeoutMs: 120000,
|
|
285
|
+
'//ci': 'Per-environment overrides (enabled, minSeverity, ignore, timeoutMs): "ci" applies on CI builds, "local" elsewhere. Example: "local": { "enabled": false }',
|
|
286
|
+
ci: {},
|
|
287
|
+
local: {},
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Every option the template documents that the file does not already carry, at
|
|
291
|
+
* its default. Without this, options such as `vulnScan` (off by default) or
|
|
292
|
+
* `licenseCheck` exist only in the docs, and nobody edits what they cannot see.
|
|
293
|
+
* Comment keys travel with the option they describe, section headers with the
|
|
294
|
+
* first option after them.
|
|
295
|
+
*/
|
|
296
|
+
function templateExtras(existing) {
|
|
297
|
+
const templatePath = path_1.default.join(__dirname, 'config', 'pr-checkmate.template.json');
|
|
298
|
+
if (!fs_1.default.existsSync(templatePath)) {
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
const template = JSON.parse(fs_1.default.readFileSync(templatePath, 'utf-8'));
|
|
302
|
+
const extras = {};
|
|
303
|
+
for (const [key, value] of Object.entries(template)) {
|
|
304
|
+
const option = key.startsWith('//') ? key.slice(2) : key;
|
|
305
|
+
if (key in existing || option in existing) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
extras[key] = value;
|
|
309
|
+
}
|
|
310
|
+
return extras;
|
|
311
|
+
}
|
|
273
312
|
function buildInitialConfig(sourcePath, languages) {
|
|
274
|
-
|
|
313
|
+
const base = {
|
|
275
314
|
$schema: SCHEMA_PATH,
|
|
276
315
|
'// how-to': HOW_TO,
|
|
277
316
|
commands: index_js_1.DEFAULT_COMMANDS,
|
|
@@ -352,9 +391,13 @@ function buildInitialConfig(sourcePath, languages) {
|
|
|
352
391
|
dataflowWindow: findings_js_1.DEFAULT_DATAFLOW_WINDOW,
|
|
353
392
|
ignorePaths: [...index_js_1.DIFF_SECURITY_IGNORE_DEFAULTS],
|
|
354
393
|
},
|
|
394
|
+
grypeScan: structuredClone(GRYPE_SCAN_SEED),
|
|
355
395
|
documentation: index_js_1.documentation,
|
|
356
396
|
languages,
|
|
357
397
|
};
|
|
398
|
+
const extras = templateExtras(base);
|
|
399
|
+
const { documentation: docs, languages: langs, ...rest } = base;
|
|
400
|
+
return { ...rest, ...extras, documentation: docs, languages: langs };
|
|
358
401
|
}
|
|
359
402
|
/** First-run setup: prompt, write config, and scaffold workflow + tsconfig. */
|
|
360
403
|
async function createConfig(root) {
|
|
@@ -403,6 +446,10 @@ async function updateConfig(root) {
|
|
|
403
446
|
$schema: json.$schema ?? SCHEMA_PATH,
|
|
404
447
|
'// how-to': json['// how-to'] ?? HOW_TO,
|
|
405
448
|
...json,
|
|
449
|
+
// An existing file predates this option, so nobody has seen it. Added only
|
|
450
|
+
// when missing; a client's own block is never touched.
|
|
451
|
+
grypeScan: json.grypeScan ?? structuredClone(GRYPE_SCAN_SEED),
|
|
452
|
+
...templateExtras({ ...json, grypeScan: true }),
|
|
406
453
|
languages,
|
|
407
454
|
};
|
|
408
455
|
fs_1.default.writeFileSync(CONFIG_FILE, `${JSON.stringify(updated, null, 2)}\n`);
|
|
@@ -36,6 +36,15 @@ const configFiles = [
|
|
|
36
36
|
source: 'src/config/pr-checkmate-workflow-docker.yml',
|
|
37
37
|
dest: 'dist/esm/config/pr-checkmate-workflow-docker.yml',
|
|
38
38
|
},
|
|
39
|
+
// Read by `init` to seed every option into a new pr-checkmate.json.
|
|
40
|
+
{
|
|
41
|
+
source: 'src/config/pr-checkmate.template.json',
|
|
42
|
+
dest: 'dist/cjs/config/pr-checkmate.template.json',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
source: 'src/config/pr-checkmate.template.json',
|
|
46
|
+
dest: 'dist/esm/config/pr-checkmate.template.json',
|
|
47
|
+
},
|
|
39
48
|
{ source: 'src/config/pr-checkmate.schema.json', dest: 'pr-checkmate.schema.json' },
|
|
40
49
|
];
|
|
41
50
|
/**
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/Mybono/pr_checkmate_public/main/pr-checkmate.schema.json",
|
|
3
|
+
"//": "PR CheckMate configuration template. Place this file at your repository root as 'pr-checkmate.json'. Every value below is the built-in DEFAULT — delete any block you do not want to change, because the file is deep-merged with the defaults. Keys starting with '//' are comments and are ignored. Full per-check reference: https://github.com/Mybono/pr_checkmate_public",
|
|
4
|
+
"//excludePaths": "FILES AND FOLDERS NO CHECK EVER LOOKS AT, as globs: \"src/generated/**\" for a whole folder, \"vendor/legacy.ts\" for one file. Applied where every check gets its file list, so the rule is written once rather than per check. Use this before reaching for a per-check ignore; use 'ignoreDirs' only when you mean a directory NAME wherever it appears.",
|
|
5
|
+
"excludePaths": [],
|
|
6
|
+
"//1-scope": "WHERE CHECKS LOOK. 'sourcePath' may be a string or an array. 'ignoreDirs' REPLACES the default ignore list rather than extending it, so copy the defaults you still want — the defaults cover build output, dependency and report directories, plus generated 'graphify-out'. Test directories are deliberately NOT in it: test code is still linted, type-checked and formatted, and is excluded per-check where it is noise (see 'duplicate', 'deadCode', 'diffSecurity' and the bundled cspell ignores).",
|
|
7
|
+
"sourcePath": ".",
|
|
8
|
+
"//2-severity": "UNIVERSAL ON/OFF SWITCH, keyed by a check's DISPLAY NAME (see //check-names below). 'off' removes the check before it runs; 'error' promotes a warning to a failure; 'warn' demotes a failure to a warning. This works for every check, including those with no 'enabled' flag of their own.",
|
|
9
|
+
"severity": {},
|
|
10
|
+
"//check-names": [
|
|
11
|
+
"Banned Imports",
|
|
12
|
+
"Circular Deps",
|
|
13
|
+
"Dependencies",
|
|
14
|
+
"Grype Scan",
|
|
15
|
+
"License Check",
|
|
16
|
+
"NPM Audit",
|
|
17
|
+
"Outdated Deps",
|
|
18
|
+
"Vuln Scan",
|
|
19
|
+
"Custom Rules",
|
|
20
|
+
"Diff Smells",
|
|
21
|
+
"Large Files",
|
|
22
|
+
"Leftover Debug",
|
|
23
|
+
"Lockfile Drift",
|
|
24
|
+
"Merge Conflict",
|
|
25
|
+
"Missing Tests",
|
|
26
|
+
"TODO/FIXME",
|
|
27
|
+
"ESLint",
|
|
28
|
+
"TypeScript",
|
|
29
|
+
"Prettier",
|
|
30
|
+
"Ruff Lint",
|
|
31
|
+
"Ruff Format",
|
|
32
|
+
"Python Types",
|
|
33
|
+
"C++ Format",
|
|
34
|
+
"SwiftLint",
|
|
35
|
+
"ktlint",
|
|
36
|
+
"Go Vet",
|
|
37
|
+
"Go Format",
|
|
38
|
+
"Clippy",
|
|
39
|
+
"Rustfmt",
|
|
40
|
+
"C# Format",
|
|
41
|
+
"RuboCop",
|
|
42
|
+
"PHP CS Fixer",
|
|
43
|
+
"Commitlint",
|
|
44
|
+
"PR Body",
|
|
45
|
+
"PR Size",
|
|
46
|
+
"PR Title",
|
|
47
|
+
"Case Collision",
|
|
48
|
+
"Config Validation",
|
|
49
|
+
"Coverage",
|
|
50
|
+
"Dead Code",
|
|
51
|
+
"Duplicate Code",
|
|
52
|
+
"License Header",
|
|
53
|
+
"Markdown",
|
|
54
|
+
"Spellcheck",
|
|
55
|
+
"YAML Lint",
|
|
56
|
+
"Broken Symlinks",
|
|
57
|
+
"ShellCheck",
|
|
58
|
+
"Security Scan",
|
|
59
|
+
"Diff Security",
|
|
60
|
+
"Dockerfile Security",
|
|
61
|
+
"Migration Safety",
|
|
62
|
+
"Sensitive Files",
|
|
63
|
+
"Workflow Security"
|
|
64
|
+
],
|
|
65
|
+
"//3-security": "Secret scanning and dependency vulnerabilities.",
|
|
66
|
+
"security": {
|
|
67
|
+
"gitleaks": {
|
|
68
|
+
"enabled": true
|
|
69
|
+
},
|
|
70
|
+
"npm-audit": {
|
|
71
|
+
"enabled": true,
|
|
72
|
+
"//auditLevel": "info | low | moderate | high | critical. Only DIRECT dependencies at or above this level block. Default 'high': a moderate CVE often has no fix available, and blocking on it stops releases indefinitely for a risk most teams have already accepted. Set 'moderate' for a stricter line.",
|
|
73
|
+
"auditLevel": "high",
|
|
74
|
+
"//ignore": "Package names that never block, but are still reported as warnings.",
|
|
75
|
+
"ignore": []
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"//diffSecurity": "'ignorePaths' skips whole files by glob; setting it REPLACES the test-path defaults shown here, which exist because a security test's job is to contain the exact constructs this check hunts for. 'ignore' silences a finding LABEL everywhere instead. 'dataflowWindow' is how many added lines a value stays tainted for, so `const q = `...${x}`` on one line and `db.query(q)` on the next are still connected — a heuristic with no scopes and no reassignment tracking, so it only ever advises; 0 switches it off.",
|
|
79
|
+
"diffSecurity": {
|
|
80
|
+
"enabled": true,
|
|
81
|
+
"ignore": [],
|
|
82
|
+
"dataflowWindow": 10,
|
|
83
|
+
"ignorePaths": [
|
|
84
|
+
"**/__tests__/**",
|
|
85
|
+
"**/__mocks__/**",
|
|
86
|
+
"**/*.test.*",
|
|
87
|
+
"**/*.spec.*",
|
|
88
|
+
"**/test/**",
|
|
89
|
+
"**/tests/**"
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"workflowSecurity": {
|
|
93
|
+
"enabled": true,
|
|
94
|
+
"ignore": []
|
|
95
|
+
},
|
|
96
|
+
"dockerfileSecurity": {
|
|
97
|
+
"enabled": true,
|
|
98
|
+
"ignore": []
|
|
99
|
+
},
|
|
100
|
+
"//sensitiveFileGuard": "Flags .env files, private keys, CI config and lockfiles. 'ignorePaths' excuses ONE file by glob (a .pem test fixture); 'ignore' silences a whole CATEGORY and would excuse the next real key too — reach for ignorePaths first.",
|
|
101
|
+
"sensitiveFileGuard": {
|
|
102
|
+
"enabled": true,
|
|
103
|
+
"ignorePaths": []
|
|
104
|
+
},
|
|
105
|
+
"migrationSafety": {
|
|
106
|
+
"enabled": true,
|
|
107
|
+
"severity": "warn",
|
|
108
|
+
"//paths": "Globs treated as migrations. Setting this REPLACES the defaults listed here.",
|
|
109
|
+
"paths": ["**/migrations/**", "**/migrate/**", "**/db/migrate/**", "**/versions/**", "**/*.sql"]
|
|
110
|
+
},
|
|
111
|
+
"//4-dependencies": "Manifest, licence, and vulnerability checks.",
|
|
112
|
+
"dependency": {
|
|
113
|
+
"enabled": true,
|
|
114
|
+
"//ignore": "Dependency names, or globs over the whole name (\"eslint-plugin-*\"), that knip should ignore. Only applied when non-empty, and never when the repo ships its own knip config — that file stays the source of truth.",
|
|
115
|
+
"ignore": []
|
|
116
|
+
},
|
|
117
|
+
"circularDeps": {
|
|
118
|
+
"//": "Circular imports (dpdm, bundled — nothing needed on the runner). Uses the project's own dpdm when it has one. When the analyzer cannot run, the check SKIPS rather than passing or failing.",
|
|
119
|
+
"enabled": true,
|
|
120
|
+
"//severity": "Advisory by default: most repos carry long-standing cycles through barrel files. Set 'error' to gate merges on them.",
|
|
121
|
+
"severity": "warn",
|
|
122
|
+
"//ignore": "Globs over repo-relative paths to keep out of the analysis (generated or vendored code).",
|
|
123
|
+
"ignore": [],
|
|
124
|
+
"//timeoutMs": "Cap on the analysis. On timeout the check skips rather than fails.",
|
|
125
|
+
"timeoutMs": 120000
|
|
126
|
+
},
|
|
127
|
+
"outdatedDeps": {
|
|
128
|
+
"enabled": true,
|
|
129
|
+
"ignore": [],
|
|
130
|
+
"//timeoutMs": "Cap on 'npm outdated'. On timeout the check skips rather than fails.",
|
|
131
|
+
"timeoutMs": 30000
|
|
132
|
+
},
|
|
133
|
+
"licenseCheck": {
|
|
134
|
+
"//": "GPL/LGPL/AGPL in PRODUCTION dependencies fail the run. Both lists below are APPENDED to the defaults.",
|
|
135
|
+
"allowPackages": [],
|
|
136
|
+
"allowLicenses": []
|
|
137
|
+
},
|
|
138
|
+
"vulnScan": {
|
|
139
|
+
"//": "osv-scanner, cross-ecosystem. OPT-IN: must be exactly true. Requires osv-scanner on the runner.",
|
|
140
|
+
"enabled": false
|
|
141
|
+
},
|
|
142
|
+
"grypeScan": {
|
|
143
|
+
"//": "Anchore grype, cross-ecosystem. ON by default but skips when grype is absent from the runner.",
|
|
144
|
+
"enabled": true,
|
|
145
|
+
"minSeverity": "medium",
|
|
146
|
+
"//ignore": "Suppress by CVE/GHSA id or by package name.",
|
|
147
|
+
"ignore": [],
|
|
148
|
+
"//timeoutMs": "Cap on the grype scan. On timeout the check skips rather than fails. The scan never walks 'ignoreDirs' (node_modules, dist, …), which is what keeps it quick.",
|
|
149
|
+
"timeoutMs": 120000,
|
|
150
|
+
"//ci": "Optional per-environment overrides (enabled, minSeverity, ignore, timeoutMs): 'ci' applies on CI builds, 'local' elsewhere. Example: \"local\": { \"enabled\": false }"
|
|
151
|
+
},
|
|
152
|
+
"//bannedImports": "Packages that must not be ADDED. Empty means the check is inert. severity defaults to 'warn'; use 'error' to fail the run.",
|
|
153
|
+
"bannedImports": [],
|
|
154
|
+
"//5-git-and-pr": "Checks on the diff and on pull-request metadata.",
|
|
155
|
+
"mergeConflict": {
|
|
156
|
+
"enabled": true,
|
|
157
|
+
"severity": "error"
|
|
158
|
+
},
|
|
159
|
+
"//packageSize": "Growth of the published npm package vs the last release. Advisory — a bigger tarball is usually earned. Only runs where package.json names a non-private package.",
|
|
160
|
+
"packageSize": {
|
|
161
|
+
"enabled": true,
|
|
162
|
+
"maxGrowthPercent": 20,
|
|
163
|
+
"compareWith": "latest"
|
|
164
|
+
},
|
|
165
|
+
"diffSmell": {
|
|
166
|
+
"enabled": true
|
|
167
|
+
},
|
|
168
|
+
"leftoverDebug": {
|
|
169
|
+
"enabled": true,
|
|
170
|
+
"severity": "warn"
|
|
171
|
+
},
|
|
172
|
+
"todoFixme": {
|
|
173
|
+
"enabled": true,
|
|
174
|
+
"severity": "warn",
|
|
175
|
+
"//requireTicket": "When true, a TODO must reference a ticket id — '#123' or 'PROJ-456'.",
|
|
176
|
+
"requireTicket": false,
|
|
177
|
+
"keywords": ["TODO", "FIXME", "XXX", "HACK"]
|
|
178
|
+
},
|
|
179
|
+
"lockfileDrift": {
|
|
180
|
+
"enabled": true,
|
|
181
|
+
"severity": "warn"
|
|
182
|
+
},
|
|
183
|
+
"largeFiles": {
|
|
184
|
+
"enabled": true,
|
|
185
|
+
"severity": "warn",
|
|
186
|
+
"maxSizeKb": 500,
|
|
187
|
+
"//allow": "Globs exempted from the size limit. APPENDED to a built-in lockfile allow-list.",
|
|
188
|
+
"allow": []
|
|
189
|
+
},
|
|
190
|
+
"missingTests": {
|
|
191
|
+
"enabled": true,
|
|
192
|
+
"severity": "warn",
|
|
193
|
+
"//ignore": "Globs that never require an accompanying test. Setting this REPLACES the defaults, which cover *.d.ts, index files and *.config.*.",
|
|
194
|
+
"ignore": [
|
|
195
|
+
"**/*.d.ts",
|
|
196
|
+
"**/index.ts",
|
|
197
|
+
"**/index.tsx",
|
|
198
|
+
"**/index.js",
|
|
199
|
+
"**/index.jsx",
|
|
200
|
+
"**/*.config.*"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
"caseCollision": {
|
|
204
|
+
"enabled": true
|
|
205
|
+
},
|
|
206
|
+
"//customRules": "Your own regex rules run against added diff lines. Each needs 'name' and 'pattern'; optional 'message', 'severity' (error|warn), 'include', 'exclude', 'flags'.",
|
|
207
|
+
"customRules": [],
|
|
208
|
+
"prBody": {
|
|
209
|
+
"enabled": true,
|
|
210
|
+
"minLength": 20,
|
|
211
|
+
"requireTicket": true
|
|
212
|
+
},
|
|
213
|
+
"prSize": {
|
|
214
|
+
"enabled": true,
|
|
215
|
+
"maxFiles": 50,
|
|
216
|
+
"maxLines": 1000
|
|
217
|
+
},
|
|
218
|
+
"commitlint": {
|
|
219
|
+
"enabled": true,
|
|
220
|
+
"types": [
|
|
221
|
+
"feat",
|
|
222
|
+
"fix",
|
|
223
|
+
"docs",
|
|
224
|
+
"chore",
|
|
225
|
+
"ci",
|
|
226
|
+
"refactor",
|
|
227
|
+
"perf",
|
|
228
|
+
"style",
|
|
229
|
+
"revert",
|
|
230
|
+
"test",
|
|
231
|
+
"build"
|
|
232
|
+
],
|
|
233
|
+
"//ignores": "Regex sources for titles to skip, e.g. release PRs.",
|
|
234
|
+
"ignores": ["^Release\\b", "^chore\\(release\\):"]
|
|
235
|
+
},
|
|
236
|
+
"//6-quality": "Cross-language quality gates.",
|
|
237
|
+
"yamlLint": {
|
|
238
|
+
"enabled": true,
|
|
239
|
+
"severity": "error",
|
|
240
|
+
"ignore": []
|
|
241
|
+
},
|
|
242
|
+
"symlinks": {
|
|
243
|
+
"//": "Whole-repo scan for tracked symlinks whose target does not exist.",
|
|
244
|
+
"enabled": true,
|
|
245
|
+
"//severity": "Advisory by default. Set 'error' to gate merges on a broken link.",
|
|
246
|
+
"severity": "warn",
|
|
247
|
+
"//ignore": "Globs for links intentionally left broken (e.g. a fixture testing another tool's own broken-symlink handling).",
|
|
248
|
+
"ignore": []
|
|
249
|
+
},
|
|
250
|
+
"typecheck": {
|
|
251
|
+
"enabled": true
|
|
252
|
+
},
|
|
253
|
+
"duplicate": {
|
|
254
|
+
"enabled": true,
|
|
255
|
+
"minLines": 5,
|
|
256
|
+
"minTokens": 50,
|
|
257
|
+
"//ignore": "Test and mock paths are excluded by default because test setup legitimately repeats.",
|
|
258
|
+
"ignore": [
|
|
259
|
+
"**/__tests__/**",
|
|
260
|
+
"**/__mocks__/**",
|
|
261
|
+
"**/*.test.*",
|
|
262
|
+
"**/*.spec.*",
|
|
263
|
+
"**/test/**",
|
|
264
|
+
"**/tests/**"
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
"deadCode": {
|
|
268
|
+
"enabled": true,
|
|
269
|
+
"//ignoreFiles": "REGEX sources (not globs), matched against reported file paths. Setting this REPLACES the defaults.",
|
|
270
|
+
"ignoreFiles": [
|
|
271
|
+
"/__tests__/",
|
|
272
|
+
"/__mocks__/",
|
|
273
|
+
"/__mock__/",
|
|
274
|
+
"/tests?/",
|
|
275
|
+
"\\.test\\.",
|
|
276
|
+
"\\.spec\\."
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
"coverage": {
|
|
280
|
+
"//": "OPT-IN: must be exactly true. Reads an existing coverage summary; it does not run your tests.",
|
|
281
|
+
"enabled": false,
|
|
282
|
+
"severity": "warn",
|
|
283
|
+
"//reportPath": "Path or array of paths to a coverage summary.",
|
|
284
|
+
"reportPath": []
|
|
285
|
+
},
|
|
286
|
+
"licenseHeader": {
|
|
287
|
+
"//": "OPT-IN: must be exactly true. Requires a header matching 'pattern' within the first 'lines' lines of each changed source file.",
|
|
288
|
+
"enabled": false,
|
|
289
|
+
"pattern": "",
|
|
290
|
+
"lines": 10
|
|
291
|
+
},
|
|
292
|
+
"configValidation": {
|
|
293
|
+
"enabled": true
|
|
294
|
+
},
|
|
295
|
+
"//7-linters": "ESLint, Prettier, cspell and markdownlint. 'rules' blocks are MERGED with the defaults; 'ignorePatterns' and 'ignorePaths' are APPENDED.",
|
|
296
|
+
"eslint": {
|
|
297
|
+
"rules": {},
|
|
298
|
+
"ignorePatterns": []
|
|
299
|
+
},
|
|
300
|
+
"prettier": {
|
|
301
|
+
"rules": {}
|
|
302
|
+
},
|
|
303
|
+
"cspell": {
|
|
304
|
+
"//": "Only \"enabled\" always applies. The rest configures the cspell config pr-checkmate generates, so it is ignored when the repository has its own cspell.json — that file wins.",
|
|
305
|
+
"//enabled": "Set false to turn the Spellcheck check off entirely.",
|
|
306
|
+
"enabled": true,
|
|
307
|
+
"//words": "Project vocabulary that should not be reported as misspelled. Appended to the bundled list.",
|
|
308
|
+
"words": [],
|
|
309
|
+
"//ignorePaths": "Globs to skip, APPENDED to the bundled list — which already covers CHANGELOG.md (assembled from commit subjects, so its typos are unfixable), test and mock paths, lockfiles and minified bundles. Anchored to the repository root, so a pattern never matches a directory ABOVE the checkout.",
|
|
310
|
+
"ignorePaths": [],
|
|
311
|
+
"ignoreRegExpList": [],
|
|
312
|
+
"//dictionaries": "Extra cspell dictionaries to enable, on top of the bundled fr, ru, uk, he, es. Unknown names are ignored.",
|
|
313
|
+
"dictionaries": [],
|
|
314
|
+
"//language": "Locales to spellcheck against. Omit it to keep the bundled \"en,ru,uk,he,fr,es\" — a value here REPLACES that list, so \"en\" alone reports every non-English word as a typo."
|
|
315
|
+
},
|
|
316
|
+
"markdownlint": {
|
|
317
|
+
"rules": {},
|
|
318
|
+
"//ignores": "APPENDED to the built-in list: node_modules, dist, coverage, graphify-out, .claude and CHANGELOG.md.",
|
|
319
|
+
"ignores": []
|
|
320
|
+
},
|
|
321
|
+
"//7b-install": "WHICH TOOLING IS FETCHED. The package ships ~233 MB and no repository needs all of it. \"adaptive\" (default) fetches only what this repository turns out to need; \"eager\" fetches everything up front, which is what a closed network or a prebuilt image wants and is also the exact previous behaviour; \"manual\" fetches nothing because the tools are already on the runner. A missing tool never fails silently: the affected checks skip with a reason in the report, or fail the run outright with onMissingTool: \"error\".",
|
|
322
|
+
"install": {
|
|
323
|
+
"strategy": "adaptive",
|
|
324
|
+
"//profiles": "Extra profiles beyond what detection concluded, for generated code or a monorepo layout detection cannot see through. Names: core, js, python, cpp, spellcheck, markdown, commitlint, duplicate.",
|
|
325
|
+
"profiles": [],
|
|
326
|
+
"//excludeProfiles": "Never install these, even when the language is detected. Wins over 'profiles'.",
|
|
327
|
+
"excludeProfiles": [],
|
|
328
|
+
"//minFilesPerLanguage": "Source files a language needs before its toolchain is worth downloading. Separate from detect.minFiles: running a check that then skips is free, downloading a toolchain is not.",
|
|
329
|
+
"minFilesPerLanguage": 1,
|
|
330
|
+
"//reuseLocal": "compatible | always | off. Run the tool the REPOSITORY already has instead of our copy. \"compatible\" (default) does so when the major matches ours, or when the tool reads the repository's own config — a legacy .eslintrc can only be read by the ESLint it was written for, and a tsconfig.json by its own compiler. \"always\" reuses across a major gap at your own risk: our generated flat config does not load in ESLint 8. \"off\" always uses our pinned copy, for reproducibility.",
|
|
331
|
+
"reuseLocal": "compatible",
|
|
332
|
+
"//onMissingTool": "auto | skip | error. In a closed contour a silent skip is not acceptable — use 'error'.",
|
|
333
|
+
"onMissingTool": "auto",
|
|
334
|
+
"//offline": "Forbid every network install at run time. Pre-warm with: npx pr-checkmate install --all",
|
|
335
|
+
"offline": false,
|
|
336
|
+
"//cacheDir": "Where fetched tooling is kept; the path includes the pr-checkmate version. Cache it in CI or the tooling is fetched on every run.",
|
|
337
|
+
"cacheDir": "~/.cache/pr-checkmate",
|
|
338
|
+
"//deny": "Packages never fetched, whatever profile asks for them.",
|
|
339
|
+
"deny": [],
|
|
340
|
+
"//prewarm": "NOT YET IMPLEMENTED — accepted and ignored. Warming the cache needs a postinstall hook, and there is nothing to warm while every profile's tooling ships inside the package. Documented as inert rather than quietly doing nothing.",
|
|
341
|
+
"prewarm": true
|
|
342
|
+
},
|
|
343
|
+
"//8-languages": "Language is auto-detected. A check skips when its language is absent, and runner-dependency tools skip when the binary is missing — so leaving everything enabled is safe. TypeScript and JavaScript have no block of their own: configure them through 'eslint', 'prettier' and 'typecheck' above.",
|
|
344
|
+
"//detect": "HOW that auto-detection reads the tree, when 'languages' is not set explicitly. Generated reports, vendored code and marker files are already excluded; these knobs are for the cases the built-in rules get wrong in your repo. 'minFiles' is how many source files a language needs to count (a marker file such as pyproject.toml includes it regardless). 'excludePaths' ADDS to the built-in exclusions rather than replacing them. 'disable' drops a language outright.",
|
|
345
|
+
"detect": {
|
|
346
|
+
"minFiles": 1,
|
|
347
|
+
"excludePaths": [],
|
|
348
|
+
"disable": []
|
|
349
|
+
},
|
|
350
|
+
"python": {
|
|
351
|
+
"enabled": true,
|
|
352
|
+
"//typeChecker": "mypy | pyright — pins one checker. Leave unset: the runner's own mypy is used when it has one, our bundled pyright otherwise.",
|
|
353
|
+
"typecheck": true,
|
|
354
|
+
"ruff": {
|
|
355
|
+
"lint": true,
|
|
356
|
+
"format": true
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"cpp": {
|
|
360
|
+
"enabled": true,
|
|
361
|
+
"clangFormat": {
|
|
362
|
+
"style": "LLVM"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"swift": {
|
|
366
|
+
"enabled": true
|
|
367
|
+
},
|
|
368
|
+
"kotlin": {
|
|
369
|
+
"enabled": true
|
|
370
|
+
},
|
|
371
|
+
"go": {
|
|
372
|
+
"enabled": true
|
|
373
|
+
},
|
|
374
|
+
"rust": {
|
|
375
|
+
"enabled": true
|
|
376
|
+
},
|
|
377
|
+
"csharp": {
|
|
378
|
+
"enabled": true
|
|
379
|
+
},
|
|
380
|
+
"ruby": {
|
|
381
|
+
"enabled": true
|
|
382
|
+
},
|
|
383
|
+
"php": {
|
|
384
|
+
"enabled": true
|
|
385
|
+
},
|
|
386
|
+
"shellcheck": {
|
|
387
|
+
"//": "Needs the `shellcheck` binary on the runner; skips when absent.",
|
|
388
|
+
"enabled": true,
|
|
389
|
+
"//minSeverity": "error | warning | info | style. Omit to keep ShellCheck's own default (every level).",
|
|
390
|
+
"//ignore": "ShellCheck codes to suppress, e.g. \"SC2086\".",
|
|
391
|
+
"ignore": []
|
|
392
|
+
}
|
|
393
|
+
}
|
package/dist/esm/init.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ export declare function setupWorkflow(root: string, mode: GateMode): void;
|
|
|
30
30
|
* heart about what should block.
|
|
31
31
|
*/
|
|
32
32
|
export declare const BLOCKING_BY_DEFAULT: readonly ["Security Scan", "Sensitive Files", "Diff Security", "Workflow Security", "Merge Conflict", "NPM Audit", "License Check", "Dependencies", "TypeScript", "ESLint", "YAML Lint"];
|
|
33
|
+
/**
|
|
34
|
+
* Every option the template documents that the file does not already carry, at
|
|
35
|
+
* its default. Without this, options such as `vulnScan` (off by default) or
|
|
36
|
+
* `licenseCheck` exist only in the docs, and nobody edits what they cannot see.
|
|
37
|
+
* Comment keys travel with the option they describe, section headers with the
|
|
38
|
+
* first option after them.
|
|
39
|
+
*/
|
|
40
|
+
export declare function templateExtras(existing: Record<string, unknown>): Record<string, unknown>;
|
|
33
41
|
export declare function buildInitialConfig(sourcePath: string, languages: string[]): Record<string, unknown>;
|
|
34
42
|
/**
|
|
35
43
|
* Initialize (or refresh) pr-checkmate configuration in the current project.
|
package/dist/esm/init.js
CHANGED
|
@@ -264,8 +264,46 @@ const HOW_TO = [
|
|
|
264
264
|
`Every option, annotated, with its default: ${FULL_CONFIG_URL}`,
|
|
265
265
|
`Docs: ${DOCS_URL}`,
|
|
266
266
|
].join(' ');
|
|
267
|
+
// Written out at its defaults so the options are visible and editable in the file
|
|
268
|
+
// instead of having to be looked up. Same trade as `max-len`: the values stop
|
|
269
|
+
// tracking the package, which is the price of being able to see them.
|
|
270
|
+
const GRYPE_SCAN_SEED = {
|
|
271
|
+
'//': 'Anchore grype, cross-ecosystem. ON by default but skips when grype is absent from the runner. Only direct dependencies are reported.',
|
|
272
|
+
enabled: true,
|
|
273
|
+
minSeverity: 'medium',
|
|
274
|
+
'//ignore': 'Suppress by CVE/GHSA id or by package name.',
|
|
275
|
+
ignore: [],
|
|
276
|
+
'//timeoutMs': 'Cap on the scan. On timeout the check skips rather than fails.',
|
|
277
|
+
timeoutMs: 120000,
|
|
278
|
+
'//ci': 'Per-environment overrides (enabled, minSeverity, ignore, timeoutMs): "ci" applies on CI builds, "local" elsewhere. Example: "local": { "enabled": false }',
|
|
279
|
+
ci: {},
|
|
280
|
+
local: {},
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Every option the template documents that the file does not already carry, at
|
|
284
|
+
* its default. Without this, options such as `vulnScan` (off by default) or
|
|
285
|
+
* `licenseCheck` exist only in the docs, and nobody edits what they cannot see.
|
|
286
|
+
* Comment keys travel with the option they describe, section headers with the
|
|
287
|
+
* first option after them.
|
|
288
|
+
*/
|
|
289
|
+
export function templateExtras(existing) {
|
|
290
|
+
const templatePath = path.join(__dirname, 'config', 'pr-checkmate.template.json');
|
|
291
|
+
if (!fs.existsSync(templatePath)) {
|
|
292
|
+
return {};
|
|
293
|
+
}
|
|
294
|
+
const template = JSON.parse(fs.readFileSync(templatePath, 'utf-8'));
|
|
295
|
+
const extras = {};
|
|
296
|
+
for (const [key, value] of Object.entries(template)) {
|
|
297
|
+
const option = key.startsWith('//') ? key.slice(2) : key;
|
|
298
|
+
if (key in existing || option in existing) {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
extras[key] = value;
|
|
302
|
+
}
|
|
303
|
+
return extras;
|
|
304
|
+
}
|
|
267
305
|
export function buildInitialConfig(sourcePath, languages) {
|
|
268
|
-
|
|
306
|
+
const base = {
|
|
269
307
|
$schema: SCHEMA_PATH,
|
|
270
308
|
'// how-to': HOW_TO,
|
|
271
309
|
commands: DEFAULT_COMMANDS,
|
|
@@ -346,9 +384,13 @@ export function buildInitialConfig(sourcePath, languages) {
|
|
|
346
384
|
dataflowWindow: DEFAULT_DATAFLOW_WINDOW,
|
|
347
385
|
ignorePaths: [...DIFF_SECURITY_IGNORE_DEFAULTS],
|
|
348
386
|
},
|
|
387
|
+
grypeScan: structuredClone(GRYPE_SCAN_SEED),
|
|
349
388
|
documentation,
|
|
350
389
|
languages,
|
|
351
390
|
};
|
|
391
|
+
const extras = templateExtras(base);
|
|
392
|
+
const { documentation: docs, languages: langs, ...rest } = base;
|
|
393
|
+
return { ...rest, ...extras, documentation: docs, languages: langs };
|
|
352
394
|
}
|
|
353
395
|
/** First-run setup: prompt, write config, and scaffold workflow + tsconfig. */
|
|
354
396
|
async function createConfig(root) {
|
|
@@ -397,6 +439,10 @@ async function updateConfig(root) {
|
|
|
397
439
|
$schema: json.$schema ?? SCHEMA_PATH,
|
|
398
440
|
'// how-to': json['// how-to'] ?? HOW_TO,
|
|
399
441
|
...json,
|
|
442
|
+
// An existing file predates this option, so nobody has seen it. Added only
|
|
443
|
+
// when missing; a client's own block is never touched.
|
|
444
|
+
grypeScan: json.grypeScan ?? structuredClone(GRYPE_SCAN_SEED),
|
|
445
|
+
...templateExtras({ ...json, grypeScan: true }),
|
|
400
446
|
languages,
|
|
401
447
|
};
|
|
402
448
|
fs.writeFileSync(CONFIG_FILE, `${JSON.stringify(updated, null, 2)}\n`);
|
|
@@ -34,6 +34,15 @@ const configFiles = [
|
|
|
34
34
|
source: 'src/config/pr-checkmate-workflow-docker.yml',
|
|
35
35
|
dest: 'dist/esm/config/pr-checkmate-workflow-docker.yml',
|
|
36
36
|
},
|
|
37
|
+
// Read by `init` to seed every option into a new pr-checkmate.json.
|
|
38
|
+
{
|
|
39
|
+
source: 'src/config/pr-checkmate.template.json',
|
|
40
|
+
dest: 'dist/cjs/config/pr-checkmate.template.json',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
source: 'src/config/pr-checkmate.template.json',
|
|
44
|
+
dest: 'dist/esm/config/pr-checkmate.template.json',
|
|
45
|
+
},
|
|
37
46
|
{ source: 'src/config/pr-checkmate.schema.json', dest: 'pr-checkmate.schema.json' },
|
|
38
47
|
];
|
|
39
48
|
/**
|
package/package.json
CHANGED