feat(cra): hardware path — derive cyber findings from networked components

For hardware CE projects (no repo) each networked component (controller/hmi/
gateway/drive/remote_access/sensor) yields typical ICS vulnerability CLASSES
(real CWE + "CISA-ICS — product-specific check" framing, NO fabricated CVEs);
they flow through the same CRA engine. /assess accepts components[]. MappedFinding
now echoes title/location/cwe so the response is self-contained for any finding
source. Live CISA-ICS/NVD per-product CVE lookup is the later enrichment.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-14 12:37:22 +02:00
parent 398eaf3c36
commit 437c2c8fa1
4 changed files with 115 additions and 3 deletions
@@ -0,0 +1,28 @@
"""Tests for the hardware path: components -> cyber findings -> assessment."""
from compliance.services.cra_component_findings import findings_from_components
from compliance.services.cra_finding_mapper import ScannerFinding, assess_findings
def test_networked_controller_yields_cwe_findings():
fs = findings_from_components([{"name": "SPS-1", "component_class": "controller", "networked": True}])
assert len(fs) >= 1
assert all(f["cwe"] for f in fs)
assert all("SPS-1" in f["location"] for f in fs)
assert all("CISA-ICS" in f["source"] for f in fs) # honest framing, no fabricated CVE
def test_non_networked_component_yields_nothing():
assert findings_from_components([{"name": "X", "component_class": "controller", "networked": False}]) == []
def test_unknown_class_yields_nothing():
assert findings_from_components([{"name": "Y", "component_class": "unknown", "networked": True}]) == []
def test_component_findings_flow_through_assessment_with_echoed_title():
fs = findings_from_components([{"name": "HMI", "component_class": "hmi", "networked": True}])
a = assess_findings([ScannerFinding.from_dict(f) for f in fs])
assert a.findings_total == len(fs)
assert all(m.title for m in a.mapped) # title echoed -> self-contained response
assert all(m.location == "HMI" for m in a.mapped)
assert any(m.primary_requirement == "CRA-AI-8" for m in a.mapped) # default creds -> auth