pr-checkmate 1.22.7 → 1.23.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 (140) hide show
  1. package/README.md +101 -333
  2. package/cspell.json +9 -1
  3. package/dist/cli.js +32 -2
  4. package/dist/config/constants.d.ts +25 -1
  5. package/dist/config/constants.js +157 -38
  6. package/dist/config/index.d.ts +15 -2
  7. package/dist/config/index.js +28 -7
  8. package/dist/config/loader.js +5 -1
  9. package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
  10. package/dist/core/checks/dependencies/banned-imports.js +71 -0
  11. package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
  12. package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +9 -10
  13. package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
  14. package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
  15. package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
  16. package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
  17. package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
  18. package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
  19. package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
  20. package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
  21. package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
  22. package/dist/core/checks/dependencies/vuln-scan.js +41 -0
  23. package/dist/core/checks/findings.d.ts +37 -1
  24. package/dist/core/checks/findings.js +80 -3
  25. package/dist/core/checks/git/custom-rules.d.ts +2 -0
  26. package/dist/core/checks/git/custom-rules.js +102 -0
  27. package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
  28. package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
  29. package/dist/core/checks/git/large-files.d.ts +2 -0
  30. package/dist/core/checks/git/large-files.js +83 -0
  31. package/dist/core/checks/git/leftover-debug.d.ts +2 -0
  32. package/dist/core/checks/git/leftover-debug.js +77 -0
  33. package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
  34. package/dist/core/checks/git/lockfile-drift.js +114 -0
  35. package/dist/core/checks/git/merge-conflict.d.ts +2 -0
  36. package/dist/core/checks/git/merge-conflict.js +109 -0
  37. package/dist/core/checks/git/missing-tests.d.ts +2 -0
  38. package/dist/core/checks/git/missing-tests.js +92 -0
  39. package/dist/core/checks/git/todo-fixme.d.ts +7 -0
  40. package/dist/core/checks/git/todo-fixme.js +74 -0
  41. package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
  42. package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
  43. package/dist/core/checks/languages/csharp-format.d.ts +13 -0
  44. package/dist/core/checks/languages/csharp-format.js +52 -0
  45. package/dist/core/checks/languages/go-format.d.ts +8 -0
  46. package/dist/core/checks/languages/go-format.js +48 -0
  47. package/dist/core/checks/languages/go-lint.d.ts +8 -0
  48. package/dist/core/checks/languages/go-lint.js +48 -0
  49. package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
  50. package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
  51. package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
  52. package/dist/core/checks/{lint.js → languages/lint.js} +25 -14
  53. package/dist/core/checks/languages/php-format.d.ts +9 -0
  54. package/dist/core/checks/languages/php-format.js +49 -0
  55. package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
  56. package/dist/core/checks/{prettier.js → languages/prettier.js} +10 -10
  57. package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
  58. package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
  59. package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
  60. package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
  61. package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
  62. package/dist/core/checks/languages/python-typecheck.js +66 -0
  63. package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
  64. package/dist/core/checks/languages/ruby-lint.js +50 -0
  65. package/dist/core/checks/languages/rust-format.d.ts +9 -0
  66. package/dist/core/checks/languages/rust-format.js +45 -0
  67. package/dist/core/checks/languages/rust-lint.d.ts +8 -0
  68. package/dist/core/checks/languages/rust-lint.js +50 -0
  69. package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
  70. package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
  71. package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
  72. package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
  73. package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
  74. package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
  75. package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
  76. package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
  77. package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
  78. package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
  79. package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
  80. package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
  81. package/dist/core/checks/quality/case-collision.d.ts +8 -0
  82. package/dist/core/checks/quality/case-collision.js +40 -0
  83. package/dist/core/checks/quality/config-validation.d.ts +8 -0
  84. package/dist/core/checks/quality/config-validation.js +63 -0
  85. package/dist/core/checks/quality/coverage.d.ts +2 -0
  86. package/dist/core/checks/quality/coverage.js +63 -0
  87. package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
  88. package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
  89. package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
  90. package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +11 -15
  91. package/dist/core/checks/quality/license-header.d.ts +7 -0
  92. package/dist/core/checks/quality/license-header.js +74 -0
  93. package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
  94. package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +8 -21
  95. package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
  96. package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +11 -19
  97. package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
  98. package/dist/core/checks/security/diff-security.js +262 -0
  99. package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
  100. package/dist/core/checks/security/dockerfile-security.js +92 -0
  101. package/dist/core/checks/security/migration-safety.d.ts +2 -0
  102. package/dist/core/checks/security/migration-safety.js +110 -0
  103. package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
  104. package/dist/core/checks/{security.js → security/security.js} +4 -4
  105. package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
  106. package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
  107. package/dist/core/checks/security/workflow-security.d.ts +2 -0
  108. package/dist/core/checks/security/workflow-security.js +75 -0
  109. package/dist/core/context.js +54 -10
  110. package/dist/core/registry.js +73 -28
  111. package/dist/core/reporters.d.ts +4 -3
  112. package/dist/core/reporters.js +104 -4
  113. package/dist/core/run-checks.js +21 -3
  114. package/dist/core/targets.d.ts +17 -1
  115. package/dist/core/targets.js +74 -4
  116. package/dist/core/types.d.ts +13 -1
  117. package/dist/index.d.ts +1 -1
  118. package/dist/index.js +3 -1
  119. package/dist/init.js +86 -8
  120. package/dist/interfaces/index.d.ts +101 -1
  121. package/dist/scripts/copy-configs.js +6 -1
  122. package/dist/utils/detect-language.d.ts +1 -1
  123. package/dist/utils/detect-language.js +32 -3
  124. package/dist/utils/glob.d.ts +10 -0
  125. package/dist/utils/glob.js +25 -0
  126. package/dist/utils/index.d.ts +1 -1
  127. package/dist/utils/index.js +1 -1
  128. package/eslint-default-rules.json +62 -0
  129. package/eslint.config.mjs +6 -66
  130. package/package.json +3 -1
  131. package/pr-checkmate.schema.json +166 -0
  132. package/src/config/cspell.json +9 -1
  133. package/src/config/eslint-default-rules.json +62 -0
  134. package/src/config/pr-checkmate.schema.json +166 -0
  135. package/dist/core/checks/diff-security.js +0 -145
  136. package/dist/utils/delta.d.ts +0 -5
  137. package/dist/utils/delta.js +0 -53
  138. package/src/config/eslint.config.mjs +0 -180
  139. /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
  140. /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
