Protokoll #6573

ID6573
Zeitstempel2025-12-23 06:22:38.409612
Clientroot
IP
Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13

Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens1,361 (Input: 0, Output: 0)
Dauer96 ms
Request-Zeit
Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18
Response-Zeit-

Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22

Request

{
    "event": "PreToolUse",
    "tool_name": "Read",
    "tool_input": {
        "file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/architecture_guard.py"
    }
}

Response

{
    "tool_response": {
        "type": "text",
        "file": {
            "filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/architecture_guard.py",
            "content": "#!\/usr\/bin\/env python3\n\"\"\"\nArchitecture Guard - Pre-Hook (Blocking)\n\nEnforces hard_constraints from architecture-gate-contract v1.1\nBlocks file creation on violation. No exceptions.\n\nRules:\n  H1: strict_types_required (all PHP files)\n  H2: domain_no_infrastructure (Domain layer)\n  H3: db_factory_only (only in Factory classes)\n  H4: no_new_repository_in_controller (Controller layer)\n  H5: no_new_infrastructure_in_controller (Controller layer)\n\nTrigger: PreToolUse (Write) on *.php\n\"\"\"\n\nimport json\nimport re\nimport sys\n\n# Hard rules from architecture-gate-contract v1.1\nHARD_RULES = [\n    {\n        \"id\": \"H1\",\n        \"name\": \"strict_types_required\",\n        \"pattern\": r\"declare\\s*\\(\\s*strict_types\\s*=\\s*1\\s*\\)\",\n        \"must_match\": True,\n        \"applies_to\": \"all\",\n        \"message\": \"Missing declare(strict_types=1). Add at top of file after <?php\"\n    },\n    {\n        \"id\": \"H2\",\n        \"name\": \"domain_no_infrastructure\",\n        \"pattern\": r\"use\\s+Infrastructure\\\\\",\n        \"must_match\": False,\n        \"applies_to\": \"\/Domain\/\",\n        \"message\": \"Domain must not use Infrastructure. Violates DIP.\"\n    },\n    {\n        \"id\": \"H3\",\n        \"name\": \"db_factory_only\",\n        \"pattern\": r\"DatabaseFactory::\",\n        \"must_match\": False,\n        \"applies_to_not\": \"\/Factory\/\",\n        \"message\": \"DatabaseFactory only allowed in Factory classes. Use DI.\"\n    },\n    {\n        \"id\": \"H4\",\n        \"name\": \"no_new_repository_in_controller\",\n        \"pattern\": r\"new\\s+\\w+Repository\\s*\\(\",\n        \"must_match\": False,\n        \"applies_to\": \"\/Controller\/\",\n        \"message\": \"new Repository in Controller not allowed. Use DI via constructor.\"\n    },\n    {\n        \"id\": \"H5\",\n        \"name\": \"no_new_infrastructure_in_controller\",\n        \"pattern\": r\"new\\s+Infrastructure\\\\\",\n        \"must_match\": False,\n        \"applies_to\": \"\/Controller\/\",\n        \"message\": \"new Infrastructure in Controller not allowed. Use DI via constructor.\"\n    }\n]\n\n# Paths exempt from all rules\nALLOWED_PATHS = [\n    \"\/Factory\/\",\n    \"\/Bootstrap\/\",\n    \"\/tests\/\",\n    \"\/Test\/\",\n    \"\/vendor\/\",\n]\n\n\ndef is_allowed_path(file_path: str) -> bool:\n    \"\"\"Check if file is in allowlist.\"\"\"\n    for allowed in ALLOWED_PATHS:\n        if allowed in file_path:\n            return True\n    return False\n\n\ndef rule_applies(rule: dict, file_path: str) -> bool:\n    \"\"\"Check if rule applies to this file path.\"\"\"\n    if \"applies_to\" in rule:\n        if rule[\"applies_to\"] == \"all\":\n            return True\n        return rule[\"applies_to\"] in file_path\n\n    if \"applies_to_not\" in rule:\n        return rule[\"applies_to_not\"] not in file_path\n\n    return True\n\n\ndef check_rule(rule: dict, content: str) -> bool:\n    \"\"\"\n    Check if content violates the rule.\n\n    Returns True if VIOLATED, False if OK.\n    \"\"\"\n    match = re.search(rule[\"pattern\"], content)\n\n    if rule[\"must_match\"]:\n        # Pattern MUST be present\n        return match is None  # Violated if NOT found\n    else:\n        # Pattern must NOT be present\n        return match is not None  # Violated if found\n\n\ndef check_all_rules(file_path: str, content: str) -> dict:\n    \"\"\"\n    Check all rules against file.\n\n    Returns:\n        {\"allowed\": True} if all pass\n        {\"allowed\": False, \"message\": \"...\"} on first violation\n    \"\"\"\n    # Skip non-PHP files\n    if not file_path.endswith(\".php\"):\n        return {\"allowed\": True}\n\n    # Skip allowlisted paths\n    if is_allowed_path(file_path):\n        return {\"allowed\": True}\n\n    for rule in HARD_RULES:\n        if not rule_applies(rule, file_path):\n            continue\n\n        if check_rule(rule, content):\n            return {\n                \"allowed\": False,\n                \"message\": f\"ARCHITECTURE VIOLATION [{rule['id']}]: {rule['message']}\"\n            }\n\n    return {\"allowed\": True}\n\n\ndef format_output(result: dict) -> str:\n    \"\"\"Format output as JSON for Claude Code hook protocol.\"\"\"\n    return json.dumps(result)\n\n\ndef main():\n    try:\n        input_data = json.load(sys.stdin)\n    except json.JSONDecodeError:\n        # Invalid input, allow by default\n        print(json.dumps({\"allowed\": True}))\n        sys.exit(0)\n\n    tool_name = input_data.get(\"tool_name\", \"\")\n\n    # Only check Write operations\n    if tool_name != \"Write\":\n        print(json.dumps({\"allowed\": True}))\n        sys.exit(0)\n\n    tool_input = input_data.get(\"tool_input\", {})\n    file_path = tool_input.get(\"file_path\", \"\")\n    content = tool_input.get(\"content\", \"\")\n\n    result = check_all_rules(file_path, content)\n\n    print(format_output(result))\n\n    if result[\"allowed\"]:\n        sys.exit(0)\n    else:\n        sys.exit(0)  # Exit 0 with allowed:false triggers block\n\n\nif __name__ == \"__main__\":\n    main()\n",
            "numLines": 178,
            "startLine": 1,
            "totalLines": 178
        }
    }
}
← Vorheriger Zur Liste Nächster →