pr-checkmate 2.1.0 → 3.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 (109) hide show
  1. package/README.md +63 -267
  2. package/cspell.json +155 -133
  3. package/dist/config/constants.d.ts +13 -1
  4. package/dist/config/constants.js +20 -7
  5. package/dist/config/index.d.ts +23 -11
  6. package/dist/config/index.js +27 -33
  7. package/dist/core/checks/dependencies/banned-imports.js +4 -1
  8. package/dist/core/checks/dependencies/circular-deps.js +14 -5
  9. package/dist/core/checks/dependencies/dependency-check.js +2 -2
  10. package/dist/core/checks/dependencies/grype-scan.js +2 -1
  11. package/dist/core/checks/dependencies/license-check.js +1 -6
  12. package/dist/core/checks/dependencies/npm-audit.js +1 -1
  13. package/dist/core/checks/dependencies/outdated-deps.js +1 -6
  14. package/dist/core/checks/dependencies/vuln-scan.js +2 -1
  15. package/dist/core/checks/findings.d.ts +46 -2
  16. package/dist/core/checks/findings.js +140 -2
  17. package/dist/core/checks/git/custom-rules.js +2 -0
  18. package/dist/core/checks/git/diff-smell.js +6 -1
  19. package/dist/core/checks/git/leftover-debug.js +8 -2
  20. package/dist/core/checks/git/lockfile-drift.js +6 -1
  21. package/dist/core/checks/git/merge-conflict.js +1 -1
  22. package/dist/core/checks/git/missing-tests.js +1 -1
  23. package/dist/core/checks/git/todo-fixme.js +10 -2
  24. package/dist/core/checks/languages/cpp-format.js +19 -42
  25. package/dist/core/checks/languages/external-checks.d.ts +77 -0
  26. package/dist/core/checks/languages/external-checks.js +200 -0
  27. package/dist/core/checks/languages/external-runner.d.ts +119 -0
  28. package/dist/core/checks/languages/external-runner.js +143 -0
  29. package/dist/core/checks/languages/go-format.d.ts +4 -4
  30. package/dist/core/checks/languages/go-format.js +151 -30
  31. package/dist/core/checks/languages/lint.js +19 -19
  32. package/dist/core/checks/languages/prettier.js +2 -7
  33. package/dist/core/checks/languages/python-typecheck.d.ts +10 -5
  34. package/dist/core/checks/languages/python-typecheck.js +161 -37
  35. package/dist/core/checks/languages/typecheck.js +10 -8
  36. package/dist/core/checks/pr/commitlint.js +7 -1
  37. package/dist/core/checks/quality/case-collision.js +6 -4
  38. package/dist/core/checks/quality/config-validation.d.ts +0 -7
  39. package/dist/core/checks/quality/config-validation.js +30 -0
  40. package/dist/core/checks/quality/duplicate-check.js +86 -28
  41. package/dist/core/checks/quality/license-header.js +7 -4
  42. package/dist/core/checks/quality/markdown-lint.js +1 -6
  43. package/dist/core/checks/quality/spellcheck.js +34 -5
  44. package/dist/core/checks/quality/symlinks.js +6 -4
  45. package/dist/core/checks/security/diff-security.js +26 -18
  46. package/dist/core/checks/security/dockerfile-security.js +7 -1
  47. package/dist/core/checks/security/migration-safety.js +32 -4
  48. package/dist/core/checks/security/security.d.ts +56 -0
  49. package/dist/core/checks/security/security.js +135 -11
  50. package/dist/core/checks/security/sensitive-file-guard.js +40 -6
  51. package/dist/core/checks/security/workflow-security.js +7 -1
  52. package/dist/core/checks/tool-install.d.ts +102 -0
  53. package/dist/core/checks/tool-install.js +69 -0
  54. package/dist/core/context.js +9 -1
  55. package/dist/core/install/cache.js +42 -11
  56. package/dist/core/install/doctor.d.ts +2 -2
  57. package/dist/core/install/doctor.js +17 -16
  58. package/dist/core/install/ensure.js +22 -3
  59. package/dist/core/install/lock.d.ts +2 -1
  60. package/dist/core/install/prepare.d.ts +75 -0
  61. package/dist/core/install/prepare.js +151 -0
  62. package/dist/core/install/profiles.d.ts +17 -3
  63. package/dist/core/install/profiles.js +27 -0
  64. package/dist/core/install/reuse.d.ts +41 -0
  65. package/dist/core/install/reuse.js +107 -0
  66. package/dist/core/registry.js +10 -18
  67. package/dist/core/reporters.js +8 -2
  68. package/dist/core/run-checks.js +74 -3
  69. package/dist/core/targets.d.ts +116 -5
  70. package/dist/core/targets.js +101 -16
  71. package/dist/core/types.d.ts +26 -2
  72. package/dist/core/types.js +28 -0
  73. package/dist/init.js +21 -1
  74. package/dist/interfaces/index.d.ts +1 -0
  75. package/dist/utils/detect-language.js +11 -1
  76. package/dist/utils/index.d.ts +1 -0
  77. package/dist/utils/index.js +1 -0
  78. package/dist/utils/package-version.d.ts +4 -0
  79. package/dist/utils/package-version.js +41 -0
  80. package/dist/utils/resolve-bin.d.ts +56 -6
  81. package/dist/utils/resolve-bin.js +136 -26
  82. package/dist/utils/update-notifier.js +5 -7
  83. package/gitleaks.toml +14 -0
  84. package/install-manifests/go/package-lock.json +24 -0
  85. package/install-manifests/go/package.json +8 -0
  86. package/install-manifests/pytypes/package-lock.json +45 -0
  87. package/install-manifests/pytypes/package.json +8 -0
  88. package/package.json +4 -2
  89. package/pr-checkmate.schema.json +8 -2
  90. package/src/config/cspell.json +155 -133
  91. package/src/config/pr-checkmate.schema.json +8 -2
  92. package/dist/core/checks/languages/csharp-format.d.ts +0 -13
  93. package/dist/core/checks/languages/csharp-format.js +0 -52
  94. package/dist/core/checks/languages/go-lint.d.ts +0 -8
  95. package/dist/core/checks/languages/go-lint.js +0 -48
  96. package/dist/core/checks/languages/kotlin-lint.d.ts +0 -2
  97. package/dist/core/checks/languages/kotlin-lint.js +0 -42
  98. package/dist/core/checks/languages/php-format.d.ts +0 -9
  99. package/dist/core/checks/languages/php-format.js +0 -49
  100. package/dist/core/checks/languages/ruby-lint.d.ts +0 -8
  101. package/dist/core/checks/languages/ruby-lint.js +0 -50
  102. package/dist/core/checks/languages/rust-format.d.ts +0 -9
  103. package/dist/core/checks/languages/rust-format.js +0 -45
  104. package/dist/core/checks/languages/rust-lint.d.ts +0 -8
  105. package/dist/core/checks/languages/rust-lint.js +0 -50
  106. package/dist/core/checks/languages/shellcheck.d.ts +0 -8
  107. package/dist/core/checks/languages/shellcheck.js +0 -55
  108. package/dist/core/checks/languages/swift-lint.d.ts +0 -2
  109. package/dist/core/checks/languages/swift-lint.js +0 -46
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.packageVersion = packageVersion;
7
+ exports.packageName = packageName;
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ /**
11
+ * Our own name and version, read from the manifest that ships inside the package.
12
+ *
13
+ * Read from disk rather than baked in at build time so it is the *running* copy
14
+ * that answers. That distinction is the whole point: a stale global install
15
+ * (`npm i -g pr-checkmate`) shadows the project's own copy on `PATH`, and a repo
16
+ * pinned to the latest version can still be checked by a year-old binary without
17
+ * anything in the log saying so. One client spent a while reading an upgrade
18
+ * notice for a version they had already installed, because nothing printed which
19
+ * version was speaking.
20
+ *
21
+ * Falls back to placeholders rather than throwing: no caller here is important
22
+ * enough to fail a run over a manifest it could not read.
23
+ */
24
+ function readManifest() {
25
+ try {
26
+ const manifest = node_path_1.default.resolve(__dirname, '../..', 'package.json');
27
+ const parsed = JSON.parse(node_fs_1.default.readFileSync(manifest, 'utf-8'));
28
+ return { name: parsed.name ?? 'pr-checkmate', version: parsed.version ?? '0.0.0' };
29
+ }
30
+ catch {
31
+ return { name: 'pr-checkmate', version: '0.0.0' };
32
+ }
33
+ }
34
+ /** The version of pr-checkmate that is executing right now. */
35
+ function packageVersion() {
36
+ return readManifest().version;
37
+ }
38
+ /** The package name that is executing right now — the one to query npm for. */
39
+ function packageName() {
40
+ return readManifest().name;
41
+ }
@@ -1,16 +1,66 @@
1
+ /** Where a tool was found, in the order the candidates are tried. */
2
+ export type ToolSource = 'client' | 'profile' | 'bundled';
3
+ /** A resolved tool binary, and which copy of it answered. */
4
+ export interface ResolvedTool {
5
+ bin: string;
6
+ source: ToolSource;
7
+ /** The search root that produced it; `undefined` for module-relative resolution. */
8
+ root?: string;
9
+ }
10
+ /**
11
+ * Point tool resolution at the profile directories fetched for this run.
12
+ *
13
+ * Called by the install layer once the cache is known. Passing an empty list —
14
+ * or never calling it at all — leaves resolution exactly as it was before
15
+ * profiles existed, which is what keeps a run that needs no fetching identical
16
+ * to a run from before there was anything to fetch.
17
+ */
18
+ export declare function registerToolPaths(dirs: string[]): void;
19
+ /** Drop every registered profile root. For tests, and for a second run in-process. */
20
+ export declare function clearToolPaths(): void;
21
+ /** The root of the installed pr-checkmate package — where our own tooling lives. */
22
+ export declare function ownPackageRoot(): string;
23
+ /**
24
+ * Whether a package is physically present in our own dependency tree.
25
+ *
26
+ * Checked by walking `node_modules` upwards rather than by `require.resolve`,
27
+ * because a package that restricts its `exports` map resolves for neither its
28
+ * main entry nor its `package.json` while being perfectly well installed —
29
+ * `cspell` is one. The question here is only "is it there", and the directory
30
+ * answers that without an opinion about what it chooses to export.
31
+ *
32
+ * Walking up matters as much as the check itself: installed as a dependency, our
33
+ * own packages are hoisted to the client's `node_modules`, one level above ours.
34
+ */
35
+ export declare function packagePresent(pkgName: string, from?: string): boolean;
36
+ /**
37
+ * Resolve a tool's binary and say which copy answered.
38
+ *
39
+ * Use this over {@link resolvePackageBin} when the answer is worth logging — the
40
+ * source is the difference between "the client's ESLint 8 ran" and "ours did",
41
+ * and that is the first thing anyone asks when a lint result looks wrong.
42
+ *
43
+ * @param pkgName Package whose binary to resolve (e.g. `eslint`).
44
+ * @param binRelPath Bin path relative to the package root (e.g. `bin/eslint.js`).
45
+ * @param options Resolution options.
46
+ * @param options.paths Roots to prefer ahead of everything else. Use
47
+ * `[process.cwd()]` to prefer the consumer project's copy.
48
+ */
49
+ export declare function resolveTool(pkgName: string, binRelPath: string, options?: {
50
+ paths?: string[];
51
+ }): ResolvedTool | null;
1
52
  /**
2
53
  * Resolves a binary path for a bundled package, bypassing exports map restrictions.
3
54
  *
4
- * Strategy (tries each in order):
5
- * 1. Direct subpath — fast path for packages that explicitly export their bin
6
- * 2. Via package.json — for packages that export ./package.json but not the bin subpath (e.g. eslint)
7
- * 3. Walk up from main entry — for packages that export neither (e.g. cspell)
55
+ * Throws when no copy can be found anywhere, which is the honest outcome: a check
56
+ * that cannot find its tool has nothing to report, and the install layer turns
57
+ * that into a skip with a reason rather than letting it surface as a stack trace.
8
58
  *
9
59
  * @param pkgName - The package whose binary to resolve (e.g. `eslint`).
10
60
  * @param binRelPath - The bin path relative to the package root (e.g. `bin/eslint.js`).
11
61
  * @param options - Resolution options.
12
- * @param options.paths - Directories to resolve from (passed to `require.resolve`).
13
- * Use `[process.cwd()]` to prefer the consumer project's copy of the package.
62
+ * @param options.paths - Directories to resolve from, preferred over everything
63
+ * else. Use `[process.cwd()]` to prefer the consumer project's copy.
14
64
  */
