pre_rules_deterministic.py

Code Hygiene Score: 100

Keine Issues gefunden.

Dependencies 5

Funktionen 2

Code

#!/usr/bin/env python3
"""
Pre-Hook Deterministic Regeln (BLOCK) - Deterministic Behavior.

P8.x Regeln: Verbietet nicht-deterministische Funktionen und globalen Zustand.
Erzwingt Dependency Injection statt globaler Abhängigkeiten.

Prinzip: "Gleicher Input erzeugt gleichen Output. Kein versteckter globaler Zustand."
"""

import re
from typing import Optional
from .rule_base import GLOBAL_ALLOWLIST, is_in_allowlist, block


# =============================================================================
# KONFIGURATION
# =============================================================================

# Verbotene nicht-deterministische Funktionen
FORBIDDEN_FUNCTIONS = {
    "P8.1": {
        "pattern": r"\btime\s*\(",
        "message": "Use Clock interface instead of time(). Inject ClockInterface for testability.",
        "allowlist": ["/Infrastructure/Clock/"],
    },
    "P8.2": {
        "pattern": r"\bdate\s*\(",
        "message": "Use Clock interface instead of date(). Inject ClockInterface for testability.",
        "allowlist": ["/Infrastructure/Clock/"],
    },
    "P8.3": {
        "pattern": r"\brand\s*\(",
        "message": "Use RandomGenerator interface instead of rand(). Inject for testability.",
        "allowlist": ["/Infrastructure/Random/"],
    },
    "P8.4": {
        "pattern": r"\bmt_rand\s*\(",
        "message": "Use RandomGenerator interface instead of mt_rand(). Inject for testability.",
        "allowlist": ["/Infrastructure/Random/"],
    },
    "P8.5": {
        "pattern": r"\brandom_int\s*\(",
        "message": "Use RandomGenerator interface instead of random_int(). Inject for testability.",
        "allowlist": ["/Infrastructure/Random/"],
    },
}

# Verbotener globaler Zustand
FORBIDDEN_GLOBAL_STATE = {
    "P8.6": {
        "pattern": r"\bglobal\s+\$",
        "message": "Use dependency injection instead of 'global' keyword.",
    },
    "P8.7": {
        "pattern": r"\$GLOBALS\b",
        "message": "Use dependency injection instead of $GLOBALS.",
    },
    "P8.8": {
        "pattern": r"\$_SESSION\b",
        "message": "Use SessionInterface instead of $_SESSION. Inject for testability.",
        "allowlist": ["/Infrastructure/Session/", "/Framework/"],
    },
    "P8.9": {
        "pattern": r"\$_COOKIE\b",
        "message": "Use CookieInterface instead of $_COOKIE. Inject for testability.",
        "allowlist": ["/Infrastructure/Http/", "/Framework/"],
    },
}


# =============================================================================
# REGELN
# =============================================================================

def p8_forbidden_functions(file_path: str, content: str) -> Optional[dict]:
    """P8.1-P8.5: Nicht-deterministische Funktionen blockieren."""
    if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):
        return None

    for rule_id, config in FORBIDDEN_FUNCTIONS.items():
        # Spezifische Allowlist für diese Regel
        specific_allowlist = config.get("allowlist", [])
        if is_in_allowlist(file_path, specific_allowlist):
            continue

        if re.search(config["pattern"], content):
            return block(rule_id, config["message"])

    return None


def p8_forbidden_global_state(file_path: str, content: str) -> Optional[dict]:
    """P8.6-P8.9: Globaler Zustand blockieren."""
    if is_in_allowlist(file_path, GLOBAL_ALLOWLIST):
        return None

    for rule_id, config in FORBIDDEN_GLOBAL_STATE.items():
        # Spezifische Allowlist für diese Regel
        specific_allowlist = config.get("allowlist", [])
        if is_in_allowlist(file_path, specific_allowlist):
            continue

        if re.search(config["pattern"], content):
            return block(rule_id, config["message"])

    return None


# =============================================================================
# RULE COLLECTION
# =============================================================================

RULES = [
    p8_forbidden_functions,
    p8_forbidden_global_state,
]
← Übersicht