BurningTimesAi/scripts/auto_approve.py

76 lines
2.4 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
PreToolUse hook — 조직 공용 안전 도구 자동 승인
Live 체계의 권한 레이어 확장 (C28 문서 수정 무승인 원칙의 즉시 적용)
stdin JSON: {tool_name, tool_input}
stdout JSON: {hookSpecificOutput: {permissionDecision: allow|deny|ask}}
"""
import json
import sys
import io
import re
# Windows CP949 환경에서 UTF-8 출력 강제
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
def respond(decision, reason):
out = {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": decision,
"permissionDecisionReason": reason,
}
}
sys.stdout.write(json.dumps(out, ensure_ascii=False))
sys.stdout.flush()
sys.exit(0)
def main():
raw = sys.stdin.read()
try:
data = json.loads(raw)
except Exception:
respond("ask", "input parse failed")
tool_name = data.get("tool_name", "")
tool_input = data.get("tool_input", {}) or {}
# 시스템 경로 차단 (Edit·Write·MultiEdit)
if tool_name in ("Edit", "Write", "MultiEdit"):
fp = (tool_input.get("file_path") or "").replace("\\", "/").lower()
if fp.startswith("/etc/") or fp.startswith("/system/") or fp.startswith("/windows/"):
respond("deny", "system directory blocked")
if re.match(r"^[a-z]:/windows/", fp):
respond("deny", "Windows system directory blocked")
# 도구별 판정
if tool_name in ("Read", "Glob", "Grep", "TodoWrite", "WebFetch", "WebSearch", "NotebookEdit"):
respond("allow", "safe read/search/todo")
if tool_name in ("Edit", "Write", "MultiEdit"):
respond("allow", "doc/code edit (C28)")
if tool_name.startswith("mcp__"):
respond("allow", "MCP tool")
if tool_name in ("Agent", "Task", "Skill"):
respond("allow", "subagent/skill")
if tool_name == "Bash":
cmd = (tool_input.get("command") or "").strip()
danger = [
r"^rm(\s|$)", r"^rmdir(\s|$)", r"^sudo(\s|$)", r"^dd\s", r"^mkfs",
r"^format\s", r"^shutdown", r"^reboot",
r"^chmod\s+777", r"^chown\s",
]
for pat in danger:
if re.search(pat, cmd):
respond("deny", "dangerous bash: " + pat)
respond("allow", "safe bash")
respond("ask", "unknown tool " + tool_name)
if __name__ == "__main__":
main()