Protokoll #4314
| ID | 4314 |
|---|---|
| Zeitstempel | 2025-12-22 09:50:12.323122 |
| Client | root |
| 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 |
| Modell | claude-sonnet-4-20250514 |
| Status | completed |
| Tokens | 4,216 (Input: 0, Output: 0) |
| Dauer | 98 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": "Edit",
"tool_input": {
"file_path": "\/opt\/mcp-servers\/mcp-contracts\/validators\/contract_validator.py",
"old_string": " def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:\n \"\"\"Ermittelt zu prüfende Pfade aus Scope\"\"\"\n if target_path:\n return [target_path]\n\n check_paths = []\n scope = self.contract_data.get(\"contract\", {}).get(\"scope\", {})\n\n if \"includes\" in scope:\n for inc in scope[\"includes\"]:\n # Glob-Pattern zu Pfad konvertieren\n pattern_path = inc.replace(\"*\", \"\").rstrip(\"\/\")\n full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))\n if os.path.exists(full_path):\n check_paths.append(full_path)\n\n return check_paths",
"new_string": " def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:\n \"\"\"Ermittelt zu prüfende Pfade aus Scope (unterstützt alle Formate)\"\"\"\n if target_path:\n return [target_path]\n\n check_paths = []\n contract = self.contract_data.get(\"contract\", {})\n scope = contract.get(\"scope\", {})\n\n # Neues Standard-Format: scope.paths\n paths_list = scope.get(\"paths\", [])\n\n # Legacy-Formate als Fallback\n if not paths_list:\n paths_list = scope.get(\"includes\", []) # Legacy: scope.includes\n if not paths_list:\n paths_list = scope.get(\"applies_to_paths\", []) # Legacy\n if not paths_list:\n # Legacy: applicability.scope\n applicability = self.contract_data.get(\"applicability\", {})\n paths_list = applicability.get(\"scope\", [])\n if isinstance(paths_list, str):\n paths_list = [paths_list]\n\n excludes = scope.get(\"excludes\", [])\n\n for pattern in paths_list:\n # Glob-Pattern expandieren\n full_pattern = os.path.join(self.BASE_PATH, pattern.lstrip(\"\/\"))\n matched = globlib.glob(full_pattern, recursive=True)\n\n if matched:\n for path in matched:\n # Excludes prüfen\n excluded = False\n for excl in excludes:\n excl_pattern = os.path.join(self.BASE_PATH, excl.lstrip(\"\/\"))\n if globlib.fnmatch.fnmatch(path, excl_pattern):\n excluded = True\n break\n if not excluded:\n check_paths.append(path)\n else:\n # Falls kein Match, versuche Basisverzeichnis\n pattern_path = pattern.replace(\"**\", \"\").replace(\"*\", \"\").rstrip(\"\/\")\n full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))\n if os.path.exists(full_path):\n check_paths.append(full_path)\n\n return list(set(check_paths)) # Duplikate entfernen"
}
}
Response
{
"tool_response": {
"filePath": "\/opt\/mcp-servers\/mcp-contracts\/validators\/contract_validator.py",
"oldString": " def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:\n \"\"\"Ermittelt zu prüfende Pfade aus Scope\"\"\"\n if target_path:\n return [target_path]\n\n check_paths = []\n scope = self.contract_data.get(\"contract\", {}).get(\"scope\", {})\n\n if \"includes\" in scope:\n for inc in scope[\"includes\"]:\n # Glob-Pattern zu Pfad konvertieren\n pattern_path = inc.replace(\"*\", \"\").rstrip(\"\/\")\n full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))\n if os.path.exists(full_path):\n check_paths.append(full_path)\n\n return check_paths",
"newString": " def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:\n \"\"\"Ermittelt zu prüfende Pfade aus Scope (unterstützt alle Formate)\"\"\"\n if target_path:\n return [target_path]\n\n check_paths = []\n contract = self.contract_data.get(\"contract\", {})\n scope = contract.get(\"scope\", {})\n\n # Neues Standard-Format: scope.paths\n paths_list = scope.get(\"paths\", [])\n\n # Legacy-Formate als Fallback\n if not paths_list:\n paths_list = scope.get(\"includes\", []) # Legacy: scope.includes\n if not paths_list:\n paths_list = scope.get(\"applies_to_paths\", []) # Legacy\n if not paths_list:\n # Legacy: applicability.scope\n applicability = self.contract_data.get(\"applicability\", {})\n paths_list = applicability.get(\"scope\", [])\n if isinstance(paths_list, str):\n paths_list = [paths_list]\n\n excludes = scope.get(\"excludes\", [])\n\n for pattern in paths_list:\n # Glob-Pattern expandieren\n full_pattern = os.path.join(self.BASE_PATH, pattern.lstrip(\"\/\"))\n matched = globlib.glob(full_pattern, recursive=True)\n\n if matched:\n for path in matched:\n # Excludes prüfen\n excluded = False\n for excl in excludes:\n excl_pattern = os.path.join(self.BASE_PATH, excl.lstrip(\"\/\"))\n if globlib.fnmatch.fnmatch(path, excl_pattern):\n excluded = True\n break\n if not excluded:\n check_paths.append(path)\n else:\n # Falls kein Match, versuche Basisverzeichnis\n pattern_path = pattern.replace(\"**\", \"\").replace(\"*\", \"\").rstrip(\"\/\")\n full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))\n if os.path.exists(full_path):\n check_paths.append(full_path)\n\n return list(set(check_paths)) # Duplikate entfernen",
"originalFile": "\"\"\"Contract Validator - YAML-Validierung und Scope-Prüfung\"\"\"\nimport os\nimport re\nimport sys\nimport glob as globlib\nfrom typing import Optional, Dict, Any, List\n\nimport yaml\n\nsys.path.insert(0, \"\/opt\/mcp-servers\/mcp-contracts\")\nfrom domain.contracts import ContractValidationResult\n\n\nclass ContractValidator:\n \"\"\"Validiert Contracts gegen ihren definierten Scope\"\"\"\n\n BASE_PATH = \"\/var\/www\/dev.campus.systemische-tools.de\"\n\n def __init__(self, contract_data: Dict[str, Any]):\n self.contract_data = contract_data\n self.contract_name = contract_data.get(\"contract\", {}).get(\"name\", \"unknown\")\n\n def validate(self, target_path: Optional[str] = None) -> ContractValidationResult:\n \"\"\"Führt vollständige Validierung durch\"\"\"\n result = ContractValidationResult(\n contract=self.contract_name,\n outcome=\"passed\",\n critical=0,\n major=0,\n minor=0,\n findings=[],\n )\n\n # Scope ermitteln\n check_paths = self._get_check_paths(target_path)\n\n if not check_paths:\n result.findings.append({\n \"type\": \"info\",\n \"message\": \"No paths to validate\",\n })\n return result\n\n # Dateien validieren\n for check_path in check_paths:\n if not os.path.exists(check_path):\n result.critical += 1\n result.findings.append({\n \"type\": \"critical\",\n \"factor\": \"path_existence\",\n \"message\": f\"Path does not exist: {check_path}\",\n })\n continue\n\n if os.path.isdir(check_path):\n self._validate_directory(check_path, result)\n else:\n self._validate_file(check_path, result)\n\n # Outcome bestimmen\n result.outcome = self._determine_outcome(result)\n\n return result\n\n def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:\n \"\"\"Ermittelt zu prüfende Pfade aus Scope\"\"\"\n if target_path:\n return [target_path]\n\n check_paths = []\n scope = self.contract_data.get(\"contract\", {}).get(\"scope\", {})\n\n if \"includes\" in scope:\n for inc in scope[\"includes\"]:\n # Glob-Pattern zu Pfad konvertieren\n pattern_path = inc.replace(\"*\", \"\").rstrip(\"\/\")\n full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))\n if os.path.exists(full_path):\n check_paths.append(full_path)\n\n return check_paths\n\n def _validate_directory(self, dir_path: str, result: ContractValidationResult) -> None:\n \"\"\"Validiert alle Dateien in einem Verzeichnis\"\"\"\n for root, dirs, files in os.walk(dir_path):\n for f in files:\n if f.endswith((\".php\", \".js\", \".css\", \".py\")):\n file_path = os.path.join(root, f)\n self._validate_file(file_path, result)\n\n def _validate_file(self, file_path: str, result: ContractValidationResult) -> None:\n \"\"\"Validiert eine einzelne Datei gegen den Contract\"\"\"\n try:\n with open(file_path, \"r\", encoding=\"utf-8\") as f:\n content = f.read()\n\n # Forbidden elements prüfen\n self._check_forbidden_elements(file_path, content, result)\n\n # Required elements prüfen\n self._check_required_elements(file_path, content, result)\n\n except Exception as e:\n result.minor += 1\n result.findings.append({\n \"type\": \"minor\",\n \"factor\": \"file_read_error\",\n \"file\": file_path,\n \"message\": str(e)[:100],\n })\n\n def _check_forbidden_elements(\n self, file_path: str, content: str, result: ContractValidationResult\n ) -> None:\n \"\"\"Prüft auf verbotene Elemente\"\"\"\n forbidden = self.contract_data.get(\"contract\", {}).get(\"forbidden\", [])\n\n for item in forbidden:\n if isinstance(item, dict):\n element = item.get(\"element\", \"\")\n severity = item.get(\"severity\", \"minor\")\n message = item.get(\"message\", f\"Forbidden element found: {element}\")\n else:\n element = str(item)\n severity = \"minor\"\n message = f\"Forbidden element found: {element}\"\n\n if element and element in content:\n if severity == \"critical\":\n result.critical += 1\n elif severity == \"major\":\n result.major += 1\n else:\n result.minor += 1\n\n result.findings.append({\n \"type\": severity,\n \"factor\": \"forbidden_element\",\n \"file\": file_path,\n \"message\": message,\n })\n\n def _check_required_elements(\n self, file_path: str, content: str, result: ContractValidationResult\n ) -> None:\n \"\"\"Prüft auf erforderliche Elemente\"\"\"\n required = self.contract_data.get(\"contract\", {}).get(\"required\", [])\n\n for item in required:\n if isinstance(item, dict):\n element = item.get(\"element\", \"\")\n severity = item.get(\"severity\", \"major\")\n message = item.get(\"message\", f\"Required element missing: {element}\")\n applies_to = item.get(\"applies_to\", [])\n else:\n element = str(item)\n severity = \"major\"\n message = f\"Required element missing: {element}\"\n applies_to = []\n\n # applies_to prüfen (z.B. nur für bestimmte Dateiendungen)\n if applies_to:\n matches = False\n for pattern in applies_to:\n if file_path.endswith(pattern.lstrip(\"*\")):\n matches = True\n break\n if not matches:\n continue\n\n if element and element not in content:\n if severity == \"critical\":\n result.critical += 1\n elif severity == \"major\":\n result.major += 1\n else:\n result.minor += 1\n\n result.findings.append({\n \"type\": severity,\n \"factor\": \"required_element\",\n \"file\": file_path,\n \"message\": message,\n })\n\n def _determine_outcome(self, result: ContractValidationResult) -> str:\n \"\"\"Bestimmt das Validierungsergebnis basierend auf Violations\"\"\"\n if result.critical > 0:\n return \"rejected\"\n elif result.major > 2:\n return \"revision_required\"\n else:\n return \"passed\"\n\n\ndef run_contract_validation(\n contract_data: Dict[str, Any],\n target_path: Optional[str] = None\n) -> ContractValidationResult:\n \"\"\"Hilfsfunktion für Contract-Validierung\"\"\"\n validator = ContractValidator(contract_data)\n return validator.validate(target_path)\n",
"structuredPatch": [
{
"oldStart": 63,
"oldLines": 22,
"newStart": 63,
"newLines": 55,
"lines": [
" return result",
" ",
" def _get_check_paths(self, target_path: Optional[str] = None) -> List[str]:",
"- \"\"\"Ermittelt zu prüfende Pfade aus Scope\"\"\"",
"+ \"\"\"Ermittelt zu prüfende Pfade aus Scope (unterstützt alle Formate)\"\"\"",
" if target_path:",
" return [target_path]",
" ",
" check_paths = []",
"- scope = self.contract_data.get(\"contract\", {}).get(\"scope\", {})",
"+ contract = self.contract_data.get(\"contract\", {})",
"+ scope = contract.get(\"scope\", {})",
" ",
"- if \"includes\" in scope:",
"- for inc in scope[\"includes\"]:",
"- # Glob-Pattern zu Pfad konvertieren",
"- pattern_path = inc.replace(\"*\", \"\").rstrip(\"\/\")",
"+ # Neues Standard-Format: scope.paths",
"+ paths_list = scope.get(\"paths\", [])",
"+",
"+ # Legacy-Formate als Fallback",
"+ if not paths_list:",
"+ paths_list = scope.get(\"includes\", []) # Legacy: scope.includes",
"+ if not paths_list:",
"+ paths_list = scope.get(\"applies_to_paths\", []) # Legacy",
"+ if not paths_list:",
"+ # Legacy: applicability.scope",
"+ applicability = self.contract_data.get(\"applicability\", {})",
"+ paths_list = applicability.get(\"scope\", [])",
"+ if isinstance(paths_list, str):",
"+ paths_list = [paths_list]",
"+",
"+ excludes = scope.get(\"excludes\", [])",
"+",
"+ for pattern in paths_list:",
"+ # Glob-Pattern expandieren",
"+ full_pattern = os.path.join(self.BASE_PATH, pattern.lstrip(\"\/\"))",
"+ matched = globlib.glob(full_pattern, recursive=True)",
"+",
"+ if matched:",
"+ for path in matched:",
"+ # Excludes prüfen",
"+ excluded = False",
"+ for excl in excludes:",
"+ excl_pattern = os.path.join(self.BASE_PATH, excl.lstrip(\"\/\"))",
"+ if globlib.fnmatch.fnmatch(path, excl_pattern):",
"+ excluded = True",
"+ break",
"+ if not excluded:",
"+ check_paths.append(path)",
"+ else:",
"+ # Falls kein Match, versuche Basisverzeichnis",
"+ pattern_path = pattern.replace(\"**\", \"\").replace(\"*\", \"\").rstrip(\"\/\")",
" full_path = os.path.join(self.BASE_PATH, pattern_path.lstrip(\"\/\"))",
" if os.path.exists(full_path):",
" check_paths.append(full_path)",
" ",
"- return check_paths",
"+ return list(set(check_paths)) # Duplikate entfernen",
" ",
" def _validate_directory(self, dir_path: str, result: ContractValidationResult) -> None:",
" \"\"\"Validiert alle Dateien in einem Verzeichnis\"\"\""
]
}
],
"userModified": false,
"replaceAll": false
}
}