96 lines
2.4 KiB
JavaScript
96 lines
2.4 KiB
JavaScript
import process from "node:process";
|
|
|
|
const chunks = [];
|
|
|
|
for await (const chunk of process.stdin) {
|
|
chunks.push(chunk);
|
|
}
|
|
|
|
let event;
|
|
|
|
try {
|
|
event = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
} catch {
|
|
deny("Raw protection could not parse the tool request.");
|
|
}
|
|
|
|
const toolName = String(
|
|
event.tool_name ?? event.toolName ?? event.name ?? ""
|
|
).toLowerCase();
|
|
const toolInput = event.tool_input ?? event.toolInput ?? event.input ?? {};
|
|
const readOnlyTool = /(read|search|grep|list|view|fetch|semantic)/.test(toolName);
|
|
|
|
if (readOnlyTool) {
|
|
allow();
|
|
}
|
|
|
|
const rawTargets = collectPathTargets(toolInput).filter(isRawPath);
|
|
const command = typeof toolInput.command === "string" ? toolInput.command : "";
|
|
const workingDirectory = String(event.cwd ?? "");
|
|
const shellTool = /(execute|terminal|shell|bash|powershell|command)/.test(toolName);
|
|
|
|
if (shellTool && (isRawPath(command) || isRawPath(workingDirectory))) {
|
|
deny(
|
|
"Shell commands that reference raw/ are blocked. Use a dedicated read or search tool to inspect raw evidence."
|
|
);
|
|
}
|
|
|
|
if (rawTargets.length > 0) {
|
|
deny(`Modification of raw evidence is forbidden: ${rawTargets[0]}`);
|
|
}
|
|
|
|
allow();
|
|
|
|
function collectPathTargets(value, key = "") {
|
|
if (Array.isArray(value)) {
|
|
return value.flatMap((item) => collectPathTargets(item, key));
|
|
}
|
|
|
|
if (value && typeof value === "object") {
|
|
return Object.entries(value).flatMap(([childKey, childValue]) =>
|
|
collectPathTargets(childValue, childKey)
|
|
);
|
|
}
|
|
|
|
if (typeof value !== "string") {
|
|
return [];
|
|
}
|
|
|
|
if (key === "input") {
|
|
return [...value.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm)].map(
|
|
(match) => match[1].trim()
|
|
);
|
|
}
|
|
|
|
return /(file|path|uri|target|destination|source)/i.test(key) ? [value] : [];
|
|
}
|
|
|
|
function isRawPath(value) {
|
|
const normalized = String(value)
|
|
.replaceAll("\\", "/")
|
|
.replaceAll('"', "")
|
|
.replaceAll("'", "")
|
|
.toLowerCase();
|
|
|
|
return /(^|[\s/:])raw(?:[\s/]|$)/.test(normalized);
|
|
}
|
|
|
|
function allow() {
|
|
process.stdout.write(JSON.stringify({ continue: true }));
|
|
process.exit(0);
|
|
}
|
|
|
|
function deny(reason) {
|
|
process.stdout.write(
|
|
JSON.stringify({
|
|
continue: false,
|
|
stopReason: reason,
|
|
hookSpecificOutput: {
|
|
hookEventName: "PreToolUse",
|
|
permissionDecision: "deny",
|
|
permissionDecisionReason: reason
|
|
}
|
|
})
|
|
);
|
|
process.exit(0);
|
|
} |