mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-08-28 02:44:59 +00:00
84 lines
2.8 KiB
JavaScript
84 lines
2.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import {
|
|
copyFileSync,
|
|
lstatSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readlinkSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { spawnSync } from 'node:child_process';
|
|
|
|
const binary = process.env.GITLEAKS_BIN || 'gitleaks';
|
|
|
|
function runGitleaks(args, cwd) {
|
|
return spawnSync(binary, args, { cwd, encoding: 'utf8', env: process.env });
|
|
}
|
|
|
|
function fail(message, result) {
|
|
console.error(message);
|
|
if (result?.error?.code === 'ENOENT') {
|
|
console.error(`Gitleaks binary not found at ${binary}. Install gitleaks or set GITLEAKS_BIN.`);
|
|
} else if (result?.stderr) {
|
|
console.error(result.stderr.trim());
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
function stageScannableSource() {
|
|
const repositoryRoot = process.cwd();
|
|
const listing = spawnSync(
|
|
'git',
|
|
['ls-files', '--cached', '--others', '--exclude-standard', '-z'],
|
|
{ cwd: repositoryRoot, encoding: 'utf8' }
|
|
);
|
|
if (listing.status !== 0) fail('Could not inventory Git-managed source files.', listing);
|
|
|
|
const stagingDirectory = mkdtempSync(join(tmpdir(), 'veritas-gitleaks-source-'));
|
|
for (const relativePath of listing.stdout.split('\0').filter(Boolean)) {
|
|
const source = resolve(repositoryRoot, relativePath);
|
|
const destination = resolve(stagingDirectory, relativePath);
|
|
mkdirSync(dirname(destination), { recursive: true });
|
|
const stats = lstatSync(source);
|
|
if (stats.isSymbolicLink()) {
|
|
writeFileSync(destination, readlinkSync(source));
|
|
} else if (stats.isFile()) {
|
|
copyFileSync(source, destination);
|
|
}
|
|
}
|
|
return stagingDirectory;
|
|
}
|
|
|
|
const sourceDirectory = stageScannableSource();
|
|
const fixtureDirectory = mkdtempSync(join(tmpdir(), 'veritas-gitleaks-regression-'));
|
|
try {
|
|
const repositoryScan = runGitleaks(
|
|
['dir', '.', '--no-banner', '--redact=100', '--gitleaks-ignore-path', '.gitleaksignore'],
|
|
sourceDirectory
|
|
);
|
|
if (repositoryScan.status !== 0) {
|
|
fail('Gitleaks found a secret outside the reviewed fingerprint baseline.', repositoryScan);
|
|
}
|
|
|
|
const syntheticToken = ['sk', '_live_', '51Z9Y8X7W6V5U4T3S2Q1P0N9'].join('');
|
|
writeFileSync(join(fixtureDirectory, 'new-secret.env'), `payment_token=${syntheticToken}\n`);
|
|
const regressionScan = runGitleaks(
|
|
['dir', '.', '--no-banner', '--redact=100', '--gitleaks-ignore-path', '/dev/null'],
|
|
fixtureDirectory
|
|
);
|
|
if (regressionScan.status !== 1) {
|
|
fail(
|
|
`Gitleaks regression fixture was not rejected (expected exit 1, got ${String(regressionScan.status)}).`,
|
|
regressionScan
|
|
);
|
|
}
|
|
} finally {
|
|
rmSync(sourceDirectory, { recursive: true, force: true });
|
|
rmSync(fixtureDirectory, { recursive: true, force: true });
|
|
}
|
|
|
|
console.log('Gitleaks accepted the reviewed baseline and rejected a newly introduced test secret.');
|