{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/block_direct_db.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nBlock Direct Database Access Hook\n\nBlockiert direkte mysql\/mariadb-Befehle in Bash.\nErzwingt Nutzung von MCP-DB stattdessen.\n\nTrigger: PreToolUse (Bash)\n\"\"\"\n\nimport json\nimport re\nimport sys\n\n# Patterns die IMMER blockiert werden\nBLOCKED_PATTERNS = [\n r'\\bmysql\\s+-[up]', # mysql -u oder mysql -p\n r'\\bmysql\\s+.*-p\\S', # mysql mit Passwort direkt nach -p\n r'\\bmariadb\\s+-[up]', # mariadb -u oder mariadb -p\n r'\\bmariadb\\s+.*-p\\S', # mariadb mit Passwort\n r'--password=', # --password=xxx\n r'\\bmysqldump\\b', # mysqldump\n r'\\bmysqlimport\\b', # mysqlimport\n r'\\bmysqladmin\\b', # mysqladmin\n r'-p[a-zA-Z0-9_]{6,}', # -p gefolgt von Passwort (min 6 Zeichen)\n]\n\nBLOCK_MESSAGE = \"\"\"\n╔══════════════════════════════════════════════════════════════════╗\n║ BLOCKIERT: Direkter Datenbankzugriff ist verboten! ║\n╠══════════════════════════════════════════════════════════════════╣\n║ ║\n║ Verwende stattdessen MCP-DB: ║\n║ ║\n║ • mcp__mcp-db__db_select - für SELECT-Abfragen ║\n║ • mcp__mcp-db__db_schema - für Tabellenstruktur ║\n║ • mcp__mcp-db__db_stats - für Statistiken ║\n║ ║\n║ NIEMALS Passwörter in Bash-Befehlen verwenden! ║\n║ ║\n╚══════════════════════════════════════════════════════════════════╝\n\"\"\"\n\n\ndef check_command(command: str) -> tuple[bool, str]:\n \"\"\"\n Prüft ob ein Befehl blockiert werden soll.\n\n Returns:\n (blocked: bool, reason: str)\n \"\"\"\n command_lower = command.lower()\n\n for pattern in BLOCKED_PATTERNS:\n if re.search(pattern, command, re.IGNORECASE):\n return True, f\"Pattern matched: {pattern}\"\n\n return False, \"\"\n\n\ndef main():\n try:\n input_data = json.load(sys.stdin)\n except json.JSONDecodeError:\n # Kein JSON = kein Hook-Input, durchlassen\n sys.exit(0)\n\n # Nur Bash-Tool prüfen\n tool_name = input_data.get(\"tool_name\", \"\")\n if tool_name != \"Bash\":\n sys.exit(0)\n\n # Command extrahieren\n tool_input = input_data.get(\"tool_input\", {})\n command = tool_input.get(\"command\", \"\")\n\n if not command:\n sys.exit(0)\n\n # Prüfen\n blocked, reason = check_command(command)\n\n if blocked:\n # Blockieren\n result = {\n \"decision\": \"block\",\n \"reason\": BLOCK_MESSAGE\n }\n print(json.dumps(result))\n sys.exit(0)\n\n # Durchlassen\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n"
}
}
{
"tool_response": {
"type": "create",
"filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/block_direct_db.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nBlock Direct Database Access Hook\n\nBlockiert direkte mysql\/mariadb-Befehle in Bash.\nErzwingt Nutzung von MCP-DB stattdessen.\n\nTrigger: PreToolUse (Bash)\n\"\"\"\n\nimport json\nimport re\nimport sys\n\n# Patterns die IMMER blockiert werden\nBLOCKED_PATTERNS = [\n r'\\bmysql\\s+-[up]', # mysql -u oder mysql -p\n r'\\bmysql\\s+.*-p\\S', # mysql mit Passwort direkt nach -p\n r'\\bmariadb\\s+-[up]', # mariadb -u oder mariadb -p\n r'\\bmariadb\\s+.*-p\\S', # mariadb mit Passwort\n r'--password=', # --password=xxx\n r'\\bmysqldump\\b', # mysqldump\n r'\\bmysqlimport\\b', # mysqlimport\n r'\\bmysqladmin\\b', # mysqladmin\n r'-p[a-zA-Z0-9_]{6,}', # -p gefolgt von Passwort (min 6 Zeichen)\n]\n\nBLOCK_MESSAGE = \"\"\"\n╔══════════════════════════════════════════════════════════════════╗\n║ BLOCKIERT: Direkter Datenbankzugriff ist verboten! ║\n╠══════════════════════════════════════════════════════════════════╣\n║ ║\n║ Verwende stattdessen MCP-DB: ║\n║ ║\n║ • mcp__mcp-db__db_select - für SELECT-Abfragen ║\n║ • mcp__mcp-db__db_schema - für Tabellenstruktur ║\n║ • mcp__mcp-db__db_stats - für Statistiken ║\n║ ║\n║ NIEMALS Passwörter in Bash-Befehlen verwenden! ║\n║ ║\n╚══════════════════════════════════════════════════════════════════╝\n\"\"\"\n\n\ndef check_command(command: str) -> tuple[bool, str]:\n \"\"\"\n Prüft ob ein Befehl blockiert werden soll.\n\n Returns:\n (blocked: bool, reason: str)\n \"\"\"\n command_lower = command.lower()\n\n for pattern in BLOCKED_PATTERNS:\n if re.search(pattern, command, re.IGNORECASE):\n return True, f\"Pattern matched: {pattern}\"\n\n return False, \"\"\n\n\ndef main():\n try:\n input_data = json.load(sys.stdin)\n except json.JSONDecodeError:\n # Kein JSON = kein Hook-Input, durchlassen\n sys.exit(0)\n\n # Nur Bash-Tool prüfen\n tool_name = input_data.get(\"tool_name\", \"\")\n if tool_name != \"Bash\":\n sys.exit(0)\n\n # Command extrahieren\n tool_input = input_data.get(\"tool_input\", {})\n command = tool_input.get(\"command\", \"\")\n\n if not command:\n sys.exit(0)\n\n # Prüfen\n blocked, reason = check_command(command)\n\n if blocked:\n # Blockieren\n result = {\n \"decision\": \"block\",\n \"reason\": BLOCK_MESSAGE\n }\n print(json.dumps(result))\n sys.exit(0)\n\n # Durchlassen\n sys.exit(0)\n\n\nif __name__ == \"__main__\":\n main()\n",
"structuredPatch": [],
"originalFile": null
}
}