@@ -3,57 +3,109 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CONFIG_FILE = exports.documentation = exports.DEFAULT_ALLOW_PACKAGES = exports.DEFAULT_COMMANDS = exports.SOURCE_EXTENSIONS = exports.DUPLICATE_CODE_FORMATS = exports.CONFIG_FILE_PATTERNS = exports.DEAD_CODE_IGNORE_DEFAULTS = exports.DUPLICATE_IGNORE_DEFAULTS = exports.IGNORE_PATTERNS = void 0;
6
+ exports.KNOWN_CONFIG_KEYS = exports.CONFIG_FILE = exports.documentation = exports.DEFAULT_ALLOW_PACKAGES = exports.DEFAULT_COMMANDS = exports.SOURCE_EXTENSIONS = exports.DUPLICATE_CODE_FORMATS = exports.CONFIG_FILE_PATTERNS = exports.DEAD_CODE_IGNORE_DEFAULTS = exports.DUPLICATE_IGNORE_DEFAULTS = exports.IGNORE_PATTERNS = exports.IGNORED_DIRS = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
8
  /**
9
- * Common patterns to ignore in all checks
9
+ * Build output, dependency, tooling, and report directories that are never
10
+ * product code. Every check excludes them by directory-name segment match (see
11
+ * `targets.ts`): a match on any segment of a path drops the file. Untracked
12
+ * build dirs are already excluded because checks read git-tracked files only —
13
+ * this list additionally covers dirs that repos commonly *commit* (`.github`,
14
+ * `.vscode`, `.idea`, `.claude`) and any checked-in build artifacts.
15
+ *
16
+ * Covers the common ecosystems: Node/JS/web, Python, Java/Kotlin/Gradle/Android,
17
+ * Swift/iOS/Xcode, and C/C++/CMake. Add more here.
18
+ */
19
+ exports.IGNORED_DIRS = [
20
+ // VCS, editors, and CI/tooling config
21
+ '.git',
22
+ '.github',
23
+ '.gitlab',
24
+ '.vscode',
25
+ '.vs',
26
+ '.idea',
27
+ '.claude',
28
+ '.cursor',
29
+ '.husky',
30
+ '.circleci',
31
+ // Node / JS / web — build output & caches
32
+ 'node_modules',
33
+ 'dist',
34
+ 'build',
35
+ 'build-release',
36
+ 'out',
37
+ 'coverage',
38
+ '.next',
39
+ '.nuxt',
40
+ '.svelte-kit',
41
+ '.turbo',
42
+ '.cache',
43
+ '.parcel-cache',
44
+ '.vercel',
45
+ '.wrangler',
46
+ '.serverless',
47
+ '.terraform',
48
+ // Python
49
+ '__pycache__',
50
+ '.pytest_cache',
51
+ '.mypy_cache',
52
+ '.ruff_cache',
53
+ '.tox',
54
+ '.venv',
55
+ 'venv',
56
+ '.eggs',
57
+ 'htmlcov',
58
+ // Java / Kotlin / Gradle / Android
59
+ '.gradle',
60
+ '.kotlin',
61
+ 'target',
62
+ 'gen',
63
+ 'captures',
64
+ // Swift / iOS / Xcode
65
+ '.build',
66
+ '.swiftpm',
67
+ 'DerivedData',
68
+ 'Pods',
69
+ 'Carthage',
70
+ // C / C++ / CMake
71
+ 'CMakeFiles',
72
+ 'cmake-build-debug',
73
+ 'cmake-build-release',
74
+ '_deps',
75
+ // Test reports / results / logs / release artifacts
76
+ 'reports',
77
+ 'report',
78
+ 'test-reports',
79
+ 'test-report',
80
+ 'test-output',
81
+ 'test-results',
82
+ 'results',
83
+ 'result',
84
+ 'logs',
85
+ 'allure-report',
86
+ 'allure-results',
87
+ 'playwright-report',
88
+ '.wdio',
89
+ ];
90
+ /**
91
+ * Glob form of the ignore list, for tools that take glob ignores directly
92
+ * (ESLint `--ignore-pattern`, cspell `--exclude`, the generated
93
+ * `.prettierignore`). Combines {@link IGNORED_DIRS} with a few tool-specific
94
+ * nested report globs that are not plain directory names.
10
95
  */
