rules_security.py
- Pfad:
/var/www/tools/ki-protokoll/claude-hook/quality/rules_security.py - Namespace: claude-hook.quality
- Zeilen: 128 | Größe: 4,240 Bytes
- Geändert: 2025-12-25 16:56:31 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 100
- Dependencies: 100 (25%)
- LOC: 100 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 100 (10%)
Keine Issues gefunden.
Dependencies 4
- extends Rule
- use re
- use typing.List
- use rule_base.Rule
Klassen 5
-
W2_1_BusinessKeywordsInControllerclass Zeile 17 -
W2_2_PrivateMethodsInControllerclass Zeile 46 -
W3_1_PotentialUntypedParamsclass Zeile 68 -
W3_3_MixedTypeclass Zeile 81 -
W7_1_UseCaseInterfaceDependencyclass Zeile 95
Code
#!/usr/bin/env python3
"""
Security & Architecture Rules (W2, W3, W7).
Regeln für MVC-Architektur, Type-Safety und Dependency Injection.
"""
import re
from typing import List
from .rule_base import Rule
# =============================================================================
# W2: MVC + CRUD - Architectural Boundaries
# =============================================================================
class W2_1_BusinessKeywordsInController(Rule):
"""W2.1: Business-Keywords in Controller."""
def should_skip(self, file_path: str) -> bool:
if "/Controller/" not in file_path:
return True
return super().should_skip(file_path)
def check(self, file_path: str, content: str) -> List[str]:
keywords = [
(r"\bcalculate\w*\s*\(", "calculate"),
(r"\bcompute\w*\s*\(", "compute"),
(r"\bvalidate\w*\s*\(", "validate"),
(r"\bprocess\w*\s*\(", "process"),
(r"\btransform\w*\s*\(", "transform"),
(r"\bconvert\w*\s*\(", "convert"),
]
found = []
for pattern, name in keywords:
if re.search(pattern, content, re.IGNORECASE):
found.append(name)
if found:
return [f"W2.1: Business keywords in Controller: {', '.join(found)}. Consider moving to Domain/UseCase."]
return []
class W2_2_PrivateMethodsInController(Rule):
"""W2.2: Viele private Methoden in Controller (max 5)."""
def should_skip(self, file_path: str) -> bool:
if "/Controller/" not in file_path:
return True
return super().should_skip(file_path)
def check(self, file_path: str, content: str) -> List[str]:
private_methods = re.findall(r"private\s+function\s+\w+", content)
count = len(private_methods)
if count > 5:
return [f"W2.2: Controller has {count} private methods (max 5). Extract to Service."]
return []
# =============================================================================
# W3: PSR + Types - Type Safety
# =============================================================================
class W3_1_PotentialUntypedParams(Rule):
"""W3.1: Potentiell untypisierte Parameter."""
def check(self, file_path: str, content: str) -> List[str]:
# Heuristik: Suche nach $param direkt nach ( oder ,
potential = re.findall(r"function\s+\w+\s*\([^)]*[(,]\s*\$", content)
if potential:
return ["W3.1: Potential untyped parameters detected. Run PHPStan for verification."]
return []
class W3_3_MixedType(Rule):
"""W3.3: mixed Type verwendet."""
def check(self, file_path: str, content: str) -> List[str]:
if re.search(r":\s*mixed\b", content):
return ["W3.3: 'mixed' type used. Consider more specific type."]
return []
# =============================================================================
# W7: DI + AUTOWIRING - Dependency Injection
# =============================================================================
class W7_1_UseCaseInterfaceDependency(Rule):
"""W7.1: UseCase mit Interface-Dependency - Hinweis zur Registrierung."""
def should_skip(self, file_path: str) -> bool:
if "/UseCases/" not in file_path:
return True
return super().should_skip(file_path)
def check(self, file_path: str, content: str) -> List[str]:
constructor_match = re.search(r"function\s+__construct\s*\(([^)]*)\)", content, re.DOTALL)
if not constructor_match:
return []
params = constructor_match.group(1)
interface_deps = re.findall(r"(\w+Interface)\s+\$", params)
if interface_deps:
return [f"W7.1: Hint - UseCase uses interfaces: {', '.join(interface_deps)}. Ensure registered in services.php."]
return []
# =============================================================================
# RULE COLLECTION
# =============================================================================
RULES = [
W2_1_BusinessKeywordsInController(),
W2_2_PrivateMethodsInController(),
W3_1_PotentialUntypedParams(),
W3_3_MixedType(),
W7_1_UseCaseInterfaceDependency(),
]