58 lines
1.4 KiB
JavaScript
58 lines
1.4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import {
|
|
chmodSync,
|
|
existsSync,
|
|
mkdirSync,
|
|
readFileSync,
|
|
writeFileSync,
|
|
} from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const MARKER = "# sf-secret-scan";
|
|
|
|
function git(args) {
|
|
return execFileSync("git", args, {
|
|
encoding: "utf8",
|
|
shell: process.platform === "win32",
|
|
}).trim();
|
|
}
|
|
|
|
const gitDir = git(["rev-parse", "--git-dir"]);
|
|
const repoRoot = git(["rev-parse", "--show-toplevel"]);
|
|
const hookDir = join(gitDir, "hooks");
|
|
const hookFile = join(hookDir, "pre-commit");
|
|
const hookCommand = `node "${join(repoRoot, "scripts", "secret-scan.mjs")}"`;
|
|
|
|
mkdirSync(hookDir, { recursive: true });
|
|
|
|
if (existsSync(hookFile)) {
|
|
const current = readFileSync(hookFile, "utf8");
|
|
if (current.includes(MARKER)) {
|
|
process.stdout.write("secret-scan pre-commit hook already installed.\n");
|
|
process.exit(0);
|
|
}
|
|
|
|
const next = `${current.replace(/\s*$/, "\n")}${MARKER}\n${hookCommand}\n`;
|
|
writeFileSync(hookFile, next, "utf8");
|
|
process.stdout.write("secret-scan appended to existing pre-commit hook.\n");
|
|
process.exit(0);
|
|
}
|
|
|
|
const hookBody = [
|
|
"#!/usr/bin/env sh",
|
|
"# sf-secret-scan",
|
|
"# Pre-commit hook: scan staged files for hardcoded secrets",
|
|
hookCommand,
|
|
"",
|
|
].join("\n");
|
|
|
|
writeFileSync(hookFile, hookBody, "utf8");
|
|
try {
|
|
chmodSync(hookFile, 0o755);
|
|
} catch {
|
|
// Best effort on Windows filesystems that do not honor chmod.
|
|
}
|
|
|
|
process.stdout.write("secret-scan pre-commit hook installed.\n");
|