79 lines
2.1 KiB
JavaScript
79 lines
2.1 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";
|
|
const PROTECTED_DELETIONS_MARKER = "# sf-protected-deletions";
|
|
|
|
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")}"`;
|
|
const protectedDeletionsCommand = `node "${join(
|
|
repoRoot,
|
|
"scripts",
|
|
"check-protected-deletions.mjs",
|
|
)}" --cached`;
|
|
|
|
mkdirSync(hookDir, { recursive: true });
|
|
|
|
if (existsSync(hookFile)) {
|
|
const current = readFileSync(hookFile, "utf8");
|
|
const additions = [];
|
|
if (!current.includes(MARKER)) {
|
|
additions.push(MARKER, hookCommand);
|
|
}
|
|
if (!current.includes(PROTECTED_DELETIONS_MARKER)) {
|
|
additions.push(
|
|
PROTECTED_DELETIONS_MARKER,
|
|
"# Pre-commit hook: block accidental deletion of hand-written extension declarations",
|
|
protectedDeletionsCommand,
|
|
);
|
|
}
|
|
if (additions.length === 0) {
|
|
process.stdout.write("sf pre-commit hooks already installed.\n");
|
|
process.exit(0);
|
|
}
|
|
|
|
const next = `${current.replace(/\s*$/, "\n")}${additions.join("\n")}\n`;
|
|
writeFileSync(hookFile, next, "utf8");
|
|
process.stdout.write("sf pre-commit hooks appended to existing hook.\n");
|
|
process.exit(0);
|
|
}
|
|
|
|
const hookBody = [
|
|
"#!/usr/bin/env sh",
|
|
"# sf-secret-scan",
|
|
"# Pre-commit hook: scan staged files for hardcoded secrets",
|
|
hookCommand,
|
|
"",
|
|
"# sf-protected-deletions",
|
|
"# Pre-commit hook: block accidental deletion of hand-written extension declarations",
|
|
protectedDeletionsCommand,
|
|
"",
|
|
].join("\n");
|
|
|
|
writeFileSync(hookFile, hookBody, "utf8");
|
|
try {
|
|
chmodSync(hookFile, 0o755);
|
|
} catch {
|
|
// Best effort on Windows filesystems that do not honor chmod.
|
|
}
|
|
|
|
process.stdout.write("sf pre-commit hooks installed.\n");
|