Protokoll #22123

ID22123
Zeitstempel2025-12-27 11:50:47.922623
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens6,386 (Input: 1,809, Output: 4,577)
Dauer95 ms
Request-Zeit2025-12-27 11:50:47.922623
Response-Zeit2025-12-27 11:50:48.017677

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_htmx.py",
        "old_string": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook HTMX Regeln (BLOCK) - Contract #14: htmx-patterns.\n\nKritische Regeln aus dem HTMX-Contract:\n- HTMX-C1: CSRF auf hx-post\n- HTMX-C2: CSRF auf hx-delete\n- HTMX-C3: CSRF auf hx-patch\n- HTMX-C4: Confirm auf hx-delete\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block\n\n\n# =============================================================================\n# VIEW FILE CHECK\n# =============================================================================\n\ndef is_view_file(file_path: str) -> bool:\n    \"\"\"Prüft ob es sich um eine View-Datei handelt.\"\"\"\n    return \"\/View\/\" in file_path and file_path.endswith(\".php\")\n\n\n# =============================================================================\n# HTMX CONTRACT RULES (Critical)\n# =============================================================================\n\ndef htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    # Finde alle hx-post Attribute\n    hx_post_pattern = r'hx-post\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_posts = list(re.finditer(hx_post_pattern, content))\n\n    if not hx_posts:\n        return None\n\n    # Prüfe jedes hx-post auf CSRF\n    for match in hx_posts:\n        # Suche im umgebenden Kontext (100 Zeichen vor und nach)\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        # Muss hx-headers mit X-CSRF-TOKEN haben\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C1\",\n                f\"hx-post at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_delete_pattern = r'hx-delete\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_deletes = list(re.finditer(hx_delete_pattern, content))\n\n    if not hx_deletes:\n        return None\n\n    for match in hx_deletes:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C2\",\n                f\"hx-delete at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_patch_pattern = r'hx-patch\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_patches = list(re.finditer(hx_patch_pattern, content))\n\n    if not hx_patches:\n        return None\n\n    for match in hx_patches:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C3\",\n                f\"hx-patch at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None",
        "new_string": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook HTMX Regeln (BLOCK) - Contract #14: htmx-patterns.\n\nKritische Regeln aus dem HTMX-Contract:\n- HTMX-C1: CSRF auf hx-post\n- HTMX-C2: CSRF auf hx-delete\n- HTMX-C3: CSRF auf hx-patch\n- HTMX-C4: Confirm auf hx-delete\n- HTMX-C5: CSRF auf hx-put\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block\n\n\n# =============================================================================\n# VIEW FILE CHECK\n# =============================================================================\n\ndef is_view_file(file_path: str) -> bool:\n    \"\"\"Prüft ob es sich um eine View-Datei handelt.\"\"\"\n    return \"\/View\/\" in file_path and file_path.endswith(\".php\")\n\n\n# =============================================================================\n# HELPER: Generic CSRF Check\n# =============================================================================\n\ndef _check_csrf_on_method(\n    file_path: str,\n    content: str,\n    method: str,\n    rule_id: str\n) -> Optional[dict]:\n    \"\"\"Generische CSRF-Prüfung für hx-{method} Attribute.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    pattern = rf'hx-{method}\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    matches = list(re.finditer(pattern, content))\n\n    if not matches:\n        return None\n\n    for match in matches:\n        # Suche im umgebenden Kontext (150 Zeichen vor und nach)\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        # Muss hx-headers mit X-CSRF-TOKEN haben\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                rule_id,\n                f\"hx-{method} at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\n# =============================================================================\n# HTMX CONTRACT RULES (Critical)\n# =============================================================================\n\ndef htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"post\", \"HTMX-C1\")\n\n\ndef htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"delete\", \"HTMX-C2\")\n\n\ndef htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"patch\", \"HTMX-C3\")\n\n\ndef htmx_c5_csrf_on_put(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C5: hx-put MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"put\", \"HTMX-C5\")"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/pre_rules_htmx.py",
        "oldString": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook HTMX Regeln (BLOCK) - Contract #14: htmx-patterns.\n\nKritische Regeln aus dem HTMX-Contract:\n- HTMX-C1: CSRF auf hx-post\n- HTMX-C2: CSRF auf hx-delete\n- HTMX-C3: CSRF auf hx-patch\n- HTMX-C4: Confirm auf hx-delete\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block\n\n\n# =============================================================================\n# VIEW FILE CHECK\n# =============================================================================\n\ndef is_view_file(file_path: str) -> bool:\n    \"\"\"Prüft ob es sich um eine View-Datei handelt.\"\"\"\n    return \"\/View\/\" in file_path and file_path.endswith(\".php\")\n\n\n# =============================================================================\n# HTMX CONTRACT RULES (Critical)\n# =============================================================================\n\ndef htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    # Finde alle hx-post Attribute\n    hx_post_pattern = r'hx-post\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_posts = list(re.finditer(hx_post_pattern, content))\n\n    if not hx_posts:\n        return None\n\n    # Prüfe jedes hx-post auf CSRF\n    for match in hx_posts:\n        # Suche im umgebenden Kontext (100 Zeichen vor und nach)\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        # Muss hx-headers mit X-CSRF-TOKEN haben\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C1\",\n                f\"hx-post at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_delete_pattern = r'hx-delete\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_deletes = list(re.finditer(hx_delete_pattern, content))\n\n    if not hx_deletes:\n        return None\n\n    for match in hx_deletes:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C2\",\n                f\"hx-delete at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_patch_pattern = r'hx-patch\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_patches = list(re.finditer(hx_patch_pattern, content))\n\n    if not hx_patches:\n        return None\n\n    for match in hx_patches:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C3\",\n                f\"hx-patch at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None",
        "newString": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook HTMX Regeln (BLOCK) - Contract #14: htmx-patterns.\n\nKritische Regeln aus dem HTMX-Contract:\n- HTMX-C1: CSRF auf hx-post\n- HTMX-C2: CSRF auf hx-delete\n- HTMX-C3: CSRF auf hx-patch\n- HTMX-C4: Confirm auf hx-delete\n- HTMX-C5: CSRF auf hx-put\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block\n\n\n# =============================================================================\n# VIEW FILE CHECK\n# =============================================================================\n\ndef is_view_file(file_path: str) -> bool:\n    \"\"\"Prüft ob es sich um eine View-Datei handelt.\"\"\"\n    return \"\/View\/\" in file_path and file_path.endswith(\".php\")\n\n\n# =============================================================================\n# HELPER: Generic CSRF Check\n# =============================================================================\n\ndef _check_csrf_on_method(\n    file_path: str,\n    content: str,\n    method: str,\n    rule_id: str\n) -> Optional[dict]:\n    \"\"\"Generische CSRF-Prüfung für hx-{method} Attribute.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    pattern = rf'hx-{method}\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    matches = list(re.finditer(pattern, content))\n\n    if not matches:\n        return None\n\n    for match in matches:\n        # Suche im umgebenden Kontext (150 Zeichen vor und nach)\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        # Muss hx-headers mit X-CSRF-TOKEN haben\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                rule_id,\n                f\"hx-{method} at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\n# =============================================================================\n# HTMX CONTRACT RULES (Critical)\n# =============================================================================\n\ndef htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"post\", \"HTMX-C1\")\n\n\ndef htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"delete\", \"HTMX-C2\")\n\n\ndef htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"patch\", \"HTMX-C3\")\n\n\ndef htmx_c5_csrf_on_put(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C5: hx-put MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    return _check_csrf_on_method(file_path, content, \"put\", \"HTMX-C5\")",
        "originalFile": "#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook HTMX Regeln (BLOCK) - Contract #14: htmx-patterns.\n\nKritische Regeln aus dem HTMX-Contract:\n- HTMX-C1: CSRF auf hx-post\n- HTMX-C2: CSRF auf hx-delete\n- HTMX-C3: CSRF auf hx-patch\n- HTMX-C4: Confirm auf hx-delete\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block\n\n\n# =============================================================================\n# VIEW FILE CHECK\n# =============================================================================\n\ndef is_view_file(file_path: str) -> bool:\n    \"\"\"Prüft ob es sich um eine View-Datei handelt.\"\"\"\n    return \"\/View\/\" in file_path and file_path.endswith(\".php\")\n\n\n# =============================================================================\n# HTMX CONTRACT RULES (Critical)\n# =============================================================================\n\ndef htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    # Finde alle hx-post Attribute\n    hx_post_pattern = r'hx-post\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_posts = list(re.finditer(hx_post_pattern, content))\n\n    if not hx_posts:\n        return None\n\n    # Prüfe jedes hx-post auf CSRF\n    for match in hx_posts:\n        # Suche im umgebenden Kontext (100 Zeichen vor und nach)\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        # Muss hx-headers mit X-CSRF-TOKEN haben\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C1\",\n                f\"hx-post at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_delete_pattern = r'hx-delete\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_deletes = list(re.finditer(hx_delete_pattern, content))\n\n    if not hx_deletes:\n        return None\n\n    for match in hx_deletes:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C2\",\n                f\"hx-delete at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_patch_pattern = r'hx-patch\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_patches = list(re.finditer(hx_patch_pattern, content))\n\n    if not hx_patches:\n        return None\n\n    for match in hx_patches:\n        start = max(0, match.start() - 150)\n        end = min(len(content), match.end() + 150)\n        context = content[start:end]\n\n        if 'hx-headers' not in context or 'CSRF' not in context.upper():\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C3\",\n                f\"hx-patch at line {line_num} missing CSRF token. \"\n                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"\n            )\n\n    return None\n\n\ndef htmx_c4_delete_requires_confirm(file_path: str, content: str) -> Optional[dict]:\n    \"\"\"HTMX-C4: hx-delete MUSS hx-confirm Attribut haben.\"\"\"\n    if not is_view_file(file_path):\n        return None\n\n    hx_delete_pattern = r'hx-delete\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'\n    hx_deletes = list(re.finditer(hx_delete_pattern, content))\n\n    if not hx_deletes:\n        return None\n\n    for match in hx_deletes:\n        # Suche im Element-Kontext (vom < bis zum nächsten >)\n        # Gehe zurück bis zum < und vorwärts bis zum >\n        element_start = content.rfind('<', 0, match.start())\n        element_end = content.find('>', match.end())\n\n        if element_start == -1 or element_end == -1:\n            continue\n\n        element = content[element_start:element_end + 1]\n\n        if 'hx-confirm' not in element:\n            line_num = content[:match.start()].count('\\n') + 1\n            return block(\n                \"HTMX-C4\",\n                f\"hx-delete at line {line_num} missing confirmation. \"\n                \"Add: hx-confirm=\\\"Wirklich loeschen?\\\"\"\n            )\n\n    return None\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    htmx_c1_csrf_on_post,\n    htmx_c2_csrf_on_delete,\n    htmx_c3_csrf_on_patch,\n    htmx_c4_delete_requires_confirm,\n]\n",
        "structuredPatch": [
            {
                "oldStart": 7,
                "oldLines": 6,
                "newStart": 7,
                "newLines": 7,
                "lines": [
                    " - HTMX-C2: CSRF auf hx-delete",
                    " - HTMX-C3: CSRF auf hx-patch",
                    " - HTMX-C4: Confirm auf hx-delete",
                    "+- HTMX-C5: CSRF auf hx-put",
                    " \"\"\"",
                    " ",
                    " import re"
                ]
            },
            {
                "oldStart": 24,
                "oldLines": 24,
                "newStart": 25,
                "newLines": 27,
                "lines": [
                    " ",
                    " ",
                    " # =============================================================================",
                    "-# HTMX CONTRACT RULES (Critical)",
                    "+# HELPER: Generic CSRF Check",
                    " # =============================================================================",
                    " ",
                    "-def htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:",
                    "-    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "+def _check_csrf_on_method(",
                    "+    file_path: str,",
                    "+    content: str,",
                    "+    method: str,",
                    "+    rule_id: str",
                    "+) -> Optional[dict]:",
                    "+    \"\"\"Generische CSRF-Prüfung für hx-{method} Attribute.\"\"\"",
                    "     if not is_view_file(file_path):",
                    "         return None",
                    " ",
                    "-    # Finde alle hx-post Attribute",
                    "-    hx_post_pattern = r'hx-post\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'",
                    "-    hx_posts = list(re.finditer(hx_post_pattern, content))",
                    "+    pattern = rf'hx-{method}\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'",
                    "+    matches = list(re.finditer(pattern, content))",
                    " ",
                    "-    if not hx_posts:",
                    "+    if not matches:",
                    "         return None",
                    " ",
                    "-    # Prüfe jedes hx-post auf CSRF",
                    "-    for match in hx_posts:",
                    "-        # Suche im umgebenden Kontext (100 Zeichen vor und nach)",
                    "+    for match in matches:",
                    "+        # Suche im umgebenden Kontext (150 Zeichen vor und nach)",
                    "         start = max(0, match.start() - 150)",
                    "         end = min(len(content), match.end() + 150)",
                    "         context = content[start:end]"
                ]
            },
            {
                "oldStart": 50,
                "oldLines": 68,
                "newStart": 54,
                "newLines": 38,
                "lines": [
                    "         if 'hx-headers' not in context or 'CSRF' not in context.upper():",
                    "             line_num = content[:match.start()].count('\\n') + 1",
                    "             return block(",
                    "-                \"HTMX-C1\",",
                    "-                f\"hx-post at line {line_num} missing CSRF token. \"",
                    "+                rule_id,",
                    "+                f\"hx-{method} at line {line_num} missing CSRF token. \"",
                    "                 \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"",
                    "             )",
                    " ",
                    "     return None",
                    " ",
                    " ",
                    "-def htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:",
                    "-    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "-    if not is_view_file(file_path):",
                    "-        return None",
                    "+# =============================================================================",
                    "+# HTMX CONTRACT RULES (Critical)",
                    "+# =============================================================================",
                    " ",
                    "-    hx_delete_pattern = r'hx-delete\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'",
                    "-    hx_deletes = list(re.finditer(hx_delete_pattern, content))",
                    "+def htmx_c1_csrf_on_post(file_path: str, content: str) -> Optional[dict]:",
                    "+    \"\"\"HTMX-C1: hx-post MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "+    return _check_csrf_on_method(file_path, content, \"post\", \"HTMX-C1\")",
                    " ",
                    "-    if not hx_deletes:",
                    "-        return None",
                    " ",
                    "-    for match in hx_deletes:",
                    "-        start = max(0, match.start() - 150)",
                    "-        end = min(len(content), match.end() + 150)",
                    "-        context = content[start:end]",
                    "+def htmx_c2_csrf_on_delete(file_path: str, content: str) -> Optional[dict]:",
                    "+    \"\"\"HTMX-C2: hx-delete MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "+    return _check_csrf_on_method(file_path, content, \"delete\", \"HTMX-C2\")",
                    " ",
                    "-        if 'hx-headers' not in context or 'CSRF' not in context.upper():",
                    "-            line_num = content[:match.start()].count('\\n') + 1",
                    "-            return block(",
                    "-                \"HTMX-C2\",",
                    "-                f\"hx-delete at line {line_num} missing CSRF token. \"",
                    "-                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"",
                    "-            )",
                    " ",
                    "-    return None",
                    "-",
                    "-",
                    " def htmx_c3_csrf_on_patch(file_path: str, content: str) -> Optional[dict]:",
                    "     \"\"\"HTMX-C3: hx-patch MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "-    if not is_view_file(file_path):",
                    "-        return None",
                    "+    return _check_csrf_on_method(file_path, content, \"patch\", \"HTMX-C3\")",
                    " ",
                    "-    hx_patch_pattern = r'hx-patch\\s*=\\s*[\"\\'][^\"\\']+[\"\\']'",
                    "-    hx_patches = list(re.finditer(hx_patch_pattern, content))",
                    " ",
                    "-    if not hx_patches:",
                    "-        return None",
                    "+def htmx_c5_csrf_on_put(file_path: str, content: str) -> Optional[dict]:",
                    "+    \"\"\"HTMX-C5: hx-put MUSS X-CSRF-TOKEN in hx-headers haben.\"\"\"",
                    "+    return _check_csrf_on_method(file_path, content, \"put\", \"HTMX-C5\")",
                    " ",
                    "-    for match in hx_patches:",
                    "-        start = max(0, match.start() - 150)",
                    "-        end = min(len(content), match.end() + 150)",
                    "-        context = content[start:end]",
                    " ",
                    "-        if 'hx-headers' not in context or 'CSRF' not in context.upper():",
                    "-            line_num = content[:match.start()].count('\\n') + 1",
                    "-            return block(",
                    "-                \"HTMX-C3\",",
                    "-                f\"hx-patch at line {line_num} missing CSRF token. \"",
                    "-                \"Add: hx-headers='{\\\"X-CSRF-TOKEN\\\": \\\"<?= $csrfToken ?>\\\"}'\"",
                    "-            )",
                    "-",
                    "-    return None",
                    "-",
                    "-",
                    " def htmx_c4_delete_requires_confirm(file_path: str, content: str) -> Optional[dict]:",
                    "     \"\"\"HTMX-C4: hx-delete MUSS hx-confirm Attribut haben.\"\"\"",
                    "     if not is_view_file(file_path):"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →