scope_resolver.py
- Pfad:
/var/www/mcp-servers/mcp-contracts/validators/scope_resolver.py - Namespace: -
- Zeilen: 110 | Größe: 3,762 Bytes
- Geändert: 2025-12-28 13:27:02 | 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
- use os
- use glob
- use pathlib.Path
- use typing.Optional
Klassen 1
-
ScopeResolverclass Zeile 9
Code
"""Scope Resolver - Pfad-Aufloesung und Glob-Pattern-Matching."""
import os
import glob as globlib
from pathlib import Path
from typing import Optional
class ScopeResolver:
"""Loest Pfade und Glob-Patterns auf."""
def __init__(self, base_path: str = "/var/www/dev.campus.systemische-tools.de"):
self.base_path = base_path
def resolve_paths(
self,
scope: dict,
target_path: Optional[str] = None,
legacy_applicability: Optional[dict] = None,
) -> list[str]:
"""
Ermittelt zu pruefende Pfade aus Scope.
Args:
scope: Contract scope dict mit paths/includes/excludes
target_path: Optional spezifischer Pfad
legacy_applicability: Legacy applicability dict
Returns:
Liste der aufgeloesten Pfade (dedupliziert)
"""
if target_path:
return [target_path]
paths_list = self._get_paths_list(scope, legacy_applicability)
excludes = scope.get("excludes", [])
check_paths = []
for pattern in paths_list:
matched = self._expand_glob(pattern)
for path in matched:
if not self._is_excluded(path, excludes):
check_paths.append(path)
return list(set(check_paths))
def _get_paths_list(
self, scope: dict, legacy_applicability: Optional[dict] = None
) -> list[str]:
"""Extrahiert Pfade aus verschiedenen Contract-Formaten."""
# Neues Standard-Format
paths_list = scope.get("paths", [])
# Legacy-Formate als Fallback
if not paths_list:
paths_list = scope.get("includes", [])
if not paths_list:
paths_list = scope.get("applies_to_paths", [])
if not paths_list and legacy_applicability:
paths_list = legacy_applicability.get("scope", [])
if isinstance(paths_list, str):
paths_list = [paths_list]
return paths_list
def _expand_glob(self, pattern: str) -> list[str]:
"""Expandiert Glob-Pattern zu konkreten Pfaden."""
full_pattern = os.path.join(self.base_path, pattern.lstrip("/"))
matched = globlib.glob(full_pattern, recursive=True)
if matched:
return matched
# Fallback: Basisverzeichnis wenn kein Match
pattern_path = pattern.replace("**", "").replace("*", "").rstrip("/")
full_path = os.path.join(self.base_path, pattern_path.lstrip("/"))
if os.path.exists(full_path):
return [full_path]
return []
def _is_excluded(self, path: str, excludes: list[str]) -> bool:
"""Prueft ob Pfad durch Exclude-Pattern ausgeschlossen wird."""
for excl in excludes:
excl_pattern = os.path.join(self.base_path, excl.lstrip("/"))
if globlib.fnmatch.fnmatch(path, excl_pattern):
return True
return False
def file_matches_pattern(self, file_path: str, pattern: str) -> bool:
"""Prueft ob Datei zum Glob-Pattern passt."""
rel_path = file_path.replace(self.base_path, "").lstrip("/")
if "**" in pattern:
parts = pattern.split("**")
if len(parts) == 2:
prefix = parts[0].rstrip("/")
suffix = parts[1].lstrip("/")
if prefix and not rel_path.startswith(prefix.lstrip("/")):
return False
if suffix and not globlib.fnmatch.fnmatch(rel_path, f"*{suffix}"):
return False
return True
elif "*" in pattern:
return globlib.fnmatch.fnmatch(rel_path, pattern)
else:
return pattern in rel_path
return True