11
96
  exports.IGNORE_PATTERNS = [
12
- '**/node_modules/**',
13
- '**/dist/**',
14
- '**/.git/**',
15
- '**/build/**',
16
- '**/coverage/**',
17
- '**/.next/**',
18
- '**/.nuxt/**',
19
- '**/out/**',
20
- '**/__pycache__/**',
21
- '**/.pytest_cache/**',
22
- '**/.venv/**',
23
- '**/venv/**',
24
- '**/allure-report/**',
25
- '**/allure-results/**',
26
- '**/reports/**',
27
- '**/report/**',
28
- '**/test-reports/**',
29
- '**/test-report/**',
30
- '**/test-output/**',
31
- '**/test-results/**',
32
- '**/results/**',
33
- '**/result/**',
34
- '**/logs/**',
35
- // Jest
97
+ ...exports.IGNORED_DIRS.map(dir => `**/${dir}/**`),
98
+ // Tool-specific nested report dirs / files (not bare directory names)
36
99
  '**/jest-html-reporters-*/**',
37
100
  '**/jest-stare/**',
38
- // Cypress
39
101
  '**/cypress/reports/**',
40
102
  '**/cypress/videos/**',
41
103
  '**/cypress/screenshots/**',
42
- // Playwright
43
- '**/playwright-report/**',
44
- // WebdriverIO
45
- '**/.wdio/**',
46
- '**/wdio-logs/**',
47
- // Mocha / Jasmine
48
104
  '**/mochawesome-report/**',
49
105
  '**/mochawesome-reports/**',
50
- // JUnit / Surefire / Maven
51
106
  '**/target/surefire-reports/**',
52
107
  '**/target/failsafe-reports/**',
53
- // Python testing
54
- '**/.pytest_cache/**',
55
- '**/htmlcov/**',
56
- // Misc reports
108
+ '**/wdio-logs/**',
57
109
  '**/lint-report/**',
58
110
  '**/audit-report/**',
59
111
  ];
