828230746e
Frontend (CRA/Cyber-Tab): - Erklär-Zwischensätze je Ebene (Befund -> CRA-Anforderung -> Best-Practice- Standard -> Maßnahmen) + "So liest du einen Befund"-Legende. - Kuratierte M-Maßnahmen und atom-grain "Regulatorische Breite" in EINE Sektion "Maßnahmen (wählbar)" zusammengeführt (statt zwei konkurrierender Listen). - Standalone "Empfohlene Maßnahmen (Sollzustand)" entfernt (jetzt je Befund). Backend: - Atom-Controls-Query liefert jetzt cpl.source_article (Artikel/Anhang/Erwägungs- grund-Anker) zusätzlich zu source_regulation; via LATERAL-Join. - enrich_findings_with_breadth trägt source_article in regulatory_breadth. - Daten waren schon ingestiert (682/691 CRA-Atome haben source_article) — wurden nur nicht selektiert/angezeigt. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
"""Pin the CRA-AI -> network_security sub_topic map (DB enrichment verified live)."""
|
|
from compliance.services import cra_use_case_controls
|
|
from compliance.services.cra_use_case_controls import (
|
|
enrich_findings_with_breadth,
|
|
subtopic_for,
|
|
)
|
|
from compliance.api.cra_annex_i_data import ANNEX_I_REQUIREMENTS
|
|
|
|
# Exact atom-grain sub_topic keys (verified against the live atom_classification).
|
|
_VALID = {
|
|
"access_control", "authentication", "cryptography", "network_segmentation",
|
|
"logging_monitoring", "supply_chain_security", "vulnerability_management",
|
|
"incident_response", "secure_development", "data_protection",
|
|
}
|
|
|
|
|
|
def test_every_requirement_maps_to_a_valid_subtopic():
|
|
for req in ANNEX_I_REQUIREMENTS:
|
|
st = subtopic_for(req["req_id"])
|
|
assert st in _VALID, "{} -> {}".format(req["req_id"], st)
|
|
|
|
|
|
class _FakeControlsService:
|
|
"""Stands in for UseCaseControlsService: returns one atom control per call,
|
|
carrying the legal anchor (source_article) the real atom query now selects."""
|
|
|
|
def __init__(self, db):
|
|
pass
|
|
|
|
def controls_for_use_case(self, use_case, sub_topic=None, limit=3):
|
|
return {"controls": [{
|
|
"control_id": "AI-{}-{}".format(use_case, sub_topic),
|
|
"title": "Test obligation",
|
|
"source_regulation": "Cyber Resilience Act (CRA)",
|
|
"source_article": "Artikel 13",
|
|
"severity": "high",
|
|
}]}
|
|
|
|
|
|
def test_breadth_carries_source_article(monkeypatch):
|
|
monkeypatch.setattr(
|
|
cra_use_case_controls, "UseCaseControlsService", _FakeControlsService,
|
|
)
|
|
mapped = [{"primary_requirement": "CRA-AI-8"}] # -> authentication sub_topic
|
|
enrich_findings_with_breadth(mapped, db=None)
|
|
breadth = mapped[0]["regulatory_breadth"]
|
|
assert breadth, "expected breadth controls"
|
|
assert all("source_article" in c for c in breadth)
|
|
assert any(c["source_article"] == "Artikel 13" for c in breadth)
|