{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_deterministic.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook Deterministic Regeln (BLOCK) - Deterministic Behavior.\n\nP8.x Regeln: Verbietet nicht-deterministische Funktionen und globalen Zustand.\nErzwingt Dependency Injection statt globaler Abhängigkeiten.\n\nPrinzip: \"Gleicher Input erzeugt gleichen Output. Kein versteckter globaler Zustand.\"\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import GLOBAL_ALLOWLIST, is_in_allowlist, block\n\n\n# =============================================================================\n# KONFIGURATION\n# =============================================================================\n\n# Verbotene nicht-deterministische Funktionen\nFORBIDDEN_FUNCTIONS = {\n \"P8.1\": {\n \"pattern\": r\"\\btime\\s*\\(\",\n \"message\": \"Use Clock interface instead of time(). Inject ClockInterface for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Clock\/\"],\n },\n \"P8.2\": {\n \"pattern\": r\"\\bdate\\s*\\(\",\n \"message\": \"Use Clock interface instead of date(). Inject ClockInterface for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Clock\/\"],\n },\n \"P8.3\": {\n \"pattern\": r\"\\brand\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of rand(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n \"P8.4\": {\n \"pattern\": r\"\\bmt_rand\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of mt_rand(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n \"P8.5\": {\n \"pattern\": r\"\\brandom_int\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of random_int(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n}\n\n# Verbotener globaler Zustand\nFORBIDDEN_GLOBAL_STATE = {\n \"P8.6\": {\n \"pattern\": r\"\\bglobal\\s+\\$\",\n \"message\": \"Use dependency injection instead of 'global' keyword.\",\n },\n \"P8.7\": {\n \"pattern\": r\"\\$GLOBALS\\b\",\n \"message\": \"Use dependency injection instead of $GLOBALS.\",\n },\n \"P8.8\": {\n \"pattern\": r\"\\$_SESSION\\b\",\n \"message\": \"Use SessionInterface instead of $_SESSION. Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Session\/\", \"\/Framework\/\"],\n },\n \"P8.9\": {\n \"pattern\": r\"\\$_COOKIE\\b\",\n \"message\": \"Use CookieInterface instead of $_COOKIE. Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Http\/\", \"\/Framework\/\"],\n },\n}\n\n\n# =============================================================================\n# REGELN\n# =============================================================================\n\ndef p8_forbidden_functions(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P8.1-P8.5: Nicht-deterministische Funktionen blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):\n return None\n\n for rule_id, config in FORBIDDEN_FUNCTIONS.items():\n # Spezifische Allowlist für diese Regel\n specific_allowlist = config.get(\"allowlist\", [])\n if is_in_allowlist(file_path, specific_allowlist):\n continue\n\n if re.search(config[\"pattern\"], content):\n return block(rule_id, config[\"message\"])\n\n return None\n\n\ndef p8_forbidden_global_state(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P8.6-P8.9: Globaler Zustand blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):\n return None\n\n for rule_id, config in FORBIDDEN_GLOBAL_STATE.items():\n # Spezifische Allowlist für diese Regel\n specific_allowlist = config.get(\"allowlist\", [])\n if is_in_allowlist(file_path, specific_allowlist):\n continue\n\n if re.search(config[\"pattern\"], content):\n return block(rule_id, config[\"message\"])\n\n return None\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n p8_forbidden_functions,\n p8_forbidden_global_state,\n]\n"
}
}
{
"tool_response": {
"type": "create",
"filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_deterministic.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook Deterministic Regeln (BLOCK) - Deterministic Behavior.\n\nP8.x Regeln: Verbietet nicht-deterministische Funktionen und globalen Zustand.\nErzwingt Dependency Injection statt globaler Abhängigkeiten.\n\nPrinzip: \"Gleicher Input erzeugt gleichen Output. Kein versteckter globaler Zustand.\"\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import GLOBAL_ALLOWLIST, is_in_allowlist, block\n\n\n# =============================================================================\n# KONFIGURATION\n# =============================================================================\n\n# Verbotene nicht-deterministische Funktionen\nFORBIDDEN_FUNCTIONS = {\n \"P8.1\": {\n \"pattern\": r\"\\btime\\s*\\(\",\n \"message\": \"Use Clock interface instead of time(). Inject ClockInterface for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Clock\/\"],\n },\n \"P8.2\": {\n \"pattern\": r\"\\bdate\\s*\\(\",\n \"message\": \"Use Clock interface instead of date(). Inject ClockInterface for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Clock\/\"],\n },\n \"P8.3\": {\n \"pattern\": r\"\\brand\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of rand(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n \"P8.4\": {\n \"pattern\": r\"\\bmt_rand\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of mt_rand(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n \"P8.5\": {\n \"pattern\": r\"\\brandom_int\\s*\\(\",\n \"message\": \"Use RandomGenerator interface instead of random_int(). Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Random\/\"],\n },\n}\n\n# Verbotener globaler Zustand\nFORBIDDEN_GLOBAL_STATE = {\n \"P8.6\": {\n \"pattern\": r\"\\bglobal\\s+\\$\",\n \"message\": \"Use dependency injection instead of 'global' keyword.\",\n },\n \"P8.7\": {\n \"pattern\": r\"\\$GLOBALS\\b\",\n \"message\": \"Use dependency injection instead of $GLOBALS.\",\n },\n \"P8.8\": {\n \"pattern\": r\"\\$_SESSION\\b\",\n \"message\": \"Use SessionInterface instead of $_SESSION. Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Session\/\", \"\/Framework\/\"],\n },\n \"P8.9\": {\n \"pattern\": r\"\\$_COOKIE\\b\",\n \"message\": \"Use CookieInterface instead of $_COOKIE. Inject for testability.\",\n \"allowlist\": [\"\/Infrastructure\/Http\/\", \"\/Framework\/\"],\n },\n}\n\n\n# =============================================================================\n# REGELN\n# =============================================================================\n\ndef p8_forbidden_functions(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P8.1-P8.5: Nicht-deterministische Funktionen blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):\n return None\n\n for rule_id, config in FORBIDDEN_FUNCTIONS.items():\n # Spezifische Allowlist für diese Regel\n specific_allowlist = config.get(\"allowlist\", [])\n if is_in_allowlist(file_path, specific_allowlist):\n continue\n\n if re.search(config[\"pattern\"], content):\n return block(rule_id, config[\"message\"])\n\n return None\n\n\ndef p8_forbidden_global_state(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P8.6-P8.9: Globaler Zustand blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):\n return None\n\n for rule_id, config in FORBIDDEN_GLOBAL_STATE.items():\n # Spezifische Allowlist für diese Regel\n specific_allowlist = config.get(\"allowlist\", [])\n if is_in_allowlist(file_path, specific_allowlist):\n continue\n\n if re.search(config[\"pattern\"], content):\n return block(rule_id, config[\"message\"])\n\n return None\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n p8_forbidden_functions,\n p8_forbidden_global_state,\n]\n",
"structuredPatch": [],
"originalFile": null
}
}