@@ -162,3 +214,70 @@ exports.documentation = {
162
214
  cspell: 'https://cspell.org/configuration/',
163
215
  };
164
216
  exports.CONFIG_FILE = node_path_1.default.resolve(process.cwd(), 'pr-checkmate.json');
217
+ /**
218
+ * Every top-level key PR CheckMate recognises in pr-checkmate.json — the union
219
+ * of the `PRCheckMateConfig` interface fields and the keys the `init` generator
220
+ * writes (which use `eslint`/`cspell`/`markdownlint` rather than the interface's
221
+ * `lint`/`spellcheck`). The Config Validation check warns on any key not in this
222
+ * set (typos), ignoring `//`-prefixed comment keys and `$schema`. Keep in sync
223
+ * when adding a new configurable check.
224
+ */
225
+ exports.KNOWN_CONFIG_KEYS = new Set([
226
+ // core
227
+ 'sourcePath',
228
+ 'ignoreDirs',
229
+ 'languages',
230
+ 'severity',
231
+ 'customRules',
232
+ '$schema',
233
+ 'commands',
234
+ 'documentation',
235
+ 'configValidation',
236
+ // linters/formatters (interface + init aliases)
237
+ 'lint',
238
+ 'eslint',
239
+ 'prettier',
240
+ 'spellcheck',
241
+ 'cspell',
242
+ 'markdownlint',
243
+ 'typecheck',
244
+ // security
245
+ 'security',
246
+ 'diffSecurity',
247
+ 'workflowSecurity',
248
+ 'dockerfileSecurity',
249
+ 'sensitiveFileGuard',
250
+ 'migrationSafety',
251
+ // dependencies
252
+ 'dependency',
253
+ 'outdatedDeps',
254
+ 'licenseCheck',
255
+ 'vulnScan',
256
+ 'bannedImports',
257
+ // git-diff / PR
258
+ 'mergeConflict',
259
+ 'diffSmell',
260
+ 'leftoverDebug',
261
+ 'todoFixme',
262
+ 'lockfileDrift',
263
+ 'largeFiles',
264
+ 'missingTests',
265
+ 'coverage',
266
+ 'caseCollision',
267
+ 'licenseHeader',
268
+ 'duplicate',
269
+ 'deadCode',
270
+ 'prBody',
271
+ 'prSize',
272
+ 'commitlint',
273
+ // languages
274
+ 'cpp',
275
+ 'python',
276
+ 'swift',
277
+ 'kotlin',
278
+ 'go',
279
+ 'rust',
280
+ 'csharp',
281
+ 'ruby',
282
+ 'php',
283
+ ]);
@@ -1,10 +1,23 @@
1
1
  export * from './constants';
2
2
  export { loadProjectConfig } from '../config/loader';
3
3
  /**
4
- * Get SOURCE_PATH dynamically
5
- * This ensures fresh config is always read
4
+ * Get the configured source path(s) dynamically as a normalized list.
5
+ * Accepts a single string or an array in pr-checkmate.json; empty/invalid
6
+ * values fall back to `['.']` (the whole repo). Clients narrow scanning to a
7
+ * subdirectory by setting `sourcePath` in their pr-checkmate.json. Always reads
8
+ * fresh config.
9
+ */
10
+ export declare function getSourcePaths(): string[];
11
+ /**
12
+ * Get a single source path (first configured entry) for callers that only
13
+ * support one directory. Prefer `getSourcePaths()` for scan targets.
6
14
  */
7
15
  export declare function getSourcePath(): string;
16
+ /**
17
+ * Get the effective list of directory names excluded from every check
18
+ * (client `ignoreDirs` in pr-checkmate.json, or the curated default).
19
+ */
20
+ export declare function getIgnoredDirs(): string[];
8
21
  /**
9
22
  * Get path to package config files
10
23
  */
@@ -18,16 +18,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
20
  exports.loadProjectConfig = void 0;
21
+ exports.getSourcePaths = getSourcePaths;
21
22
  exports.getSourcePath = getSourcePath;
23
+ exports.getIgnoredDirs = getIgnoredDirs;
22
24
  exports.getPackageConfigPath = getPackageConfigPath;
23
25
  exports.hasLocalConfig = hasLocalConfig;
