#!/usr/bin/env python3 """PreToolUse guard for Read/Write/Edit/Glob/Grep (EDEN, Master Prompt §2.1/§3.4). Blocks access to paths outside the project root and to ~/.ssh or /etc, and asks for confirmation before reading a .env/credential-looking file. Fails open on any internal error. """ import json import os import re import sys PROJECT_ROOT = "/opt/eden" HOME = os.path.expanduser("~") SECRET_NAME_RE = re.compile(r"(^|/)(\.env(\..+)?|.*credential.*|.*secret.*)$", re.IGNORECASE) def extract_path(tool_input: dict) -> str: for key in ("file_path", "path", "notebook_path"): if key in tool_input: return tool_input[key] or "" # Grep/Glob use "path" for the search root; pattern itself isn't a filesystem path. return "" def decide(path: str): if not path: return "allow", None abspath = os.path.abspath(path) ssh_dir = os.path.join(HOME, ".ssh") if abspath == ssh_dir or abspath.startswith(ssh_dir + os.sep): return "deny", "acesso a ~/.ssh" if abspath == "/etc" or abspath.startswith("/etc" + os.sep): return "deny", "acesso a /etc" if abspath == "/root" or abspath.startswith("/root" + os.sep): return "deny", "acesso a /root" if abspath.startswith("/opt/") and not ( abspath == PROJECT_ROOT or abspath.startswith(PROJECT_ROOT + os.sep) ): return "deny", f"caminho fora de {PROJECT_ROOT} (outro projeto no host)" basename = os.path.basename(abspath) if SECRET_NAME_RE.match(basename): return "ask", f"leitura/escrita de arquivo que parece conter segredo ({basename})" return "allow", None def main(): try: payload = json.load(sys.stdin) tool_input = payload.get("tool_input") or {} path = extract_path(tool_input) except Exception: print(json.dumps({})) return decision, reason = decide(path) if decision == "allow": print(json.dumps({})) return output = { "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": decision, "permissionDecisionReason": f"[eden-guard] {reason} (EDEN_MASTER_PROMPT_CLAUDE.md §2.1/§3.4)", } } print(json.dumps(output)) if __name__ == "__main__": main()