#!/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");