24
26
  const node_fs_1 = __importDefault(require("node:fs"));
25
27
  const node_path_1 = __importDefault(require("node:path"));
28
+ const loader_1 = require("../config/loader");
26
29
  const utils_1 = require("../utils");
27
30
  const constants_1 = require("./constants");
28
31
  __exportStar(require("./constants"), exports);
29
- var loader_1 = require("../config/loader");
30
- Object.defineProperty(exports, "loadProjectConfig", { enumerable: true, get: function () { return loader_1.loadProjectConfig; } });
32
+ var loader_2 = require("../config/loader");
33
+ Object.defineProperty(exports, "loadProjectConfig", { enumerable: true, get: function () { return loader_2.loadProjectConfig; } });
31
34
  /**
32
35
  * Load configuration dynamically (always reads fresh config)
33
36
  */
@@ -41,15 +44,33 @@ function loadConfig() {
41
44
  catch (err) {
42
45
  utils_1.logger.warn(`⚠️ Failed to read config from ${constants_1.CONFIG_FILE}, using defaults${err}`);
43
46
  }
44
- return { sourcePath: 'src' };
47
+ return { sourcePath: '.' };
45
48
  }
46
49
  /**
47
- * Get SOURCE_PATH dynamically
48
- * This ensures fresh config is always read
50
+ * Get the configured source path(s) dynamically as a normalized list.
51
+ * Accepts a single string or an array in pr-checkmate.json; empty/invalid
52
+ * values fall back to `['.']` (the whole repo). Clients narrow scanning to a
53
+ * subdirectory by setting `sourcePath` in their pr-checkmate.json. Always reads
54
+ * fresh config.
55
+ */
56
+ function getSourcePaths() {
57
+ const { sourcePath } = loadConfig();
58
+ const paths = (Array.isArray(sourcePath) ? sourcePath : [sourcePath]).filter((p) => typeof p === 'string' && p.trim().length > 0);
59
+ return paths.length > 0 ? paths : ['.'];
60
+ }
61
+ /**
62
+ * Get a single source path (first configured entry) for callers that only
63
+ * support one directory. Prefer `getSourcePaths()` for scan targets.
49
64
  */
50
65
  function getSourcePath() {
51
- const config = loadConfig();
52
- return config.sourcePath;
66
+ return getSourcePaths()[0];
67
+ }
68
+ /**
69
+ * Get the effective list of directory names excluded from every check
70
+ * (client `ignoreDirs` in pr-checkmate.json, or the curated default).
71
+ */
72
+ function getIgnoredDirs() {
73
+ return (0, loader_1.loadProjectConfig)().ignoreDirs ?? [];
53
74
  }
54
75
  /**
55
76
  * Get path to package config files
@@ -34,6 +34,9 @@ function mergeWithDefaults(userConfig) {
34
34
  const defaults = getDefaultConfig();
35
35
  return {
36
36
  sourcePath: userConfig.sourcePath || defaults.sourcePath,
37
+ // Replace (not merge): the client sees the full default list in their
38
+ // generated config and edits it directly, so their list is authoritative.
39
+ ignoreDirs: userConfig.ignoreDirs ?? defaults.ignoreDirs,
37
40
  lint: {
38
41
  rules: { ...defaults.lint?.rules, ...userConfig.lint?.rules },
39
42
  ignorePatterns: [
@@ -90,7 +93,8 @@ function mergeWithDefaults(userConfig) {
90
93
  */
