init
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user