pr-checkmate 1.9.4 â 1.9.5
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 +2 -0
- package/dist/config/constants.js +1 -0
- package/dist/scripts/index.js +0 -1
- package/dist/scripts/security.js +94 -19
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -40,6 +40,8 @@ npx pr-checkmate <job>
|
|
|
40
40
|
| `prettier` | Format code using Prettier |
|
|
41
41
|
| `deps` | Check project dependencies |
|
|
42
42
|
| `spellcheck` | Run spellcheck via cspell |
|
|
43
|
+
| `security` | Run security scan for secrets |
|
|
44
|
+
|
|
43
45
|
<br>
|
|
44
46
|
|
|
45
47
|
## đĻ Example GitHub Actions Workflow
|
package/dist/config/constants.js
CHANGED
|
@@ -77,5 +77,6 @@ exports.DEFAULT_COMMANDS = {
|
|
|
77
77
|
'npx pr-checkmate lint': 'Lint code using ESLint',
|
|
78
78
|
'npx pr-checkmate prettier': 'Format code using Prettier',
|
|
79
79
|
'npx pr-checkmate deps': 'Check project dependencies',
|
|
80
|
+
'npx pr-checkmate security': 'Security scan',
|
|
80
81
|
'npx pr-checkmate spellcheck': 'Run spellcheck via cspell',
|
|
81
82
|
};
|
package/dist/scripts/index.js
CHANGED
package/dist/scripts/security.js
CHANGED
|
@@ -1,35 +1,110 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.runSecurityScan = runSecurityScan;
|
|
4
7
|
const execa_1 = require("execa");
|
|
5
8
|
const utils_1 = require("../utils");
|
|
6
|
-
const
|
|
7
|
-
const
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_child_process_1 = require("node:child_process");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
/**
|
|
13
|
+
* Get HEAD SHA from git
|
|
14
|
+
*/
|
|
15
|
+
function getHeadSha() {
|
|
16
|
+
try {
|
|
17
|
+
return (0, node_child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
utils_1.logger.warn(`â ī¸ Could not determine HEAD SHA from git\n${err}`);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get BASE SHA (for PR) or parent commit (for push)
|
|
26
|
+
*/
|
|
27
|
+
function getBaseSha() {
|
|
28
|
+
const eventName = process.env.GITHUB_EVENT_NAME;
|
|
29
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
30
|
+
try {
|
|
31
|
+
if (eventName === 'pull_request' && eventPath && (0, node_fs_1.existsSync)(eventPath)) {
|
|
32
|
+
// For PR: use pull_request.base.sha from GitHub event
|
|
33
|
+
const fs = require('node:fs');
|
|
34
|
+
const event = JSON.parse(fs.readFileSync(eventPath, 'utf-8'));
|
|
35
|
+
const baseSha = event?.pull_request?.base?.sha;
|
|
36
|
+
if (baseSha) {
|
|
37
|
+
utils_1.logger.info(`[getBaseSha]: âšī¸ Using PR base SHA: ${baseSha}`);
|
|
38
|
+
return baseSha;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
utils_1.logger.warn(`[getBaseSha]: â ī¸ Could not read GitHub event, trying git parent commit
|
|
44
|
+
${err}`);
|
|
45
|
+
}
|
|
46
|
+
// For push: use parent commit
|
|
47
|
+
try {
|
|
48
|
+
return (0, node_child_process_1.execSync)('git rev-parse HEAD^', { encoding: 'utf-8' }).trim();
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
utils_1.logger.warn(`â ī¸ Could not determine BASE SHA (might be first commit)\n${err}`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if gitleaks-secret-scanner is installed locally
|
|
57
|
+
*/
|
|
58
|
+
function getGitleaksCommand() {
|
|
59
|
+
const localPath = node_path_1.default.join(process.cwd(), 'node_modules', '.bin', 'gitleaks-secret-scanner');
|
|
60
|
+
if ((0, node_fs_1.existsSync)(localPath)) {
|
|
61
|
+
utils_1.logger.info('[getGitleaksCommand]: đĻ Using local gitleaks-secret-scanner');
|
|
62
|
+
return localPath;
|
|
63
|
+
}
|
|
64
|
+
utils_1.logger.info('[getGitleaksCommand]: đĨ Using npx gitleaks-secret-scanner');
|
|
65
|
+
return 'npx';
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run security scan for secrets
|
|
69
|
+
*/
|
|
8
70
|
async function runSecurityScan() {
|
|
9
|
-
utils_1.logger.info('đ Running
|
|
71
|
+
utils_1.logger.info('đ Running security scan with gitleaks-secret-scanner...');
|
|
10
72
|
try {
|
|
11
|
-
|
|
73
|
+
// Set up environment variables
|
|
74
|
+
const headSha = getHeadSha();
|
|
12
75
|
if (!headSha) {
|
|
13
|
-
|
|
14
|
-
headSha = (0, child_process_1.execSync)('git rev-parse HEAD').toString().trim();
|
|
15
|
-
process.env.HEAD_SHA = headSha;
|
|
16
|
-
utils_1.logger.info(`âšī¸ Detected HEAD_SHA=${headSha}`);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
utils_1.logger.warn('â ī¸ Could not determine HEAD SHA, skipping diff-mode ci');
|
|
20
|
-
}
|
|
76
|
+
utils_1.logger.warn('â ī¸ Could not determine HEAD SHA, security scan may not work properly');
|
|
21
77
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
78
|
+
const baseSha = getBaseSha();
|
|
79
|
+
if (!baseSha) {
|
|
80
|
+
utils_1.logger.warn('â ī¸ Could not determine BASE SHA, will scan all commits');
|
|
81
|
+
}
|
|
82
|
+
// Prepare environment
|
|
83
|
+
const env = {
|
|
84
|
+
...process.env,
|
|
85
|
+
...(headSha && { HEAD_SHA: headSha }),
|
|
86
|
+
...(baseSha && { BASE_SHA: baseSha }),
|
|
87
|
+
};
|
|
88
|
+
// Get gitleaks command
|
|
89
|
+
const cmd = getGitleaksCommand();
|
|
90
|
+
const args = cmd === 'npx' ? ['gitleaks-secret-scanner', '--diff-mode', 'ci'] : ['--diff-mode', 'ci'];
|
|
91
|
+
utils_1.logger.info(`Running: ${cmd} ${args.join(' ')}`);
|
|
92
|
+
utils_1.logger.info(`HEAD_SHA=${env.HEAD_SHA || 'auto-detect'}, BASE_SHA=${env.BASE_SHA || 'auto-detect'}`);
|
|
93
|
+
await (0, execa_1.execa)(cmd, args, {
|
|
26
94
|
stdio: 'inherit',
|
|
27
|
-
env
|
|
95
|
+
env,
|
|
28
96
|
});
|
|
29
|
-
utils_1.logger.info('â
|
|
97
|
+
utils_1.logger.info('â
Security scan completed successfully');
|
|
30
98
|
}
|
|
31
99
|
catch (err) {
|
|
32
|
-
|
|
100
|
+
// gitleaks returns exit code 1 if secrets are found
|
|
101
|
+
// This is expected behavior, we should inform but not necessarily crash
|
|
102
|
+
if (err instanceof Error && 'exitCode' in err && err.exitCode === 1) {
|
|
103
|
+
utils_1.logger.warn('â ī¸ gitleaks found potential secrets - please review gitleaks-report.html');
|
|
104
|
+
utils_1.logger.warn('đĄ If this is a false positive, add it to .gitleaksignore');
|
|
105
|
+
throw err; // Still throw to fail the CI
|
|
106
|
+
}
|
|
107
|
+
utils_1.logger.error('[runSecurityScan]: â Security scan failed');
|
|
33
108
|
throw err;
|
|
34
109
|
}
|
|
35
110
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-checkmate",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "Automated PR quality checks: linting, formatting, dependency analysis, and spellcheck",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"spellcheck": "cspell '**/*.{ts,tsx,js,jsx,md,json}' --no-progress",
|
|
38
38
|
"scan:secrets": "gitleaks-secret-scanner --diff-mode ci --html-report gitleaks-report.html",
|
|
39
39
|
"test": "echo 'Tests coming soon'",
|
|
40
|
+
"security-scan": "npx pr-checkmate security",
|
|
40
41
|
"clean": "rm -rf dist",
|
|
41
42
|
"release": "standard-version"
|
|
42
43
|
},
|