{
"event": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_constants.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook Constants Regeln (BLOCK) - Magic Number Enforcement.\n\nP7.x Regeln: Keine Magic Numbers, benannte Konstanten verwenden.\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import GLOBAL_ALLOWLIST, COMMON_NUMBERS, is_in_allowlist, block\n\n\n# =============================================================================\n# CONSTANTS ALLOWLIST\n# =============================================================================\n\nCONSTANTS_ALLOWLIST = [\n \"\/Constants.php\", # PHP Constants file\n \"\/constants.py\", # Python constants files\n \"\/config.py\", # Config files\n \"\/Config.php\", # PHP config files\n \"\/config\/\", # Config directories\n \"CodeQualityChecker.php\", # Quality checker itself\n]\n\n# Erlaubte Magic Numbers (zusätzlich zu COMMON_NUMBERS)\nALLOWED_MAGIC = COMMON_NUMBERS | {\n # Array-Indizes\n '3', '4', '5', '6', '7', '8', '9',\n # HTTP Status\n '202', '206', '300', '303', '307', '308',\n '405', '406', '408', '409', '410', '422', '429', '502', '503', '504',\n # Bit-Operationen\n '16', '32', '64', '128', '256', '512', '1024', '2048', '4096',\n}\n\n# Kritische Magic Numbers die IMMER blockiert werden\nCRITICAL_MAGIC = {\n '3600': 'SECONDS_PER_HOUR',\n '86400': 'SECONDS_PER_DAY',\n '604800': 'SECONDS_PER_WEEK',\n '2592000': 'SECONDS_PER_MONTH',\n '31536000': 'SECONDS_PER_YEAR',\n}\n\n\n# =============================================================================\n# PRÜFUNG 7: CONSTANTS\n# =============================================================================\n\ndef p7_1_critical_magic_numbers(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P7.1: Kritische Magic Numbers blockieren (3600, 86400, etc.).\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST + CONSTANTS_ALLOWLIST):\n return None\n\n # Nur PHP und Python Dateien\n if not (file_path.endswith('.php') or file_path.endswith('.py')):\n return None\n\n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n # Skip Kommentare\n stripped = line.strip()\n if stripped.startswith('\/\/') or stripped.startswith('#') or stripped.startswith('*'):\n continue\n\n # Skip const\/define Definitionen\n if re.search(r'\\bconst\\b|\\bdefine\\b|=.*Constants::', line, re.IGNORECASE):\n continue\n\n # Prüfe auf kritische Magic Numbers\n for magic, constant_name in CRITICAL_MAGIC.items():\n # Nur alleinstehende Zahlen matchen\n pattern = rf'\\b{magic}\\b'\n if re.search(pattern, line):\n return block(\n \"P7.1\",\n f\"Critical magic number {magic} found at line {line_num}. \"\n f\"Use Domain\\\\Constants::{constant_name} instead.\"\n )\n\n return None\n\n\ndef p7_2_time_calculations(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P7.2: Zeit-Berechnungen mit Magic Numbers blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST + CONSTANTS_ALLOWLIST):\n return None\n\n if not (file_path.endswith('.php') or file_path.endswith('.py')):\n return None\n\n # Pattern für Zeit-Berechnungen: * 60 * 60, * 24 * 60, etc.\n time_calc_patterns = [\n (r'\\*\\s*60\\s*\\*\\s*60', 'Use Constants::SECONDS_PER_HOUR'),\n (r'\\*\\s*24\\s*\\*\\s*60', 'Use Constants for time calculations'),\n (r'\\*\\s*60\\s*\\*\\s*24', 'Use Constants for time calculations'),\n (r'\\*\\s*365\\s*\\*\\s*24', 'Use Constants for time calculations'),\n ]\n\n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n # Skip Kommentare\n stripped = line.strip()\n if stripped.startswith('\/\/') or stripped.startswith('#') or stripped.startswith('*'):\n continue\n\n for pattern, suggestion in time_calc_patterns:\n if re.search(pattern, line):\n return block(\n \"P7.2\",\n f\"Time calculation with magic numbers at line {line_num}. {suggestion}\"\n )\n\n return None\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n p7_1_critical_magic_numbers,\n p7_2_time_calculations,\n]\n"
}
}
{
"tool_response": {
"type": "create",
"filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_constants.py",
"content": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook Constants Regeln (BLOCK) - Magic Number Enforcement.\n\nP7.x Regeln: Keine Magic Numbers, benannte Konstanten verwenden.\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import GLOBAL_ALLOWLIST, COMMON_NUMBERS, is_in_allowlist, block\n\n\n# =============================================================================\n# CONSTANTS ALLOWLIST\n# =============================================================================\n\nCONSTANTS_ALLOWLIST = [\n \"\/Constants.php\", # PHP Constants file\n \"\/constants.py\", # Python constants files\n \"\/config.py\", # Config files\n \"\/Config.php\", # PHP config files\n \"\/config\/\", # Config directories\n \"CodeQualityChecker.php\", # Quality checker itself\n]\n\n# Erlaubte Magic Numbers (zusätzlich zu COMMON_NUMBERS)\nALLOWED_MAGIC = COMMON_NUMBERS | {\n # Array-Indizes\n '3', '4', '5', '6', '7', '8', '9',\n # HTTP Status\n '202', '206', '300', '303', '307', '308',\n '405', '406', '408', '409', '410', '422', '429', '502', '503', '504',\n # Bit-Operationen\n '16', '32', '64', '128', '256', '512', '1024', '2048', '4096',\n}\n\n# Kritische Magic Numbers die IMMER blockiert werden\nCRITICAL_MAGIC = {\n '3600': 'SECONDS_PER_HOUR',\n '86400': 'SECONDS_PER_DAY',\n '604800': 'SECONDS_PER_WEEK',\n '2592000': 'SECONDS_PER_MONTH',\n '31536000': 'SECONDS_PER_YEAR',\n}\n\n\n# =============================================================================\n# PRÜFUNG 7: CONSTANTS\n# =============================================================================\n\ndef p7_1_critical_magic_numbers(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P7.1: Kritische Magic Numbers blockieren (3600, 86400, etc.).\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST + CONSTANTS_ALLOWLIST):\n return None\n\n # Nur PHP und Python Dateien\n if not (file_path.endswith('.php') or file_path.endswith('.py')):\n return None\n\n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n # Skip Kommentare\n stripped = line.strip()\n if stripped.startswith('\/\/') or stripped.startswith('#') or stripped.startswith('*'):\n continue\n\n # Skip const\/define Definitionen\n if re.search(r'\\bconst\\b|\\bdefine\\b|=.*Constants::', line, re.IGNORECASE):\n continue\n\n # Prüfe auf kritische Magic Numbers\n for magic, constant_name in CRITICAL_MAGIC.items():\n # Nur alleinstehende Zahlen matchen\n pattern = rf'\\b{magic}\\b'\n if re.search(pattern, line):\n return block(\n \"P7.1\",\n f\"Critical magic number {magic} found at line {line_num}. \"\n f\"Use Domain\\\\Constants::{constant_name} instead.\"\n )\n\n return None\n\n\ndef p7_2_time_calculations(file_path: str, content: str) -> Optional[dict]:\n \"\"\"P7.2: Zeit-Berechnungen mit Magic Numbers blockieren.\"\"\"\n if is_in_allowlist(file_path, GLOBAL_ALLOWLIST + CONSTANTS_ALLOWLIST):\n return None\n\n if not (file_path.endswith('.php') or file_path.endswith('.py')):\n return None\n\n # Pattern für Zeit-Berechnungen: * 60 * 60, * 24 * 60, etc.\n time_calc_patterns = [\n (r'\\*\\s*60\\s*\\*\\s*60', 'Use Constants::SECONDS_PER_HOUR'),\n (r'\\*\\s*24\\s*\\*\\s*60', 'Use Constants for time calculations'),\n (r'\\*\\s*60\\s*\\*\\s*24', 'Use Constants for time calculations'),\n (r'\\*\\s*365\\s*\\*\\s*24', 'Use Constants for time calculations'),\n ]\n\n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n # Skip Kommentare\n stripped = line.strip()\n if stripped.startswith('\/\/') or stripped.startswith('#') or stripped.startswith('*'):\n continue\n\n for pattern, suggestion in time_calc_patterns:\n if re.search(pattern, line):\n return block(\n \"P7.2\",\n f\"Time calculation with magic numbers at line {line_num}. {suggestion}\"\n )\n\n return None\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n p7_1_critical_magic_numbers,\n p7_2_time_calculations,\n]\n",
"structuredPatch": [],
"originalFile": null
}
}