feat(mcp): HTTP+Bearer CRA-MCP-Server für den Repo-Scanner + Finding-Adapter
Register-Flow für compliance-scanner-agent (anderes Team, Rust): deren MCP-Client (McpServerConfig) erwartet Streamable HTTP + Bearer — unser MCP war stdio/ohne Auth. - server.py auf FastMCP umgestellt: Tools cra_assess_findings + cra_list_requirements, Dual-Transport (stdio default; Streamable HTTP wenn MCP_PORT gesetzt), Bearer-Gate via CRA_MCP_TOKEN. - ScannerFinding.from_dict tolerant für ihr Finding-Schema (_id/fingerprint, scan_type→category, cvss_score→cvss, file_path→location, severity info→low). - Eigenständiger docker-compose-Dienst bp-compliance-mcp (Port 8099, pure/kein DB, isoliert von der Haupt-API) + Hetzner-amd64-Override. - Tests: test_cra_scanner_adapter, test_mcp_server (Bearer-Gate + Tool-Registry). Pull-Flow (wir holen ihre Findings über ihren MCP) + öffentliches nginx-Routing folgen separat (brauchen ihren Endpoint/Token). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -73,15 +73,23 @@ class ScannerFinding:
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: dict) -> "ScannerFinding":
|
||||
# Tolerant to the compliance-scanner-agent Finding shape (Rust/Mongo):
|
||||
# _id/fingerprint, scan_type, cvss_score, file_path, severity incl. "info".
|
||||
raw_id = d.get("id") or d.get("finding_id") or d.get("_id") or d.get("fingerprint") or ""
|
||||
if isinstance(raw_id, dict): # Mongo extended JSON {"$oid": "..."}
|
||||
raw_id = raw_id.get("$oid") or ""
|
||||
sev = (d.get("severity") or "").lower()
|
||||
if sev == "info": # scanner has 5 levels; we use 4
|
||||
sev = "low"
|
||||
return cls(
|
||||
id=str(d.get("id") or d.get("finding_id") or ""),
|
||||
id=str(raw_id),
|
||||
title=d.get("title", "") or d.get("name", ""),
|
||||
description=d.get("description", "") or d.get("detail", ""),
|
||||
category=d.get("category", "") or d.get("type", ""),
|
||||
category=d.get("category", "") or d.get("type", "") or d.get("scan_type", "") or d.get("scanner", ""),
|
||||
cwe=str(d.get("cwe", "") or ""),
|
||||
severity=d.get("severity", "") or "",
|
||||
cvss=d.get("cvss"),
|
||||
location=d.get("location", "") or d.get("path", ""),
|
||||
severity=sev,
|
||||
cvss=d.get("cvss") if d.get("cvss") is not None else d.get("cvss_score"),
|
||||
location=d.get("location", "") or d.get("path", "") or d.get("file_path", ""),
|
||||
safety_impact=bool(d.get("safety_impact", False)),
|
||||
exploited=bool(d.get("exploited", False)),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user