15
65
  export declare function resolvePackageBin(pkgName: string, binRelPath: string, options?: {
16
66
  paths?: string[];
@@ -3,51 +3,161 @@ 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.registerToolPaths = registerToolPaths;
7
+ exports.clearToolPaths = clearToolPaths;
8
+ exports.ownPackageRoot = ownPackageRoot;
9
+ exports.packagePresent = packagePresent;
10
+ exports.resolveTool = resolveTool;
6
11
  exports.resolvePackageBin = resolvePackageBin;
7
12
  const node_fs_1 = __importDefault(require("node:fs"));
8
13
  const node_path_1 = __importDefault(require("node:path"));
9
14
  /**
10
- * Resolves a binary path for a bundled package, bypassing exports map restrictions.
15
+ * Extra roots to search, registered once per run by the install layer.
11
16
  *
12
- * Strategy (tries each in order):
13
- * 1. Direct subpath — fast path for packages that explicitly export their bin
14
- * 2. Via package.json — for packages that export ./package.json but not the bin subpath (e.g. eslint)
15
- * 3. Walk up from main entry — for packages that export neither (e.g. cspell)
17
+ * Module state rather than a parameter threaded through fifteen call sites: a
18
+ * profile directory is a property of the *run*, not of any one check, and every
19
+ * check that resolves a binary would otherwise have to be handed a value it has
20
+ * no opinion about. `registerToolPaths` is called before the first check starts
21
+ * and never during one, so nothing observes it changing underneath.
22
+ */
23
+ let profileRoots = [];
24
+ /**
25
+ * Point tool resolution at the profile directories fetched for this run.
16
26
  *
17
- * @param pkgName - The package whose binary to resolve (e.g. `eslint`).
18
- * @param binRelPath - The bin path relative to the package root (e.g. `bin/eslint.js`).
19
- * @param options - Resolution options.
20
- * @param options.paths - Directories to resolve from (passed to `require.resolve`).
21
- * Use `[process.cwd()]` to prefer the consumer project's copy of the package.
27
+ * Called by the install layer once the cache is known. Passing an empty list —
28
+ * or never calling it at all — leaves resolution exactly as it was before
29
+ * profiles existed, which is what keeps a run that needs no fetching identical
30
+ * to a run from before there was anything to fetch.
22
31
  */
23
- function resolvePackageBin(pkgName, binRelPath, options) {
24
- const resolveOpts = options?.paths ? { paths: options.paths } : undefined;
25
- // 1. Direct subpath
32
+ function registerToolPaths(dirs) {
33
+ profileRoots = [...dirs];
34
+ }
35
+ /** Drop every registered profile root. For tests, and for a second run in-process. */
36
+ function clearToolPaths() {
37
+ profileRoots = [];
38
+ }
39
+ /** The root of the installed pr-checkmate package — where our own tooling lives. */
40
+ function ownPackageRoot() {
41
+ return node_path_1.default.resolve(__dirname, '../..');
42
+ }
43
+ /**
44
+ * Whether a package is physically present in our own dependency tree.
45
+ *
46
+ * Checked by walking `node_modules` upwards rather than by `require.resolve`,
47
+ * because a package that restricts its `exports` map resolves for neither its
48
+ * main entry nor its `package.json` while being perfectly well installed —
49
+ * `cspell` is one. The question here is only "is it there", and the directory
50
+ * answers that without an opinion about what it chooses to export.
51
+ *
52
+ * Walking up matters as much as the check itself: installed as a dependency, our
53
+ * own packages are hoisted to the client's `node_modules`, one level above ours.
54
+ */
55
+ function packagePresent(pkgName, from = ownPackageRoot()) {
56
+ let dir = from;
57
+ while (dir !== node_path_1.default.dirname(dir)) {
58
+ if (node_fs_1.default.existsSync(node_path_1.default.join(dir, 'node_modules', pkgName, 'package.json')))
59
+ return true;
60
+ dir = node_path_1.default.dirname(dir);
61
+ }
62
+ return false;
63
+ }
64
+ /** One resolution attempt against a single set of search paths. */
65
+ function tryResolve(pkgName, binRelPath, paths) {
66
+ const resolveOpts = paths ? { paths } : undefined;
67
+ // 1. Direct subpath — the fast path for packages that export their bin.
26
68
  try {
27
69
  return require.resolve(`${pkgName}/${binRelPath}`, resolveOpts);
28
70
  }
29
71
  catch { }
30
- // 2. Via package.json
72
+ // 2. Via package.json — for packages that export `./package.json` but not the
73
+ // bin subpath (eslint).
31
74
  try {
32
75
  const pkgJsonPath = require.resolve(`${pkgName}/package.json`, resolveOpts);
33
76
  return node_path_1.default.join(node_path_1.default.dirname(pkgJsonPath), binRelPath);
34
77
  }
35
78
  catch { }
36
- // 3. Walk up from main entry to find package root by matching package name
37
- const main = require.resolve(pkgName, resolveOpts);
38
- let dir = node_path_1.default.dirname(main);
39
- while (dir !== node_path_1.default.dirname(dir)) {
40
- const pkgJsonPath = node_path_1.default.join(dir, 'package.json');
41
- if (node_fs_1.default.existsSync(pkgJsonPath)) {
42
- try {
43
- const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
44
- if (pkg.name === pkgName) {
45
- return node_path_1.default.join(dir, binRelPath);
79
+ // 3. Walk up from the main entry, matching the package name — for packages
80
+ // that export neither (cspell).
81
+ try {
82
+ let dir = node_path_1.default.dirname(require.resolve(pkgName, resolveOpts));
83
+ while (dir !== node_path_1.default.dirname(dir)) {
84
+ const pkgJsonPath = node_path_1.default.join(dir, 'package.json');
85
+ if (node_fs_1.default.existsSync(pkgJsonPath)) {
86
+ try {
87
+ const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgJsonPath, 'utf-8'));
88
+ if (pkg.name === pkgName)
89
+ return node_path_1.default.join(dir, binRelPath);
46
90
  }
91
+ catch { }
47
92
  }
48
- catch { }
93
+ dir = node_path_1.default.dirname(dir);
49
94
  }
50
- dir = node_path_1.default.dirname(dir);
51
95
  }
96
+ catch { }
97
+ return null;
98
+ }
99
+ /**
100
+ * The roots to try, in order, and what finding a tool in each one means.
101
+ *
102
+ * The order is the policy, and it is deliberate:
103
+ *
104
+ * 1. **The client's own copy**, when a caller asked for it. A repository pinned
105
+ * to ESLint 8 with a legacy `.eslintrc` must keep working, and only its copy
106
+ * can do that.
107
+ * 2. **A fetched profile**, for tooling that does not ship inside the package.
108
+ * 3. **Our bundle** — module-relative, exactly as resolution worked before
109
+ * profiles existed.
110
+ *
111
+ * Branch 3 is passed `undefined` rather than our package root on purpose: that is
112
+ * literally the previous behaviour, so a run with nothing registered resolves
113
+ * every tool along the identical path it always did.
114
+ */
115
+ function candidates(optPaths) {
116
+ const list = [];
117
+ if (optPaths && optPaths.length > 0)
118
+ list.push({ paths: optPaths, source: 'client' });
119
+ for (const root of profileRoots)
120
+ list.push({ paths: [root], source: 'profile' });
121
+ list.push({ source: 'bundled' });
122
+ return list;
123
+ }
124
+ /**
125
+ * Resolve a tool's binary and say which copy answered.
126
+ *
127
+ * Use this over {@link resolvePackageBin} when the answer is worth logging — the
128
+ * source is the difference between "the client's ESLint 8 ran" and "ours did",
129
+ * and that is the first thing anyone asks when a lint result looks wrong.
130
+ *
131
+ * @param pkgName Package whose binary to resolve (e.g. `eslint`).
132
+ * @param binRelPath Bin path relative to the package root (e.g. `bin/eslint.js`).
133
+ * @param options Resolution options.
134
+ * @param options.paths Roots to prefer ahead of everything else. Use
135
+ * `[process.cwd()]` to prefer the consumer project's copy.
136
+ */
137
+ function resolveTool(pkgName, binRelPath, options) {
138
+ for (const candidate of candidates(options?.paths)) {
139
+ const bin = tryResolve(pkgName, binRelPath, candidate.paths);
140
+ if (bin)
141
+ return { bin, source: candidate.source, root: candidate.paths?.[0] };
142
+ }
143
+ return null;
144
+ }
145
+ /**
146
+ * Resolves a binary path for a bundled package, bypassing exports map restrictions.
147
+ *
148
+ * Throws when no copy can be found anywhere, which is the honest outcome: a check
149
+ * that cannot find its tool has nothing to report, and the install layer turns
150
+ * that into a skip with a reason rather than letting it surface as a stack trace.
151
+ *
152
+ * @param pkgName - The package whose binary to resolve (e.g. `eslint`).
153
+ * @param binRelPath - The bin path relative to the package root (e.g. `bin/eslint.js`).
154
+ * @param options - Resolution options.
155
+ * @param options.paths - Directories to resolve from, preferred over everything
156
+ * else. Use `[process.cwd()]` to prefer the consumer project's copy.
157
+ */
158
+ function resolvePackageBin(pkgName, binRelPath, options) {
159
+ const resolved = resolveTool(pkgName, binRelPath, options);
160
+ if (resolved)
161
+ return resolved.bin;
52
162
  throw new Error(`Cannot resolve binary "${binRelPath}" for package "${pkgName}"`);
53
163
  }
@@ -1,16 +1,12 @@
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.isMajorUpgrade = isMajorUpgrade;
7
4
  exports.getUpdateNotice = getUpdateNotice;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
5
  // Imported from the module rather than the `../config` barrel on purpose:
11
6
  // `config/index.ts` imports `../utils`, so going through the barrel would make
12
7
  // utils ⇄ config circular. `constants.ts` itself pulls in nothing from utils.
13
8
  const constants_1 = require("../config/constants");
9
+ const package_version_1 = require("./package-version");
14
10
  // Same widths as the run summary in `reporters.ts`, so the two boxes line up
15
11
  // when both are printed at the end of a run.
16
12
  const NOTICE_BORDER = '═'.repeat(63);
@@ -72,8 +68,10 @@ async function getUpdateNotice(timeoutMs = 2500) {
72
68
  if (process.env.PR_CHECKMATE_NO_UPDATE_CHECK)
73
69
  return null;
74
70
  try {
75
- const pkgPath = node_path_1.default.resolve(__dirname, '../..', 'package.json');
76
- const pkg = JSON.parse(node_fs_1.default.readFileSync(pkgPath, 'utf-8'));
71
+ // The *running* copy's identity, not the project's declared dependency. A
72
+ // stale global install shadows the local one on `PATH`, and it is the stale
73
+ // copy that must own the notice it prints.
74
+ const pkg = { name: (0, package_version_1.packageName)(), version: (0, package_version_1.packageVersion)() };
77
75
  const controller = new AbortController();
78
76
  const timer = setTimeout(() => controller.abort(), timeoutMs);
79
77
  let latest;
package/gitleaks.toml CHANGED
@@ -3,6 +3,20 @@ title = "pr-checkmate gitleaks config"
3
3
  [extend]
4
4
  useDefault = true
5
5
 
6
+ # THIS FILE SHIPS, AND IT IS APPLIED TO EVERY CLIENT WITHOUT A GITLEAKS CONFIG OF
7
+ # THEIR OWN. Read `src/core/checks/security/security.ts`: `--config` points here
8
+ # whenever `hasLocalConfig` finds nothing in the repository being scanned.
9
+ #
10
+ # So an entry added here to quieten OUR OWN corpus silences it for everybody. That
11
+ # was measured, not imagined: adding `tests/` to the paths below removed six real
12
+ # `Generic API Key` findings from a client repository — under
13
+ # `packages/commons/tests/`, `packages/node/tests/`, and three more — in a check
14
+ # that BLOCKS. Our own noise is never a reason to widen this list; use
15
+ # `.gitleaksignore` in this repository instead, which does not ship.
16
+ #
17
+ # `__tests__` predates that and is left alone: it is a convention for a directory
18
+ # of test files specifically, not a whole path segment named `test`.
19
+
6
20
  [allowlist]
7
21
  description = "pr-checkmate global allowlist"
8
22
  paths = [
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "pr-checkmate-profile-go",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "pr-checkmate-profile-go",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "@wasm-fmt/gofmt": "0.7.3"
12
+ }
13
+ },
14
+ "node_modules/@wasm-fmt/gofmt": {
15
+ "version": "0.7.3",
16
+ "resolved": "https://registry.npmjs.org/@wasm-fmt/gofmt/-/gofmt-0.7.3.tgz",
17
+ "integrity": "sha512-nzVTwMxHDOYrHonT7DzjqicbaTYOYPNYeXKPJnDrVUbJjx67Sg/LS1uzlOTWKToGMF8Y8l0u7G5/5Q3/8nHMMA==",
18
+ "license": "MIT",
19
+ "engines": {
20
+ "node": ">=16.17.0"
21
+ }
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "pr-checkmate-profile-go",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "@wasm-fmt/gofmt": "0.7.3"
6
+ },
7
+ "private": true
8
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "pr-checkmate-profile-pytypes",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "pr-checkmate-profile-pytypes",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "pyright": "1.1.413"
12
+ }
13
+ },
14
+ "node_modules/fsevents": {
15
+ "version": "2.3.3",
16
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
17
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
18
+ "hasInstallScript": true,
19
+ "license": "MIT",
20
+ "optional": true,
21
+ "os": [
22
+ "darwin"
23
+ ],
24
+ "engines": {
25
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
26
+ }
27
+ },
28
+ "node_modules/pyright": {
29
+ "version": "1.1.413",
30
+ "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.413.tgz",
31
+ "integrity": "sha512-1lpxKrh0DHHpfAQOfciZo2ojua2jase3wwO9at8kldc+F/p1PBscxA5CQ3G1qg5lMOMhXo6ZaiMLMXEAqADIAg==",
32
+ "license": "MIT",
33
+ "bin": {
34
+ "pyright": "index.js",
35
+ "pyright-langserver": "langserver.index.js"
36
+ },
37
+ "engines": {
38
+ "node": ">=14.0.0"
39
+ },
40
+ "optionalDependencies": {
41
+ "fsevents": "~2.3.3"
42
+ }
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "pr-checkmate-profile-pytypes",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "pyright": "1.1.413"
6
+ },
7
+ "private": true
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-checkmate",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "description": "Security-first PR gate for CI: secret scanning, grype dependency scanning, SBOM — plus linting and formatting across 11 languages",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -52,7 +52,7 @@
52
52
  "spellcheck": "cspell '**/*.{ts,tsx,js,jsx,md,json}' --no-progress",
53
53
  "docs": "typedoc",
54
54
  "scan:secrets": "gitleaks-secret-scanner --diff-mode ci --html-report gitleaks-report.html",
55
- "test": "node --require ts-node/register --test --test-timeout=60000 --test-concurrency=1 \"tests/**/*.test.ts\"",
55
+ "test": "node --require ts-node/register --test --test-timeout=60000 \"tests/**/*.test.ts\"",
56
56
  "test:ci": "bash scripts/test-per-file.sh",
57
57
  "verify:tarball": "bash scripts/verify-tarball.sh",
58
58
  "security-scan": "npx pr-checkmate security",
@@ -82,6 +82,7 @@
82
82
  "@typescript-eslint/eslint-plugin": "^8.62.1",
83
83
  "@typescript-eslint/parser": "^8.62.1",
84
84
  "@wasm-fmt/clang-format": "^22.1.8",
85
+ "@wasm-fmt/gofmt": "^0.7.3",
85
86
  "cspell": "^10.0.1",
86
87
  "dpdm": "^4.2.0",
87
88
  "eslint": "^10.6.0",
@@ -106,6 +107,7 @@
106
107
  "devDependencies": {
107
108
  "conventional-commits-filter": "^5.0.0",
108
109
  "conventional-commits-parser": "^6.4.0",
110
+ "pyright": "^1.1.413",
109
111
  "standard-version": "^9.5.0",
110
112
  "typedoc": "^0.28.20"
111
113
  },
@@ -727,7 +727,7 @@
727
727
  "default": 1
728
728
  },
729
729
  "reuseLocal": {
730
- "description": "Reuse a tool already in the client's node_modules: \"compatible\" (default), \"always\", or \"off\".",
730
+ "description": "Reuse a tool already present in the repository's node_modules instead of our copy. \"compatible\" (default) reuses 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 that wrote it, and a tsconfig by its own compiler). \"always\" reuses across a major gap at your own risk. \"off\" always uses our pinned copy, for reproducibility.",
731
731
  "type": "string",
732
732
  "enum": ["compatible", "always", "off"],
733
733
  "default": "compatible"
@@ -761,7 +761,7 @@
761
761
  "default": "~/.cache/pr-checkmate"
762
762
  },
763
763
  "prewarm": {
764
- "description": "Warm the cache in postinstall. false leaves everything to the lazy path.",
764
+ "description": "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; the hook lands with the dependency extraction (ticket 064, release 2). Documented as inert rather than quietly doing nothing.",
765
765
  "type": "boolean",
766
766
  "default": true
767
767
  },
@@ -1174,6 +1174,12 @@
1174
1174
  }
1175
1175
  }
1176
1176
  }
1177
+ },
1178
+ "dataflowWindow": {
1179
+ "type": "integer",
1180
+ "minimum": 0,
1181
+ "default": 10,
1182
+ "description": "Added lines a value stays tainted for, connecting an interpolated string assigned on one line to a query on a later line. 0 disables the cross-line heuristic. Advisory only — it has no scopes and no reassignment tracking, so it never blocks a run."
1177
1183
  }
1178
1184
  }
1179
1185
  },