91
94
  function getDefaultConfig() {
92
95
  return {
93
- sourcePath: 'src',
96
+ sourcePath: '.',
97
+ ignoreDirs: [...constants_1.IGNORED_DIRS],
94
98
  lint: {
95
99
  rules: {
96
100
  'no-console': 'warn',
@@ -0,0 +1,2 @@
1
+ import { Check } from '../../types';
2
+ export declare const bannedImportsCheck: Check;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bannedImportsCheck = void 0;
4
+ const utils_1 = require("../../../utils");
5
+ const types_1 = require("../../types");
6
+ const findings_1 = require("../findings");
7
+ const PREFIX = 'Banned Imports';
8
+ const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
9
+ /**
10
+ * Compile `bannedImports` into matchers that catch a banned package via an ES
11
+ * import, a CommonJS require, or its addition to a manifest dependency list.
12
+ */
13
+ function compileBans(ctx) {
14
+ const list = ctx.config.bannedImports ?? [];
15
+ return list
16
+ .filter(b => b?.name)
17
+ .map(b => {
18
+ const n = escapeRe(b.name);
19
+ const re = new RegExp(`from\\s+['"]${n}(?:/[^'"]*)?['"]|require\\(\\s*['"]${n}(?:/[^'"]*)?['"]|import\\s+['"]${n}['"]|["']${n}["']\\s*:`);
20
+ return {
21
+ message: b.message ?? `banned dependency: ${b.name}`,
22
+ re,
23
+ severity: b.severity === 'error' ? 'error' : 'warn',
24
+ };
25
+ });
26
+ }
27
+ exports.bannedImportsCheck = {
28
+ name: 'Banned Imports',
29
+ phase: 'informational',
30
+ applies(ctx) {
31
+ return (ctx.config.bannedImports?.length ?? 0) > 0 && Boolean(ctx.baseSha);
32
+ },
33
+ async run(ctx) {
34
+ var _a;
35
+ const bans = compileBans(ctx);
36
+ if (bans.length === 0)
37
+ return (0, types_1.pass)('no banned imports configured');
38
+ try {
39
+ const stdout = await (0, findings_1.diffAddedLines)(ctx, ['*']);
40
+ const errors = {};
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));
50
+ }
51
+ }
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(', '));
65
+ }
66
+ catch (err) {
67
+ utils_1.logger.warn(`[Banned Imports]: ⚠️ Could not analyze diff\n${err}`);
68
+ return (0, types_1.skip)('diff unavailable');
69
+ }
70
+ },
71
+ };
@@ -1,2 +1,2 @@
1
- import { Check } from '../types';
1
+ import { Check } from '../../types';
2
2
  export declare const circularDepsCheck: Check;
