feat(cra): cyber-meets-safety bridge as real logic (step 2)
Deterministic bridge (cra_safety_bridge.py): a cyber finding's attack capability (remote_actuation / code_tampering / integrity_loss / auth_bypass, derived from its CRA category) is matched against what each CE safety function is vulnerable to. A match re-opens the mitigated hazard, flags the finding safety_impact (which floors it to P0), and produces the cross-link. Endpoint accepts safety_functions; frontend passes the project's safety functions and renders the LIVE cross-links (no more hardcode). Safety functions are demo input now; come from the CE risk assessment in production. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
"""Tests for the deterministic cyber-meets-safety bridge."""
|
||||
from compliance.services.cra_finding_mapper import ScannerFinding, assess_findings
|
||||
|
||||
SF_ACTUATION = {"name": "Zweihandschaltung Hubwerk", "hazard": "Quetschen",
|
||||
"original_measure": "PL d", "kind": "prevent_unexpected_actuation"}
|
||||
SF_INTEGRITY = {"name": "Ueberlastsicherung", "hazard": "Lastabsturz",
|
||||
"original_measure": "Lastmomentbegrenzer", "kind": "signal_integrity"}
|
||||
|
||||
|
||||
def test_default_password_defeats_actuation_safety_function():
|
||||
a = assess_findings(
|
||||
[ScannerFinding(id="pw", title="default password", cwe="CWE-259", severity="critical")],
|
||||
safety_functions=[SF_ACTUATION])
|
||||
assert len(a.cross_links) == 1
|
||||
assert "pw" in a.cross_links[0]["cyber_finding_ids"]
|
||||
assert a.mapped[0].safety_impact is True
|
||||
assert a.mapped[0].priority_tier == "P0"
|
||||
|
||||
|
||||
def test_unencrypted_transit_defeats_signal_integrity_and_floors_low_severity():
|
||||
a = assess_findings(
|
||||
[ScannerFinding(id="mqtt", title="cleartext MQTT", cwe="CWE-319", severity="low")],
|
||||
safety_functions=[SF_INTEGRITY])
|
||||
assert len(a.cross_links) == 1
|
||||
assert a.mapped[0].priority_tier == "P0" # safety_impact floors a low-severity finding
|
||||
|
||||
|
||||
def test_logging_finding_does_not_defeat_actuation():
|
||||
a = assess_findings(
|
||||
[ScannerFinding(id="log", title="no security logging", cwe="CWE-778", severity="high")],
|
||||
safety_functions=[SF_ACTUATION])
|
||||
assert a.cross_links == []
|
||||
assert a.mapped[0].safety_impact is False
|
||||
|
||||
|
||||
def test_no_safety_functions_means_no_cross_links():
|
||||
a = assess_findings([ScannerFinding(id="pw", title="default password", cwe="CWE-259", severity="critical")])
|
||||
assert a.cross_links == []
|
||||
|
||||
|
||||
def test_explicit_vulnerable_to_overrides_kind():
|
||||
sf = {"name": "X", "hazard": "H", "vulnerable_to": ["integrity_loss"]}
|
||||
a = assess_findings(
|
||||
[ScannerFinding(id="mqtt", title="cleartext", cwe="CWE-319", severity="high")],
|
||||
safety_functions=[sf])
|
||||
assert len(a.cross_links) == 1
|
||||
Reference in New Issue
Block a user