pr-checkmate 1.22.8 → 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.
- package/README.md +101 -333
- package/cspell.json +9 -1
- package/dist/cli.js +32 -2
- package/dist/config/constants.d.ts +9 -0
- package/dist/config/constants.js +68 -1
- package/dist/core/checks/dependencies/banned-imports.d.ts +2 -0
- package/dist/core/checks/dependencies/banned-imports.js +71 -0
- package/dist/core/checks/{circular-deps.d.ts → dependencies/circular-deps.d.ts} +1 -1
- package/dist/core/checks/{circular-deps.js → dependencies/circular-deps.js} +5 -5
- package/dist/core/checks/{dependency-check.d.ts → dependencies/dependency-check.d.ts} +1 -1
- package/dist/core/checks/{dependency-check.js → dependencies/dependency-check.js} +3 -3
- package/dist/core/checks/{license-check.d.ts → dependencies/license-check.d.ts} +1 -1
- package/dist/core/checks/{license-check.js → dependencies/license-check.js} +3 -3
- package/dist/core/checks/{npm-audit.d.ts → dependencies/npm-audit.d.ts} +1 -1
- package/dist/core/checks/{npm-audit.js → dependencies/npm-audit.js} +3 -3
- package/dist/core/checks/{outdated-deps.d.ts → dependencies/outdated-deps.d.ts} +1 -1
- package/dist/core/checks/{outdated-deps.js → dependencies/outdated-deps.js} +3 -3
- package/dist/core/checks/dependencies/vuln-scan.d.ts +9 -0
- package/dist/core/checks/dependencies/vuln-scan.js +41 -0
- package/dist/core/checks/findings.d.ts +37 -1
- package/dist/core/checks/findings.js +80 -3
- package/dist/core/checks/git/custom-rules.d.ts +2 -0
- package/dist/core/checks/git/custom-rules.js +102 -0
- package/dist/core/checks/{diff-smell.d.ts → git/diff-smell.d.ts} +1 -1
- package/dist/core/checks/{diff-smell.js → git/diff-smell.js} +3 -3
- package/dist/core/checks/git/large-files.d.ts +2 -0
- package/dist/core/checks/git/large-files.js +83 -0
- package/dist/core/checks/git/leftover-debug.d.ts +2 -0
- package/dist/core/checks/git/leftover-debug.js +77 -0
- package/dist/core/checks/git/lockfile-drift.d.ts +2 -0
- package/dist/core/checks/git/lockfile-drift.js +114 -0
- package/dist/core/checks/git/merge-conflict.d.ts +2 -0
- package/dist/core/checks/git/merge-conflict.js +109 -0
- package/dist/core/checks/git/missing-tests.d.ts +2 -0
- package/dist/core/checks/git/missing-tests.js +92 -0
- package/dist/core/checks/git/todo-fixme.d.ts +7 -0
- package/dist/core/checks/git/todo-fixme.js +74 -0
- package/dist/core/checks/{cpp-format.d.ts → languages/cpp-format.d.ts} +1 -1
- package/dist/core/checks/{cpp-format.js → languages/cpp-format.js} +3 -3
- package/dist/core/checks/languages/csharp-format.d.ts +13 -0
- package/dist/core/checks/languages/csharp-format.js +52 -0
- package/dist/core/checks/languages/go-format.d.ts +8 -0
- package/dist/core/checks/languages/go-format.js +48 -0
- package/dist/core/checks/languages/go-lint.d.ts +8 -0
- package/dist/core/checks/languages/go-lint.js +48 -0
- package/dist/core/checks/{kotlin-lint.d.ts → languages/kotlin-lint.d.ts} +1 -1
- package/dist/core/checks/{kotlin-lint.js → languages/kotlin-lint.js} +13 -17
- package/dist/core/checks/{lint.d.ts → languages/lint.d.ts} +1 -1
- package/dist/core/checks/{lint.js → languages/lint.js} +5 -5
- package/dist/core/checks/languages/php-format.d.ts +9 -0
- package/dist/core/checks/languages/php-format.js +49 -0
- package/dist/core/checks/{prettier.d.ts → languages/prettier.d.ts} +1 -1
- package/dist/core/checks/{prettier.js → languages/prettier.js} +5 -5
- package/dist/core/checks/{python-format.d.ts → languages/python-format.d.ts} +1 -1
- package/dist/core/checks/{python-format.js → languages/python-format.js} +3 -3
- package/dist/core/checks/{python-lint.d.ts → languages/python-lint.d.ts} +1 -1
- package/dist/core/checks/{python-lint.js → languages/python-lint.js} +3 -3
- package/dist/core/checks/languages/python-typecheck.d.ts +9 -0
- package/dist/core/checks/languages/python-typecheck.js +66 -0
- package/dist/core/checks/languages/ruby-lint.d.ts +8 -0
- package/dist/core/checks/languages/ruby-lint.js +50 -0
- package/dist/core/checks/languages/rust-format.d.ts +9 -0
- package/dist/core/checks/languages/rust-format.js +45 -0
- package/dist/core/checks/languages/rust-lint.d.ts +8 -0
- package/dist/core/checks/languages/rust-lint.js +50 -0
- package/dist/core/checks/{swift-lint.d.ts → languages/swift-lint.d.ts} +1 -1
- package/dist/core/checks/{swift-lint.js → languages/swift-lint.js} +13 -17
- package/dist/core/checks/{typecheck.d.ts → languages/typecheck.d.ts} +1 -1
- package/dist/core/checks/{typecheck.js → languages/typecheck.js} +3 -3
- package/dist/core/checks/{commitlint.d.ts → pr/commitlint.d.ts} +1 -1
- package/dist/core/checks/{commitlint.js → pr/commitlint.js} +4 -4
- package/dist/core/checks/{pr-body.d.ts → pr/pr-body.d.ts} +1 -1
- package/dist/core/checks/{pr-body.js → pr/pr-body.js} +2 -2
- package/dist/core/checks/{pr-size-check.d.ts → pr/pr-size-check.d.ts} +1 -1
- package/dist/core/checks/{pr-size-check.js → pr/pr-size-check.js} +13 -11
- package/dist/core/checks/{pr-title-lint.d.ts → pr/pr-title-lint.d.ts} +1 -1
- package/dist/core/checks/{pr-title-lint.js → pr/pr-title-lint.js} +2 -2
- package/dist/core/checks/quality/case-collision.d.ts +8 -0
- package/dist/core/checks/quality/case-collision.js +40 -0
- package/dist/core/checks/quality/config-validation.d.ts +8 -0
- package/dist/core/checks/quality/config-validation.js +63 -0
- package/dist/core/checks/quality/coverage.d.ts +2 -0
- package/dist/core/checks/quality/coverage.js +63 -0
- package/dist/core/checks/{dead-code.d.ts → quality/dead-code.d.ts} +1 -1
- package/dist/core/checks/{dead-code.js → quality/dead-code.js} +4 -4
- package/dist/core/checks/{duplicate-check.d.ts → quality/duplicate-check.d.ts} +1 -1
- package/dist/core/checks/{duplicate-check.js → quality/duplicate-check.js} +6 -6
- package/dist/core/checks/quality/license-header.d.ts +7 -0
- package/dist/core/checks/quality/license-header.js +74 -0
- package/dist/core/checks/{markdown-lint.d.ts → quality/markdown-lint.d.ts} +1 -1
- package/dist/core/checks/{markdown-lint.js → quality/markdown-lint.js} +5 -5
- package/dist/core/checks/{spellcheck.d.ts → quality/spellcheck.d.ts} +1 -1
- package/dist/core/checks/{spellcheck.js → quality/spellcheck.js} +5 -5
- package/dist/core/checks/{diff-security.d.ts → security/diff-security.d.ts} +1 -1
- package/dist/core/checks/security/diff-security.js +262 -0
- package/dist/core/checks/security/dockerfile-security.d.ts +2 -0
- package/dist/core/checks/security/dockerfile-security.js +92 -0
- package/dist/core/checks/security/migration-safety.d.ts +2 -0
- package/dist/core/checks/security/migration-safety.js +110 -0
- package/dist/core/checks/{security.d.ts → security/security.d.ts} +1 -1
- package/dist/core/checks/{security.js → security/security.js} +4 -4
- package/dist/core/checks/{sensitive-file-guard.d.ts → security/sensitive-file-guard.d.ts} +1 -1
- package/dist/core/checks/{sensitive-file-guard.js → security/sensitive-file-guard.js} +4 -4
- package/dist/core/checks/security/workflow-security.d.ts +2 -0
- package/dist/core/checks/security/workflow-security.js +75 -0
- package/dist/core/context.js +14 -0
- package/dist/core/registry.js +73 -28
- package/dist/core/reporters.d.ts +4 -3
- package/dist/core/reporters.js +104 -4
- package/dist/core/run-checks.js +21 -3
- package/dist/core/targets.d.ts +4 -1
- package/dist/core/targets.js +16 -3
- package/dist/core/types.d.ts +13 -1
- package/dist/init.js +63 -0
- package/dist/interfaces/index.d.ts +99 -0
- package/dist/scripts/copy-configs.js +1 -0
- package/dist/utils/detect-language.d.ts +1 -1
- package/dist/utils/detect-language.js +32 -3
- package/dist/utils/glob.d.ts +10 -0
- package/dist/utils/glob.js +25 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +2 -1
- package/pr-checkmate.schema.json +166 -0
- package/src/config/cspell.json +9 -1
- package/src/config/pr-checkmate.schema.json +166 -0
- package/dist/core/checks/diff-security.js +0 -145
- /package/dist/core/checks/{ruff-shared.d.ts → languages/ruff-shared.d.ts} +0 -0
- /package/dist/core/checks/{ruff-shared.js → languages/ruff-shared.js} +0 -0
|
@@ -7,6 +7,7 @@ exports.detectLanguages = detectLanguages;
|
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const execa_1 = require("./execa");
|
|
10
|
+
const glob_1 = require("./glob");
|
|
10
11
|
const logger_1 = require("./logger");
|
|
11
12
|
/**
|
|
12
13
|
* Marker files that unambiguously indicate a language's presence, independent of
|
|
@@ -26,6 +27,13 @@ const MARKER_FILES = {
|
|
|
26
27
|
'settings.gradle.kts',
|
|
27
28
|
'AndroidManifest.xml',
|
|
28
29
|
],
|
|
30
|
+
go: ['go.mod'],
|
|
31
|
+
rust: ['Cargo.toml'],
|
|
32
|
+
// Glob markers (`*.csproj`/`*.sln`) — matched against root dir entries, since
|
|
33
|
+
// C# projects have no single fixed marker filename.
|
|
34
|
+
csharp: ['*.csproj', '*.sln'],
|
|
35
|
+
ruby: ['Gemfile', '.rubocop.yml'],
|
|
36
|
+
php: ['composer.json'],
|
|
29
37
|
};
|
|
30
38
|
/**
|
|
31
39
|
* Source extensions per language, used to count tracked files via `git ls-files`.
|
|
@@ -37,9 +45,25 @@ const EXTENSIONS = {
|
|
|
37
45
|
cpp: ['.cpp', '.cc', '.cxx', '.c++', '.hpp', '.hh', '.hxx'],
|
|
38
46
|
swift: ['.swift'],
|
|
39
47
|
kotlin: ['.kt', '.kts', '.java'],
|
|
48
|
+
go: ['.go'],
|
|
49
|
+
rust: ['.rs'],
|
|
50
|
+
csharp: ['.cs'],
|
|
51
|
+
ruby: ['.rb', '.rake'],
|
|
52
|
+
php: ['.php'],
|
|
40
53
|
};
|
|
41
54
|
function hasMarker(root, lang) {
|
|
42
|
-
return MARKER_FILES[lang].some(name =>
|
|
55
|
+
return MARKER_FILES[lang].some(name => {
|
|
56
|
+
if (!name.includes('*'))
|
|
57
|
+
return node_fs_1.default.existsSync(node_path_1.default.join(root, name));
|
|
58
|
+
// Glob marker (e.g. `*.csproj`): match against root-directory entries.
|
|
59
|
+
try {
|
|
60
|
+
const re = (0, glob_1.globToRegExp)(name);
|
|
61
|
+
return node_fs_1.default.readdirSync(root).some(entry => re.test(entry));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
43
67
|
}
|
|
44
68
|
/**
|
|
45
69
|
* Counts tracked files per language using `git ls-files`. Returns an empty map
|
|
@@ -54,6 +78,11 @@ async function countTrackedFiles(root) {
|
|
|
54
78
|
cpp: 0,
|
|
55
79
|
swift: 0,
|
|
56
80
|
kotlin: 0,
|
|
81
|
+
go: 0,
|
|
82
|
+
rust: 0,
|
|
83
|
+
csharp: 0,
|
|
84
|
+
ruby: 0,
|
|
85
|
+
php: 0,
|
|
57
86
|
};
|
|
58
87
|
try {
|
|
59
88
|
const { stdout } = await (0, execa_1.execa)('git', ['ls-files'], { cwd: root });
|
|
@@ -87,7 +116,7 @@ async function detectLanguages(root = process.cwd()) {
|
|
|
87
116
|
const counts = await countTrackedFiles(root);
|
|
88
117
|
const detected = Object.keys(EXTENSIONS).filter(lang => hasMarker(root, lang) || counts[lang] > 0);
|
|
89
118
|
detected.sort((a, b) => counts[b] - counts[a]);
|
|
90
|
-
|
|
91
|
-
|
|
119
|
+
const countStr = Object.keys(counts).map(l => `${l}=${counts[l]}`).join(', ');
|
|
120
|
+
logger_1.logger.info(`[detectLanguages]: Detected ${detected.length ? detected.join(', ') : 'none'} (counts: ${countStr})`);
|
|
92
121
|
return detected;
|
|
93
122
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal glob → RegExp for path matching against config patterns. Supports `*`
|
|
3
|
+
* (matches within a path segment), `**` (across segments), and a leading `** /`
|
|
4
|
+
* that also matches the repo root (zero segments). Anchored to the whole path.
|
|
5
|
+
* Not a full glob implementation — enough for the allow/ignore lists in
|
|
6
|
+
* pr-checkmate.json (e.g. "assets/**", "*.png", "** / *.d.ts").
|
|
7
|
+
*/
|
|
8
|
+
export declare function globToRegExp(glob: string): RegExp;
|
|
9
|
+
/** True when `file` matches any of the glob `patterns`. */
|
|
10
|
+
export declare function matchesAnyGlob(file: string, patterns: string[]): boolean;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.globToRegExp = globToRegExp;
|
|
4
|
+
exports.matchesAnyGlob = matchesAnyGlob;
|
|
5
|
+
/**
|
|
6
|
+
* Minimal glob → RegExp for path matching against config patterns. Supports `*`
|
|
7
|
+
* (matches within a path segment), `**` (across segments), and a leading `** /`
|
|
8
|
+
* that also matches the repo root (zero segments). Anchored to the whole path.
|
|
9
|
+
* Not a full glob implementation — enough for the allow/ignore lists in
|
|
10
|
+
* pr-checkmate.json (e.g. "assets/**", "*.png", "** / *.d.ts").
|
|
11
|
+
*/
|
|
12
|
+
function globToRegExp(glob) {
|
|
13
|
+
const re = glob
|
|
14
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // escape regex specials (not * or /)
|
|
15
|
+
.replace(/\*\*\//g, ' dir ') // `**/` → optional leading dirs (matches root too)
|
|
16
|
+
.replace(/\*\*/g, ' any ') // bare `**` → across segments
|
|
17
|
+
.replace(/\*/g, '[^/]*') // `*` → within a segment
|
|
18
|
+
.replace(/ dir /g, '(?:.*/)?')
|
|
19
|
+
.replace(/ any /g, '.*');
|
|
20
|
+
return new RegExp(`^${re}$`);
|
|
21
|
+
}
|
|
22
|
+
/** True when `file` matches any of the glob `patterns`. */
|
|
23
|
+
function matchesAnyGlob(file, patterns) {
|
|
24
|
+
return patterns.some(p => globToRegExp(p).test(file));
|
|
25
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __exportStar(require("./result-collector"), exports);
|
|
|
25
25
|
__exportStar(require("./resolve-bin"), exports);
|
|
26
26
|
__exportStar(require("./own-deps"), exports);
|
|
27
27
|
__exportStar(require("./detect-language"), exports);
|
|
28
|
+
__exportStar(require("./glob"), exports);
|
|
28
29
|
/**
|
|
29
30
|
*
|
|
30
31
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-checkmate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
".prettierrc",
|
|
35
35
|
"cspell.json",
|
|
36
36
|
"src/config/pr-checkmate-workflow.yml",
|
|
37
|
+
"pr-checkmate.schema.json",
|
|
37
38
|
".markdownlint.json",
|
|
38
39
|
"gitleaks.toml",
|
|
39
40
|
"LICENSE"
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "PR CheckMate configuration",
|
|
4
|
+
"description": "Config for pr-checkmate. Unknown keys are reported by the Config Validation check.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": true,
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": { "type": "string" },
|
|
9
|
+
"sourcePath": {
|
|
10
|
+
"description": "Directory (or directories) checks are scoped to. Defaults to '.'.",
|
|
11
|
+
"oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
|
|
12
|
+
},
|
|
13
|
+
"ignoreDirs": {
|
|
14
|
+
"description": "Directory names excluded from every check.",
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": { "type": "string" }
|
|
17
|
+
},
|
|
18
|
+
"severity": {
|
|
19
|
+
"description": "Universal per-check severity override, keyed by the check's display name.",
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": { "enum": ["error", "warn", "off"] }
|
|
22
|
+
},
|
|
23
|
+
"customRules": {
|
|
24
|
+
"description": "User-defined regex rules run against the diff.",
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"required": ["name", "pattern"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"name": { "type": "string" },
|
|
31
|
+
"pattern": { "type": "string" },
|
|
32
|
+
"message": { "type": "string" },
|
|
33
|
+
"severity": { "enum": ["error", "warn"] },
|
|
34
|
+
"include": { "type": "array", "items": { "type": "string" } },
|
|
35
|
+
"exclude": { "type": "array", "items": { "type": "string" } },
|
|
36
|
+
"flags": { "type": "string" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"bannedImports": {
|
|
41
|
+
"description": "Dependencies/imports that must not be added.",
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"required": ["name"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"name": { "type": "string" },
|
|
48
|
+
"message": { "type": "string" },
|
|
49
|
+
"severity": { "enum": ["error", "warn"] }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"prSize": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"enabled": { "type": "boolean" },
|
|
57
|
+
"maxFiles": { "type": "number" },
|
|
58
|
+
"maxLines": { "type": "number" }
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"largeFiles": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {
|
|
64
|
+
"enabled": { "type": "boolean" },
|
|
65
|
+
"severity": { "enum": ["error", "warn"] },
|
|
66
|
+
"maxSizeKb": { "type": "number" },
|
|
67
|
+
"allow": { "type": "array", "items": { "type": "string" } }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"licenseHeader": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"properties": {
|
|
73
|
+
"enabled": { "type": "boolean" },
|
|
74
|
+
"pattern": { "type": "string" },
|
|
75
|
+
"lines": { "type": "number" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"coverage": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"enabled": { "type": "boolean" },
|
|
82
|
+
"severity": { "enum": ["error", "warn"] },
|
|
83
|
+
"reportPath": {
|
|
84
|
+
"oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"vulnScan": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": { "enabled": { "type": "boolean" } }
|
|
91
|
+
},
|
|
92
|
+
"mergeConflict": { "$ref": "#/$defs/toggleSeverity" },
|
|
93
|
+
"leftoverDebug": { "$ref": "#/$defs/toggleSeverity" },
|
|
94
|
+
"lockfileDrift": { "$ref": "#/$defs/toggleSeverity" },
|
|
95
|
+
"missingTests": { "$ref": "#/$defs/toggleSeverity" },
|
|
96
|
+
"diffSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
97
|
+
"workflowSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
98
|
+
"dockerfileSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
99
|
+
"migrationSafety": { "$ref": "#/$defs/toggleSeverity" },
|
|
100
|
+
"todoFixme": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"enabled": { "type": "boolean" },
|
|
104
|
+
"severity": { "enum": ["error", "warn"] },
|
|
105
|
+
"requireTicket": { "type": "boolean" },
|
|
106
|
+
"keywords": { "type": "array", "items": { "type": "string" } }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"diffSmell": { "$ref": "#/$defs/toggle" },
|
|
110
|
+
"caseCollision": { "$ref": "#/$defs/toggle" },
|
|
111
|
+
"sensitiveFileGuard": { "$ref": "#/$defs/toggle" },
|
|
112
|
+
"configValidation": { "$ref": "#/$defs/toggle" },
|
|
113
|
+
"typecheck": { "$ref": "#/$defs/toggle" },
|
|
114
|
+
"prBody": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"properties": {
|
|
117
|
+
"enabled": { "type": "boolean" },
|
|
118
|
+
"minLength": { "type": "number" },
|
|
119
|
+
"requireTicket": { "type": "boolean" }
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"cpp": { "$ref": "#/$defs/toggle" },
|
|
123
|
+
"python": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"properties": {
|
|
126
|
+
"enabled": { "type": "boolean" },
|
|
127
|
+
"typecheck": { "type": "boolean" },
|
|
128
|
+
"typeChecker": { "enum": ["mypy", "pyright"] },
|
|
129
|
+
"ruff": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"properties": {
|
|
132
|
+
"lint": { "type": "boolean" },
|
|
133
|
+
"format": { "type": "boolean" }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"swift": { "$ref": "#/$defs/toggle" },
|
|
139
|
+
"kotlin": { "$ref": "#/$defs/toggle" },
|
|
140
|
+
"go": { "$ref": "#/$defs/toggle" },
|
|
141
|
+
"rust": { "$ref": "#/$defs/toggle" },
|
|
142
|
+
"csharp": { "$ref": "#/$defs/toggle" },
|
|
143
|
+
"ruby": { "$ref": "#/$defs/toggle" },
|
|
144
|
+
"php": { "$ref": "#/$defs/toggle" }
|
|
145
|
+
},
|
|
146
|
+
"$defs": {
|
|
147
|
+
"toggle": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"properties": { "enabled": { "type": "boolean" } }
|
|
150
|
+
},
|
|
151
|
+
"toggleSeverity": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"enabled": { "type": "boolean" },
|
|
155
|
+
"severity": { "enum": ["error", "warn"] }
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"toggleIgnore": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"enabled": { "type": "boolean" },
|
|
162
|
+
"ignore": { "type": "array", "items": { "type": "string" } }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
package/src/config/cspell.json
CHANGED
|
@@ -693,7 +693,15 @@
|
|
|
693
693
|
"litert",
|
|
694
694
|
"SHTPB",
|
|
695
695
|
"FUTX",
|
|
696
|
-
"subdirs"
|
|
696
|
+
"subdirs",
|
|
697
|
+
"clippy",
|
|
698
|
+
"mypy",
|
|
699
|
+
"pyright",
|
|
700
|
+
"jacoco",
|
|
701
|
+
"depcheckrc",
|
|
702
|
+
"gofmt",
|
|
703
|
+
"dotnet",
|
|
704
|
+
"rubocop"
|
|
697
705
|
],
|
|
698
706
|
"ignorePaths": [
|
|
699
707
|
"**/node_modules/**",
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "PR CheckMate configuration",
|
|
4
|
+
"description": "Config for pr-checkmate. Unknown keys are reported by the Config Validation check.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": true,
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": { "type": "string" },
|
|
9
|
+
"sourcePath": {
|
|
10
|
+
"description": "Directory (or directories) checks are scoped to. Defaults to '.'.",
|
|
11
|
+
"oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
|
|
12
|
+
},
|
|
13
|
+
"ignoreDirs": {
|
|
14
|
+
"description": "Directory names excluded from every check.",
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": { "type": "string" }
|
|
17
|
+
},
|
|
18
|
+
"severity": {
|
|
19
|
+
"description": "Universal per-check severity override, keyed by the check's display name.",
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": { "enum": ["error", "warn", "off"] }
|
|
22
|
+
},
|
|
23
|
+
"customRules": {
|
|
24
|
+
"description": "User-defined regex rules run against the diff.",
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"required": ["name", "pattern"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"name": { "type": "string" },
|
|
31
|
+
"pattern": { "type": "string" },
|
|
32
|
+
"message": { "type": "string" },
|
|
33
|
+
"severity": { "enum": ["error", "warn"] },
|
|
34
|
+
"include": { "type": "array", "items": { "type": "string" } },
|
|
35
|
+
"exclude": { "type": "array", "items": { "type": "string" } },
|
|
36
|
+
"flags": { "type": "string" }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"bannedImports": {
|
|
41
|
+
"description": "Dependencies/imports that must not be added.",
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"required": ["name"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"name": { "type": "string" },
|
|
48
|
+
"message": { "type": "string" },
|
|
49
|
+
"severity": { "enum": ["error", "warn"] }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"prSize": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"enabled": { "type": "boolean" },
|
|
57
|
+
"maxFiles": { "type": "number" },
|
|
58
|
+
"maxLines": { "type": "number" }
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"largeFiles": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {
|
|
64
|
+
"enabled": { "type": "boolean" },
|
|
65
|
+
"severity": { "enum": ["error", "warn"] },
|
|
66
|
+
"maxSizeKb": { "type": "number" },
|
|
67
|
+
"allow": { "type": "array", "items": { "type": "string" } }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"licenseHeader": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"properties": {
|
|
73
|
+
"enabled": { "type": "boolean" },
|
|
74
|
+
"pattern": { "type": "string" },
|
|
75
|
+
"lines": { "type": "number" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"coverage": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"enabled": { "type": "boolean" },
|
|
82
|
+
"severity": { "enum": ["error", "warn"] },
|
|
83
|
+
"reportPath": {
|
|
84
|
+
"oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"vulnScan": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": { "enabled": { "type": "boolean" } }
|
|
91
|
+
},
|
|
92
|
+
"mergeConflict": { "$ref": "#/$defs/toggleSeverity" },
|
|
93
|
+
"leftoverDebug": { "$ref": "#/$defs/toggleSeverity" },
|
|
94
|
+
"lockfileDrift": { "$ref": "#/$defs/toggleSeverity" },
|
|
95
|
+
"missingTests": { "$ref": "#/$defs/toggleSeverity" },
|
|
96
|
+
"diffSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
97
|
+
"workflowSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
98
|
+
"dockerfileSecurity": { "$ref": "#/$defs/toggleIgnore" },
|
|
99
|
+
"migrationSafety": { "$ref": "#/$defs/toggleSeverity" },
|
|
100
|
+
"todoFixme": {
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"enabled": { "type": "boolean" },
|
|
104
|
+
"severity": { "enum": ["error", "warn"] },
|
|
105
|
+
"requireTicket": { "type": "boolean" },
|
|
106
|
+
"keywords": { "type": "array", "items": { "type": "string" } }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"diffSmell": { "$ref": "#/$defs/toggle" },
|
|
110
|
+
"caseCollision": { "$ref": "#/$defs/toggle" },
|
|
111
|
+
"sensitiveFileGuard": { "$ref": "#/$defs/toggle" },
|
|
112
|
+
"configValidation": { "$ref": "#/$defs/toggle" },
|
|
113
|
+
"typecheck": { "$ref": "#/$defs/toggle" },
|
|
114
|
+
"prBody": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"properties": {
|
|
117
|
+
"enabled": { "type": "boolean" },
|
|
118
|
+
"minLength": { "type": "number" },
|
|
119
|
+
"requireTicket": { "type": "boolean" }
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"cpp": { "$ref": "#/$defs/toggle" },
|
|
123
|
+
"python": {
|
|
124
|
+
"type": "object",
|
|
125
|
+
"properties": {
|
|
126
|
+
"enabled": { "type": "boolean" },
|
|
127
|
+
"typecheck": { "type": "boolean" },
|
|
128
|
+
"typeChecker": { "enum": ["mypy", "pyright"] },
|
|
129
|
+
"ruff": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"properties": {
|
|
132
|
+
"lint": { "type": "boolean" },
|
|
133
|
+
"format": { "type": "boolean" }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"swift": { "$ref": "#/$defs/toggle" },
|
|
139
|
+
"kotlin": { "$ref": "#/$defs/toggle" },
|
|
140
|
+
"go": { "$ref": "#/$defs/toggle" },
|
|
141
|
+
"rust": { "$ref": "#/$defs/toggle" },
|
|
142
|
+
"csharp": { "$ref": "#/$defs/toggle" },
|
|
143
|
+
"ruby": { "$ref": "#/$defs/toggle" },
|
|
144
|
+
"php": { "$ref": "#/$defs/toggle" }
|
|
145
|
+
},
|
|
146
|
+
"$defs": {
|
|
147
|
+
"toggle": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"properties": { "enabled": { "type": "boolean" } }
|
|
150
|
+
},
|
|
151
|
+
"toggleSeverity": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"enabled": { "type": "boolean" },
|
|
155
|
+
"severity": { "enum": ["error", "warn"] }
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"toggleIgnore": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"enabled": { "type": "boolean" },
|
|
162
|
+
"ignore": { "type": "array", "items": { "type": "string" } }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.diffSecurityCheck = void 0;
|
|
4
|
-
const utils_1 = require("../../utils");
|
|
5
|
-
const types_1 = require("../types");
|
|
6
|
-
const findings_1 = require("./findings");
|
|
7
|
-
const SECURITY_PATTERNS = [
|
|
8
|
-
{
|
|
9
|
-
pattern: /^\+(?!\+).*dangerouslySetInnerHTML\s*=/,
|
|
10
|
-
label: 'dangerouslySetInnerHTML (XSS risk)',
|
|
11
|
-
severity: 'error',
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
pattern: /^\+(?!\+).*\.innerHTML\s*=/,
|
|
15
|
-
label: 'innerHTML assignment (XSS risk)',
|
|
16
|
-
severity: 'warn',
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
pattern: /^\+(?!\+).*document\.write\s*\(/,
|
|
20
|
-
label: 'document.write() (XSS risk)',
|
|
21
|
-
severity: 'error',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
pattern: /^\+(?!\+)(?![^'"`]*['"`]).*\beval\s*\(/,
|
|
25
|
-
label: 'eval() (code injection risk)',
|
|
26
|
-
severity: 'error',
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
pattern: /^\+(?!\+).*\bnew\s+Function\s*\(/,
|
|
30
|
-
label: 'new Function() (code injection risk)',
|
|
31
|
-
severity: 'error',
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
pattern: /^\+(?!\+).*__proto__\s*[=:[]/,
|
|
35
|
-
label: '__proto__ mutation (prototype pollution)',
|
|
36
|
-
severity: 'error',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
pattern: /^\+(?!\+).*\.constructor\.prototype\b/,
|
|
40
|
-
label: 'constructor.prototype access (prototype pollution)',
|
|
41
|
-
severity: 'warn',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
pattern: /^\+(?!\+).*createHash\s*\(\s*['"]md5['"]/,
|
|
45
|
-
label: 'MD5 (weak hash — use sha256 or stronger)',
|
|
46
|
-
severity: 'warn',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
pattern: /^\+(?!\+).*createHash\s*\(\s*['"]sha1['"]/,
|
|
50
|
-
label: 'SHA-1 (weak hash — use sha256 or stronger)',
|
|
51
|
-
severity: 'warn',
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
pattern: /^\+(?!\+).*\bcreateDecipher\s*\(/,
|
|
55
|
-
label: 'deprecated createDecipher() — use createDecipheriv()',
|
|
56
|
-
severity: 'warn',
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
pattern: /^\+(?!\+).*\bcreateCipher\s*\(/,
|
|
60
|
-
label: 'deprecated createCipher() — use createCipheriv()',
|
|
61
|
-
severity: 'warn',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
pattern: /^\+(?!\+).*cors\s*\(\s*\{[^}]*origin\s*:\s*['"]\*['"]/,
|
|
65
|
-
label: "CORS wildcard origin: '*' (allows any domain)",
|
|
66
|
-
severity: 'warn',
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
pattern: /^\+(?!\+).*['"]Access-Control-Allow-Origin['"]\s*[,:]\s*['"]\*['"]/,
|
|
70
|
-
label: "Access-Control-Allow-Origin: '*' header (CORS wildcard)",
|
|
71
|
-
severity: 'warn',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
pattern: /^\+(?!\+).*(fetch|axios\.get|axios\.post|axios\.put|axios\.delete|http\.get|http\.request)\s*\(\s*['"]http:\/\//,
|
|
75
|
-
label: 'Insecure HTTP (non-HTTPS) in external call',
|
|
76
|
-
severity: 'warn',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
pattern: /^\+(?!\+).*(exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/,
|
|
80
|
-
label: 'exec/spawn with template literal (command injection risk)',
|
|
81
|
-
severity: 'error',
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
pattern: /^\+(?!\+).*(exec|execSync)\s*\(\s*['"][^'"]*['"\s]*\+/,
|
|
85
|
-
label: 'exec/spawn with string concatenation (command injection risk)',
|
|
86
|
-
severity: 'error',
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
pattern: /^\+(?!\+).*\b(query|execute|raw)\s*\(\s*`[^`]*\$\{/,
|
|
90
|
-
label: 'SQL query with template literal interpolation (SQL injection risk)',
|
|
91
|
-
severity: 'error',
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
// A quoted string that contains a whole SQL keyword, concatenated with a
|
|
95
|
-
// variable — the real injection shape. Word boundaries + the quote context
|
|
96
|
-
// stop identifiers like `insertions + deletions` from false-positiving.
|
|
97
|
-
pattern: /^\+(?!\+).*['"`][^'"`]*\b(SELECT|INSERT|UPDATE|DELETE|WHERE)\b[^'"`]*['"`]\s*\+\s*\w/i,
|
|
98
|
-
label: 'SQL string concatenation (SQL injection risk)',
|
|
99
|
-
severity: 'error',
|
|
100
|
-
},
|
|
101
|
-
];
|
|
102
|
-
/** Bucket added-line matches by severity, keyed by pattern label. */
|
|
103
|
-
function scanDiff(stdout) {
|
|
104
|
-
const errors = {};
|
|
105
|
-
const warnings = {};
|
|
106
|
-
for (const line of stdout.split('\n')) {
|
|
107
|
-
for (const { pattern, label, severity } of SECURITY_PATTERNS) {
|
|
108
|
-
if (pattern.test(line)) {
|
|
109
|
-
const bucket = severity === 'error' ? errors : warnings;
|
|
110
|
-
(bucket[label] ?? (bucket[label] = [])).push(line.slice(1).trim().substring(0, 120));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return { errors, warnings };
|
|
115
|
-
}
|
|
116
|
-
exports.diffSecurityCheck = {
|
|
117
|
-
name: 'Diff Security',
|
|
118
|
-
phase: 'informational',
|
|
119
|
-
applies(ctx) {
|
|
120
|
-
return ctx.config.diffSecurity?.enabled !== false && Boolean(ctx.baseSha);
|
|
121
|
-
},
|
|
122
|
-
async run(ctx) {
|
|
123
|
-
try {
|
|
124
|
-
const stdout = await (0, findings_1.diffAddedLines)(ctx, [
|
|
125
|
-
'*.ts',
|
|
126
|
-
'*.tsx',
|
|
127
|
-
'*.js',
|
|
128
|
-
'*.jsx',
|
|
129
|
-
'*.mjs',
|
|
130
|
-
'*.cjs',
|
|
131
|
-
]);
|
|
132
|
-
const { errors, warnings } = scanDiff(stdout);
|
|
133
|
-
return (0, findings_1.reportSeverityBuckets)(errors, warnings, {
|
|
134
|
-
prefix: 'Diff Security',
|
|
135
|
-
errorSummary: n => `${n} issue(s)`,
|
|
136
|
-
warningSummary: n => `${n} warning(s)`,
|
|
137
|
-
sampleLimit: 3,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
catch (err) {
|
|
141
|
-
utils_1.logger.warn(`[Diff Security]: ⚠️ Could not analyze diff\n${err}`);
|
|
142
|
-
return (0, types_1.skip)('diff unavailable');
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
};
|
|
File without changes
|
|
File without changes
|