Skip to content

Commit b55416f

Browse files
refactor(ci): extract secrets detection into dedicated shell script
1 parent e943c2c commit b55416f

3 files changed

Lines changed: 85 additions & 75 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"commitlint": "commitlint --edit",
4141
"commitlint:last": "commitlint --from HEAD~1 --to HEAD --verbose",
4242
"validate:secrets": "node scripts/validate-secrets.js",
43-
"license-check": "sh scripts/secrets-check.sh",
43+
"license-check": "node scripts/license-check.js",
4444
"ci": "npm run license-check && npm run lint && npm run build && npm run test:unit && npm run test:integration",
4545
"ci:full": "npm run commitlint:last && npm run ci",
4646
"prepare": "husky",

scripts/secrets-check.sh

Lines changed: 0 additions & 43 deletions
This file was deleted.

scripts/validate-secrets.js

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,107 @@
11
#!/usr/bin/env node
22
/**
3-
* Cross-platform secrets detection using Gitleaks
4-
* Works on Windows, macOS, and Linux
3+
* Cross-platform secrets detection using Gitleaks.
4+
* Supports Docker and Podman (including Colima, OrbStack, Podman Machine).
5+
* Works on Windows, macOS, and Linux.
56
*
6-
* This script runs Gitleaks in a Docker container for local validation.
7-
* CI uses the official gitleaks-action@v2 for better GitHub integration.
8-
* Both share the same .gitleaks.toml configuration.
7+
* Usage:
8+
* node scripts/validate-secrets.js # scan working directory
99
*/
1010

11-
import { spawn } from 'child_process';
12-
import { platform } from 'os';
13-
import { resolve } from 'path';
14-
import { existsSync } from 'fs';
11+
import { spawn, execSync } from 'child_process'
12+
import { existsSync } from 'fs'
13+
import { platform } from 'os'
14+
import { resolve } from 'path'
1515

16-
const isWindows = platform() === 'win32';
17-
const projectPath = resolve(process.cwd());
16+
const GITLEAKS_IMAGE = 'ghcr.io/gitleaks/gitleaks:v8.30.1'
17+
const isWindows = platform() === 'win32'
18+
const projectPath = resolve(process.cwd())
19+
const configPath = resolve(projectPath, '.gitleaks.toml')
20+
const hasConfig = existsSync(configPath)
1821

19-
// Check if .gitleaks.toml exists
20-
const configPath = resolve(projectPath, '.gitleaks.toml');
21-
const hasConfig = existsSync(configPath);
22+
function commandExists(cmd) {
23+
try {
24+
execSync(isWindows ? `where ${cmd}` : `which ${cmd}`, { stdio: 'ignore' })
25+
return true
26+
} catch {
27+
return false
28+
}
29+
}
30+
31+
function daemonRunning(engine) {
32+
try {
33+
execSync(`${engine} info`, { stdio: 'ignore' })
34+
return true
35+
} catch {
36+
return false
37+
}
38+
}
39+
40+
function detectEngine() {
41+
for (const engine of ['docker', 'podman']) {
42+
if (commandExists(engine)) return engine
43+
}
44+
return null
45+
}
46+
47+
function hintForStoppedDaemon(engine) {
48+
if (engine === 'docker') {
49+
if (commandExists('colima')) return "Run 'colima start' to enable secrets detection locally"
50+
if (commandExists('orbstack')) return 'Start OrbStack to enable secrets detection locally'
51+
}
52+
if (engine === 'podman') {
53+
return "Run 'podman machine start' to enable secrets detection locally"
54+
}
55+
return 'Start your container engine to enable secrets detection locally'
56+
}
57+
58+
const engine = detectEngine()
59+
60+
if (!engine) {
61+
console.log('No container engine found (docker/podman) - skipping secrets detection')
62+
console.log('Install Docker or Podman to enable local secrets scanning')
63+
process.exit(1)
64+
}
65+
66+
if (!daemonRunning(engine)) {
67+
const engineLabel = engine.charAt(0).toUpperCase() + engine.slice(1)
68+
console.error(`${engineLabel} daemon is not running`)
69+
console.error(hintForStoppedDaemon(engine))
70+
process.exit(1)
71+
}
2272

2373
const args = [
2474
'run',
2575
'--rm',
2676
'-v',
27-
`${projectPath}:/path`,
28-
'ghcr.io/gitleaks/gitleaks:v8.30.1',
29-
'detect',
30-
'--source=/path',
77+
`${projectPath}:/workspace`,
78+
GITLEAKS_IMAGE,
79+
'dir',
80+
'--no-banner',
3181
'--verbose',
32-
'--no-git'
33-
];
82+
]
3483

35-
// Add config file if it exists
3684
if (hasConfig) {
37-
args.push('--config=/path/.gitleaks.toml');
85+
args.push('--config=/workspace/.gitleaks.toml')
3886
}
3987

40-
console.log('Running Gitleaks secrets detection...');
88+
args.push('/workspace')
89+
90+
console.log('Checking for secrets with Gitleaks...')
4191

42-
const gitleaks = spawn('docker', args, {
92+
const gitleaks = spawn(engine, args, {
4393
stdio: 'inherit',
44-
shell: isWindows
45-
});
94+
shell: isWindows,
95+
})
4696

4797
gitleaks.on('close', (code) => {
48-
process.exit(code);
49-
});
98+
if (code !== 0) {
99+
console.error('Secrets detected! Please remove sensitive data before committing.')
100+
}
101+
process.exit(code)
102+
})
50103

51104
gitleaks.on('error', (err) => {
52-
console.error('Failed to run Gitleaks:', err.message);
53-
process.exit(1);
54-
});
105+
console.error(`Failed to run Gitleaks via ${engine}:`, err.message)
106+
process.exit(1)
107+
})

0 commit comments

Comments
 (0)