@@ -1,14 +1,11 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.circularDepsCheck = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const config_1 = require("../../config");
9
- const utils_1 = require("../../utils");
10
- const execa_1 = require("../../utils/execa");
11
- const types_1 = require("../types");
4
+ const config_1 = require("../../../config");
5
+ const utils_1 = require("../../../utils");
6
+ const execa_1 = require("../../../utils/execa");
7
+ const targets_1 = require("../../targets");
8
+ const types_1 = require("../../types");
12
9
  exports.circularDepsCheck = {
13
10
  name: 'Circular Deps',
14
11
  phase: 'blocking',
@@ -16,8 +13,10 @@ exports.circularDepsCheck = {
16
13
  return ctx.languages.includes('typescript') || ctx.languages.includes('javascript');
17
14
  },
18
15
  async run(ctx) {
19
- const pattern = node_path_1.default.join(ctx.cwd, (0, config_1.getSourcePath)(), '**/*.{ts,tsx,js,jsx}');
20
- const result = await (0, execa_1.execa)('npx', ['dpdm', '--no-warning', '--no-tree', '--circular', pattern], {
16
+ const files = await (0, targets_1.listTrackedFiles)(ctx, ['*.ts', '*.tsx', '*.js', '*.jsx'], (0, config_1.getSourcePaths)());
17
+ if (files.length === 0)
18
+ return (0, types_1.pass)();
19
+ const result = await (0, execa_1.execa)('npx', ['dpdm', '--no-warning', '--no-tree', '--circular', ...files], {
21
20
  cwd: ctx.cwd,
22
21
  reject: false,
23
22
  });
@@ -1,2 +1,2 @@
1
- import { Check } from '../types';
1
+ import { Check } from '../../types';
2
2
  export declare const dependencyCheck: Check;
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.dependencyCheck = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const utils_1 = require("../../utils");
10
- const execa_1 = require("../../utils/execa");
11
- const types_1 = require("../types");
9
+ const utils_1 = require("../../../utils");
10
+ const execa_1 = require("../../../utils/execa");
11
+ const types_1 = require("../../types");
12
12
  exports.dependencyCheck = {
13
13
  name: 'Dependencies',
14
14
  phase: 'blocking',
@@ -1,2 +1,2 @@
1
- import { Check } from '../types';
1
+ import { Check } from '../../types';
2
2
  export declare const licenseCheck: Check;
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.licenseCheck = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const utils_1 = require("../../utils");
10
- const execa_1 = require("../../utils/execa");
11
- const types_1 = require("../types");
9
+ const utils_1 = require("../../../utils");
10
+ const execa_1 = require("../../../utils/execa");
11
+ const types_1 = require("../../types");
12
12
  const FORBIDDEN_LICENSES = ['GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'LGPL-2.0', 'LGPL-2.1', 'LGPL-3.0'];
13
13
  /** Strip the trailing "@version" to get the bare package name (scoped-safe). */
14
14
  function bareName(pkgKey) {
@@ -1,4 +1,4 @@
1
- import { Check } from '../types';
1
+ import { Check } from '../../types';
2
2
  /**
3
3
  * npm audit — only direct-dependency vulnerabilities block. Transitive ones and
4
4
  * vulnerabilities in pr-checkmate itself are ignored (the client cannot fix those).
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.npmAuditCheck = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const utils_1 = require("../../utils");
10
- const execa_1 = require("../../utils/execa");
11
- const types_1 = require("../types");
9
+ const utils_1 = require("../../../utils");
10
+ const execa_1 = require("../../../utils/execa");
11
+ const types_1 = require("../../types");
12
12
  const SEVERITY_ORDER = ['info', 'low', 'moderate', 'high', 'critical'];
13
13
  function isSeverityAtLeast(severity, level) {
14
14
  const sevIdx = SEVERITY_ORDER.indexOf(severity);
@@ -1,2 +1,2 @@
1
- import { Check } from '../types';
1
+ import { Check } from '../../types';
2
2
  export declare const outdatedDepsCheck: Check;
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.outdatedDepsCheck = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const utils_1 = require("../../utils");
10
- const execa_1 = require("../../utils/execa");
11
- const types_1 = require("../types");
9
+ const utils_1 = require("../../../utils");
10
+ const execa_1 = require("../../../utils/execa");
11
+ const types_1 = require("../../types");
12
12
  exports.outdatedDepsCheck = {
13
13
  name: 'Outdated Deps',
14
14
  phase: 'informational',
@@ -0,0 +1,9 @@
1
+ import { Check } from '../../types';
2
+ /**
3
+ * Cross-language dependency vulnerability scan via osv-scanner, which reads
4
+ * lockfiles across ecosystems (npm, PyPI, Go, crates, Maven, …) against the OSV
5
+ * database. Runner-dependency and opt-in (`vulnScan.enabled: true`): osv-scanner
6
+ * must be on the runner, and the check skips gracefully when it is absent.
7
+ * Complements the JS-only `npm-audit` with coverage for every other ecosystem.
8
+ */
9
+ export declare const vulnScanCheck: Check;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.vulnScanCheck = void 0;
4
+ const utils_1 = require("../../../utils");
5
+ const execa_1 = require("../../../utils/execa");
6
+ const types_1 = require("../../types");
7
+ /**
8
+ * Cross-language dependency vulnerability scan via osv-scanner, which reads
9
+ * lockfiles across ecosystems (npm, PyPI, Go, crates, Maven, …) against the OSV
10
+ * database. Runner-dependency and opt-in (`vulnScan.enabled: true`): osv-scanner
11
+ * must be on the runner, and the check skips gracefully when it is absent.
12
+ * Complements the JS-only `npm-audit` with coverage for every other ecosystem.
13
+ */
14
+ exports.vulnScanCheck = {
15
+ name: 'Vuln Scan',
16
+ phase: 'informational',
17
+ applies(ctx) {
18
+ return ctx.config.vulnScan?.enabled === true;
19
+ },
20
+ async run(ctx) {
21
+ const result = await (0, execa_1.execa)('osv-scanner', ['-r', '.'], { cwd: ctx.cwd, reject: false });
22
+ // execa v9 with reject:false resolves (not throws) with `code: 'ENOENT'`
23
+ // when the binary is absent — detect the missing scanner on the result.
24
+ if (result.code === 'ENOENT')
25
+ return (0, types_1.skip)('osv-scanner not installed');
26
+ if (result.exitCode === 0) {
27
+ utils_1.logger.info('[Vuln Scan]: ✅ No known vulnerabilities');
28
+ return (0, types_1.pass)();
29
+ }
30
+ const lines = [result.stdout, result.stderr]
31
+ .filter(Boolean)
32
+ .join('\n')
33
+ .split('\n')
34
+ .filter(l => /\b(CVE-|GHSA-|vulnerab|advisor)/i.test(l));
35
+ utils_1.logger.warn('[Vuln Scan]: ⚠️ known vulnerabilities found:');
36
+ lines.slice(0, 10).forEach(l => utils_1.logger.warn(` ${l.trim()}`));
37
+ if (lines.length > 10)
38
+ utils_1.logger.warn(` ... and ${lines.length - 10} more`);
39
+ return (0, types_1.warn)(`${lines.length || 'unknown'} vulnerability finding(s) (osv-scanner)`);
40
+ },
41
+ };
@@ -1,4 +1,26 @@
1
1
  import { CheckContext, CheckOutcome } from '../types';
2
+ /**
3
+ * Client-configurable severity for a check's findings, read from that check's
4
+ * config block (e.g. `mergeConflict.severity`). `error` fails the run, `warn`
5
+ * only advises. Every check declares a natural default; the client overrides it
6
+ * per repo in pr-checkmate.json — promoting an advisory check to a gate, or
7
+ * downgrading a blocking one, with no code change.
8
+ */
9
+ export type Severity = 'error' | 'warn';
10
+ export interface SeverityEmitter {
11
+ /** Log at the resolved level (`logger.error` for error, `logger.warn` for warn). */
12
+ log: (msg: string) => void;
13
+ /** Prefix icon matching the level. */
14
+ icon: string;
15
+ /** Build the outcome at the resolved level (`fail` for error, `warn` for warn). */
16
+ emit: (details: string) => CheckOutcome;
17
+ }
18
+ /**
19
+ * Resolve a check's effective severity (`configured` from config, else its
20
+ * `fallback`) into a matched logger, icon, and outcome constructor — so a check
21
+ * logs and returns consistently at whatever level the client chose.
22
+ */
23
+ export declare function severityEmitter(configured: Severity | undefined, fallback: Severity): SeverityEmitter;
2
24
  /** Findings grouped by label → matching sample strings. */
3
25
  export type FindingBucket = Record<string, string[]>;
4
26
  /**
@@ -6,6 +28,14 @@ export type FindingBucket = Record<string, string[]>;
6
28
  * (zero context, added/copied/modified/renamed files) for added-line scanning.
7
29
  */
8
30
  export declare function diffAddedLines(ctx: CheckContext, globs: string[]): Promise<string>;
31
+ /**
32
+ * Strip a trailing line comment (`//` or `#`) from a line, tracking quote state
33
+ * so a marker inside a string literal (or a `#` in `"#fff"`, a `//` in a quoted
34
+ * URL) is preserved. Heuristic, not a tokenizer: block comments and regex
35
+ * literals aren't handled. Used by code-targeting checks so `# print(x)` or
36
+ * `// eval(x)` in a comment isn't flagged as real code.
37
+ */
38
+ export declare function stripInlineComment(line: string): string;
9
39
  /** Total number of findings across all labels in a bucket. */
10
40
  export declare function bucketTotal(bucket: FindingBucket): number;
11
41
  interface LogOptions {
@@ -31,10 +61,16 @@ interface SeverityReportOptions {
31
61
  showCount?: boolean;
32
62
  /** Max samples printed per label; omit to print all. */
33
63
  sampleLimit?: number;
64
+ /**
65
+ * Finding labels to suppress (client `<check>.ignore`). A label is dropped
66
+ * when it contains any ignore entry (case-insensitive), so a repo can mute a
67
+ * single built-in finding without disabling the whole check.
68
+ */
69
+ ignore?: string[];
34
70
  }
35
71
  /**
36
72
  * Report error/warning finding buckets: log both, then produce the outcome.
37
73
  * Returns pass() when both buckets are empty, otherwise warn() with a summary.
38
74
  */
39
- export declare function reportSeverityBuckets(errors: FindingBucket, warnings: FindingBucket, opts: SeverityReportOptions): CheckOutcome;
75
+ export declare function reportSeverityBuckets(errorsIn: FindingBucket, warningsIn: FindingBucket, opts: SeverityReportOptions): CheckOutcome;
40
76
  export {};