feat(cra): Pull-Flow — Findings vom Scanner-MCP ziehen + assessen
CI / nodejs-build (push) Successful in 3m12s
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 39s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 15s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 12s
CI / validate-canonical-controls (push) Successful in 12s
CI / loc-budget (push) Successful in 25s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped

(2) Wir als MCP-Client zum compliance-scanner-agent:
- scanner_mcp_client.fetch_findings(): streamablehttp_client + ClientSession →
  list_findings, parst JSON-Text zu Finding-Dicts. Config via SCANNER_MCP_URL/
  SCANNER_MCP_TOKEN (unset = leer → UI behält Demo). Transport lazy-importiert.
- POST /v1/cra/assess-from-scanner: rohe Scanner-Dicts → toleranter Mapper
  (behält scan_type/cvss_score/file_path) → assess + Breadth.
- Tests: parse_findings_text + no-config-Pfad.

Live-Verdrahtung der UI folgt, sobald ihr Endpoint+Token stehen (dann nur Env
setzen + useCRA auf /assess-from-scanner zeigen).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-15 19:05:44 +02:00
parent e7c3cd7cee
commit e140477c0b
4 changed files with 129 additions and 0 deletions
@@ -15,6 +15,7 @@ from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from compliance.services.cra_finding_mapper import assess_findings_payload
from compliance.services.scanner_mcp_client import fetch_findings
from compliance.services.cra_snapshot_store import save_snapshot, list_snapshots, get_snapshot
from compliance.services.cra_use_case_controls import enrich_findings_with_breadth
from compliance.services.cra_component_findings import findings_from_components
@@ -97,6 +98,42 @@ async def assess(body: AssessRequest):
return _assess_enriched(body)
class ScannerPullRequest(BaseModel):
repo_id: Optional[str] = None
severity: Optional[str] = None
scanner_url: Optional[str] = None # override SCANNER_MCP_URL
token: Optional[str] = None # override SCANNER_MCP_TOKEN
weights: Optional[Dict[str, str]] = None
safety_functions: Optional[List[SafetyFunctionIn]] = None
@router.post("/assess-from-scanner")
async def assess_from_scanner(body: ScannerPullRequest):
"""Pull-flow: fetch findings from the scanner's MCP, then assess.
Raw scanner finding dicts go straight to the tolerant mapper (keeps
scan_type/cvss_score/file_path). Returns empty assessment if no scanner is
configured — the frontend then keeps its demo scenario.
"""
findings = await fetch_findings(
repo_id=body.repo_id, severity=body.severity,
base_url=body.scanner_url, token=body.token,
)
payload = {
"findings": findings,
"weights": body.weights,
"safety_functions": [s.model_dump() for s in body.safety_functions] if body.safety_functions else None,
}
result = assess_findings_payload(payload)
db = SessionLocal()
try:
enrich_findings_with_breadth(result.get("mapped", []), db)
finally:
db.close()
result["source"] = {"scanner": True, "pulled": len(findings)}
return result
@router.post("/projects/{project_id}/assess-snapshot")
async def assess_snapshot(project_id: str, body: AssessRequest, tenant_id: str = Depends(get_tenant_id)):
"""Run the assessment and persist it as a versioned snapshot (running system)."""