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
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:
@@ -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)."""
|
||||
|
||||
Reference in New Issue
Block a user