pr-checkmate 1.9.3 → 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 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
@@ -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
  };
@@ -33,7 +33,6 @@ async function runJob(jobName) {
33
33
  case 'all':
34
34
  await (0, lint_1.runLint)();
35
35
  await (0, dependency_check_1.runDependencyCheck)();
36
- // await runSecurityScan();
37
36
  try {
38
37
  await (0, prettier_autoformat_1.runPrettier)();
39
38
  }
@@ -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 fs_1 = require("fs");
7
- const child_process_1 = require("child_process");
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 secret scan with gitleaks-secret-scanner...');
71
+ utils_1.logger.info('🔐 Running security scan with gitleaks-secret-scanner...');
10
72
  try {
11
- let headSha = process.env.HEAD_SHA;
73
+ // Set up environment variables
74
+ const headSha = getHeadSha();
12
75
  if (!headSha) {
13
- try {
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 cmd = (0, fs_1.existsSync)('node_modules/.bin/gitleaks-secret-scanner')
23
- ? './node_modules/.bin/gitleaks-secret-scanner'
24
- : 'npx gitleaks-secret-scanner';
25
- await (0, execa_1.execa)(cmd, ['--diff-mode', 'ci', '--html-report', 'gitleaks-report.html'], {
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: process.env,
95
+ env,
28
96
  });
29
- utils_1.logger.info('✅ Secret scan completed');
97
+ utils_1.logger.info('✅ Security scan completed successfully');
30
98
  }
31
99
  catch (err) {
32
- utils_1.logger.error('❌ Secrets found or scan failed');
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",
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
  },