mirror of
https://github.com/duthaho/claudekit.git
synced 2026-07-18 13:39:40 +03:00
53 lines
1.6 KiB
JavaScript
53 lines
1.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* PreToolUse hook (matcher: Write|Edit): blocks edits to sensitive files —
|
|
* env files, private key material, credential dotfiles.
|
|
* Exit 0 = allow, Exit 2 = block.
|
|
* Fails open on errors (exit 0) so a hook bug never stalls the session.
|
|
*
|
|
* Template env files (.env.example / .env.sample / .env.template) stay
|
|
* editable — they exist to be written.
|
|
*/
|
|
"use strict";
|
|
|
|
const ALLOWED = [/\.env\.(example|sample|template)$/i];
|
|
|
|
const SENSITIVE_PATTERNS = [
|
|
{ name: "env file", re: /(^|\/)\.env(\.[^/]+)?$/i },
|
|
{ name: "key material", re: /\.(pem|key|p12|pfx)$/i },
|
|
{ name: "SSH private key", re: /(^|\/)id_(rsa|ed25519|ecdsa|dsa)[^/]*$/i },
|
|
{ name: "credential file", re: /(^|\/)\.(netrc|npmrc|git-credentials)$/i },
|
|
{ name: "AWS credentials", re: /(^|\/)\.aws\/credentials$/i },
|
|
];
|
|
|
|
async function main() {
|
|
try {
|
|
let data = "";
|
|
for await (const chunk of process.stdin) data += chunk;
|
|
const input = JSON.parse(data);
|
|
|
|
const raw = input?.tool_input?.file_path ?? "";
|
|
// Normalize Windows separators so path-anchored patterns hold.
|
|
const filePath = (typeof raw === "string" ? raw : "").replace(/\\/g, "/");
|
|
if (!filePath) process.exit(0);
|
|
|
|
if (ALLOWED.some((re) => re.test(filePath))) process.exit(0);
|
|
|
|
for (const { name, re } of SENSITIVE_PATTERNS) {
|
|
if (re.test(filePath)) {
|
|
console.error(
|
|
`BLOCKED: "${filePath}" is a ${name} — edit it manually, outside the agent session.`
|
|
);
|
|
process.exit(2);
|
|
}
|
|
}
|
|
|
|
process.exit(0);
|
|
} catch {
|
|
// Fail open — never block on hook errors
|
|
process.exit(0);
|
|
}
|
|
}
|
|
|
|
main();
|