feat(cra): SBOM- + DAST-Findings aus dem Scanner-MCP konsumieren
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 6s
CI / validate-canonical-controls (push) Successful in 10s
CI / loc-budget (push) Successful in 20s
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) Has been skipped
CI / test-go (push) Successful in 1m4s
CI / iace-gt-coverage (push) Successful in 15s
CI / test-python-backend (push) Successful in 24s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Successful in 6s
CI / validate-canonical-controls (push) Successful in 10s
CI / loc-budget (push) Successful in 20s
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) Has been skipped
CI / test-go (push) Successful in 1m4s
CI / iace-gt-coverage (push) Successful in 15s
CI / test-python-backend (push) Successful in 24s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
Sharangs compliance-scanner-agent exponiert SBOM (sbom_vuln_report) + DAST (list_dast_findings) als eigene MCP-Tools (nicht via list_findings). Neuer fetch_all_findings(repo_id) zieht list_findings + SBOM + DAST in EINER MCP-Session und normalisiert ins Finding-Schema: - SBOM: ein Finding pro verwundbarem Paket (nicht pro CVE), cwe=CWE-1395 -> deterministisch CRA-AI-22 (robust gegen Paketnamen wie "sqlite"). - DAST: cwe/endpoint/vuln_type uebernommen -> Mapping via cwe/keywords. assess-from-scanner nutzt fetch_all_findings + liefert source.breakdown (code/sbom/dast). DAST hat im MCP keinen repo_id-Filter -> dast_repo_scoped:false (deployment-weit, transparent geflaggt). Echte MCP-Daten: Kitchenasty 58 code + 35 sbom + 81 dast -> 174 gemappt (Coverage 94,3%, alle 35 SBOM -> CRA-AI-22). Enthaelt zusaetzlich das Qdrant->Prod-Kopierскript (#42, verbatim macmini->prod). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""SBOM/DAST normalization from the scanner MCP -> CRA finding shape + mapping.
|
||||
|
||||
Shapes pinned from the live MCP (sbom_vuln_report / list_dast_findings, 2026-06-18).
|
||||
"""
|
||||
import json
|
||||
|
||||
from compliance.services.scanner_mcp_client import normalize_sbom_report, normalize_dast
|
||||
from compliance.services.cra_finding_mapper import ScannerFinding, map_finding
|
||||
|
||||
SBOM = json.dumps({
|
||||
"repo_id": "r1",
|
||||
"vulnerable_packages_count": 1,
|
||||
"total_vulnerabilities": 3,
|
||||
"packages": [
|
||||
{"name": "dompurify", "version": "3.3.3", "package_manager": "npm",
|
||||
"license": "MIT", "vulnerabilities": [
|
||||
{"id": "GHSA-39q2", "source": "osv", "severity": None},
|
||||
{"id": "GHSA-39q2", "source": "osv", "severity": None}, # dup
|
||||
{"id": "GHSA-76mc", "source": "osv", "severity": "high"}]},
|
||||
{"name": "clean-pkg", "version": "1.0", "package_manager": "npm",
|
||||
"vulnerabilities": []}, # no vulns -> skipped
|
||||
],
|
||||
})
|
||||
|
||||
DAST = json.dumps([
|
||||
{"_id": {"$oid": "abc123"}, "vuln_type": "security_misconfiguration",
|
||||
"title": "SQL backup exposure: /backup.sql", "description": "Sensitive resource accessible.",
|
||||
"severity": "high", "cwe": "CWE-16", "endpoint": "https://demo.x/backup.sql",
|
||||
"method": "GET", "exploitable": True},
|
||||
])
|
||||
|
||||
|
||||
class TestSbom:
|
||||
def test_one_finding_per_vulnerable_package(self):
|
||||
out = normalize_sbom_report(SBOM)
|
||||
assert len(out) == 1 # clean-pkg skipped
|
||||
f = out[0]
|
||||
assert f["scan_type"] == "dependency"
|
||||
assert f["cwe"] == "CWE-1395"
|
||||
assert f["location"] == "npm:dompurify@3.3.3"
|
||||
assert f["severity"] == "high" # escalated from the one graded vuln
|
||||
assert "GHSA-39q2" in f["description"] and "GHSA-76mc" in f["description"]
|
||||
|
||||
def test_maps_to_dependency_requirement_even_with_keyword_in_name(self):
|
||||
# CWE path dominates → CRA-AI-22, not CRA-AI-20 from a "sql"-like name
|
||||
out = normalize_sbom_report(json.dumps({
|
||||
"repo_id": "r", "packages": [
|
||||
{"name": "sqlite3", "version": "5.0", "package_manager": "npm",
|
||||
"vulnerabilities": [{"id": "CVE-x", "severity": "medium"}]}]}))
|
||||
m = map_finding(ScannerFinding.from_dict(out[0]))
|
||||
assert m.primary_requirement == "CRA-AI-22"
|
||||
|
||||
def test_bad_json(self):
|
||||
assert normalize_sbom_report("not json") == []
|
||||
assert normalize_sbom_report("{}") == []
|
||||
|
||||
|
||||
class TestDast:
|
||||
def test_normalizes_dast_finding(self):
|
||||
out = normalize_dast(DAST)
|
||||
assert len(out) == 1
|
||||
f = out[0]
|
||||
assert f["scan_type"] == "dast"
|
||||
assert f["cwe"] == "CWE-16"
|
||||
assert f["location"] == "https://demo.x/backup.sql"
|
||||
assert f["exploited"] is True
|
||||
assert "security_misconfiguration" in f["description"]
|
||||
|
||||
def test_dast_maps_via_cwe(self):
|
||||
out = normalize_dast(DAST)
|
||||
m = map_finding(ScannerFinding.from_dict(out[0]))
|
||||
assert m.primary_requirement == "CRA-AI-1" # CWE-16 -> secure config
|
||||
assert m.finding_id == "abc123" # _id.$oid extracted
|
||||
|
||||
def test_empty(self):
|
||||
assert normalize_dast("[]") == []
|
||||
assert normalize_dast("not json") == []
|
||||
Reference in New Issue
Block a user