feat(cra): kuratierte Maßnahmen-Bibliothek — alle 40 CRA-Anforderungen belegt
- data/measures_curated.json: 24 deduplizierte, standard-gestützte Maßnahmen (9 bestehende M540-548 + 15 neue M600-614), Volltext + norm_refs + multi-reg covers. Deckt alle 40 CRA-AI-x (vorher nur 17). - cra_annex_i_data lädt die Bibliothek defensiv: MEASURES=Superset, MEASURE_DETAILS (Volltext), mapped_measures aus covers abgeleitet. Fallback = hartkodierte 9. - Mapper: open_measures tragen jetzt name+description+norm_refs (echte Volltexte). - useCRA: merge nutzt Backend-Volltexte statt Demo-Lookup. - Tests: Coverage (40/40) + Volltext im Assessment. Quelle: extern handkuratiert/recherchiert, hier dedupliziert + gemappt. Maschinen- VO/NIS2/IEC-Maßnahmen folgen, sobald deren Spine existiert. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -13,11 +13,21 @@ compliance.api.cra_annex_i_data (pure data, no FastAPI dependency).
|
||||
from dataclasses import dataclass, field, asdict
|
||||
from typing import Optional
|
||||
|
||||
from compliance.api.cra_annex_i_data import ANNEX_I_REQUIREMENTS, MEASURES, DEADLINES
|
||||
from compliance.api.cra_annex_i_data import ANNEX_I_REQUIREMENTS, MEASURES, MEASURE_DETAILS, DEADLINES
|
||||
from compliance.services.cra_security_crosswalk import security_refs_for
|
||||
from compliance.services.cra_prioritizer import prioritize, OBJECTIVES
|
||||
from compliance.services.cra_safety_bridge import build_cross_links
|
||||
|
||||
def _measure_obj(mid: str) -> dict:
|
||||
"""Full curated measure (name/description/norm_refs) for the assessment output,
|
||||
falling back to just the name when only the thin id->name map has it."""
|
||||
d = MEASURE_DETAILS.get(mid)
|
||||
if d:
|
||||
return {"id": mid, "name": d.get("name", ""), "description": d.get("description", ""),
|
||||
"norm_refs": d.get("norm_refs", [])}
|
||||
return {"id": mid, "name": MEASURES.get(mid, ""), "description": MEASURES.get(mid, ""), "norm_refs": []}
|
||||
|
||||
|
||||
_REQ_INDEX = {r["req_id"]: r for r in ANNEX_I_REQUIREMENTS}
|
||||
_SEV_ORDER = {"LOW": 1, "MEDIUM": 2, "HIGH": 3, "CRITICAL": 4}
|
||||
_SEV_BY_RANK = {v: k for k, v in _SEV_ORDER.items()}
|
||||
@@ -249,7 +259,7 @@ def assess_findings(findings: list, weights=None, safety_functions=None) -> CRAA
|
||||
mapped=mapped,
|
||||
by_risk=by_risk,
|
||||
requirements_touched=sorted(reqs_touched),
|
||||
open_measures=[{"id": mid, "description": MEASURES.get(mid, "")} for mid in measure_ids],
|
||||
open_measures=[_measure_obj(mid) for mid in measure_ids],
|
||||
unmapped_findings=unmapped,
|
||||
coverage_pct=round(100.0 * covered / total, 1) if total else 0.0,
|
||||
quick_wins=[m.finding_id for m in mapped if m.quick_win],
|
||||
|
||||
Reference in New Issue
Block a user