diff --git a/ai-compliance-sdk/data/control_mappings/cra_nist.jsonl b/ai-compliance-sdk/data/control_mappings/cra_nist.jsonl index 2c0f0ccd..93fa8e8e 100644 --- a/ai-compliance-sdk/data/control_mappings/cra_nist.jsonl +++ b/ai-compliance-sdk/data/control_mappings/cra_nist.jsonl @@ -2,7 +2,7 @@ // Reviewt 2026-06-25 (benjamin): 3 accepted, mapping_type=primary_implementation (kanonische Primaer-Control je Anforderung). // Heimat der OWASP-Rejects (2)(e)/(2)(l)/(2)(i): dort war OWASP nicht der Zielstandard ("Mapping ueber NIST/BSI erforderlich"). // related-Controls (SC-3(3), RA-5, AC-6, SI-16, ...) folgen separat als mapping_type=supports — hier nur der kanonische Einstieg. -// obligation_id ADOPTIERT (2026-06-25, Registry-Handoff #4): SI-7->signed_update_integrity, SI-2->provide_security_updates, CM-7->remote_access_attack_surface_min. Join jetzt exakt (nicht citation_unit). CM-7 ist breiter als remote_access — Registry waehlte die vorhandene Obligation; Verfeinerung via Capability/cross_domain spaeter. -{"source_norm": "CRA Annex I Part I (2)(e) — Integritaet", "source_role": "operational_requirement", "target_framework": "NIST SP 800-53", "target_control": "SI-7", "mapping_type": "primary_implementation", "mapping_status": "accepted", "provenance": "human_curated", "rationale": "NIST SI-7 = Software, Firmware, and Information Integrity — kanonische Integritaetskontrolle (Signaturpruefung, Manipulationserkennung).", "reviewed_by": "benjamin", "review_date": "2026-06-25", "review_reason": "Primaere Implementierung der CRA-Integritaetsanforderung; OWASP war hier kein passender Treffer. Related (spaeter, supports): SA-10, CM-14.", "version": "2026-06-25", "obligation_id": "signed_update_integrity"} +// obligation_id (Registry-Handoff #4 adoptiert, #6 auf CORE re-pointet 2026-06-26): SI-7->software_integrity_protection (CORE (2)(f)), SI-2->provide_security_updates, CM-7->attack_surface_minimization (CORE (2)(j)). Join exakt. Die domaenen-scoped IDs (signed_update_integrity, remote_access_attack_surface_min) bleiben gueltige Obligations und zeigen per specializes->CORE auf diese Ziele. +{"source_norm": "CRA Annex I Part I (2)(e) — Integritaet", "source_role": "operational_requirement", "target_framework": "NIST SP 800-53", "target_control": "SI-7", "mapping_type": "primary_implementation", "mapping_status": "accepted", "provenance": "human_curated", "rationale": "NIST SI-7 = Software, Firmware, and Information Integrity — kanonische Integritaetskontrolle (Signaturpruefung, Manipulationserkennung).", "reviewed_by": "benjamin", "review_date": "2026-06-25", "review_reason": "Primaere Implementierung der CRA-Integritaetsanforderung; OWASP war hier kein passender Treffer. Related (spaeter, supports): SA-10, CM-14.", "version": "2026-06-25", "obligation_id": "software_integrity_protection"} {"source_norm": "CRA Annex I Part I (2)(l) — Sichere Updates", "source_role": "operational_requirement", "target_framework": "NIST SP 800-53", "target_control": "SI-2", "mapping_type": "primary_implementation", "mapping_status": "accepted", "provenance": "human_curated", "rationale": "NIST SI-2 = Flaw Remediation — kanonische Update-/Patch-Kontrolle.", "reviewed_by": "benjamin", "review_date": "2026-06-25", "review_reason": "Primaere Implementierung der CRA-Update-Anforderung. Related (spaeter, supports): RA-5, CM-3, SA-11.", "version": "2026-06-25", "obligation_id": "provide_security_updates"} -{"source_norm": "CRA Annex I Part I (2)(i) — Angriffsflaeche minimieren", "source_role": "operational_requirement", "target_framework": "NIST SP 800-53", "target_control": "CM-7", "mapping_type": "primary_implementation", "mapping_status": "accepted", "provenance": "human_curated", "rationale": "NIST CM-7 = Least Functionality — Deaktivierung nicht benoetigter Ports/Dienste/Funktionen.", "reviewed_by": "benjamin", "review_date": "2026-06-25", "review_reason": "CM-7 als Primaer-Control fuer Angriffsflaeche (nicht SC-3(3)). Related (spaeter, supports): SC-3(3), AC-6, SI-16.", "version": "2026-06-25", "obligation_id": "remote_access_attack_surface_min"} +{"source_norm": "CRA Annex I Part I (2)(i) — Angriffsflaeche minimieren", "source_role": "operational_requirement", "target_framework": "NIST SP 800-53", "target_control": "CM-7", "mapping_type": "primary_implementation", "mapping_status": "accepted", "provenance": "human_curated", "rationale": "NIST CM-7 = Least Functionality — Deaktivierung nicht benoetigter Ports/Dienste/Funktionen.", "reviewed_by": "benjamin", "review_date": "2026-06-25", "review_reason": "CM-7 als Primaer-Control fuer Angriffsflaeche (nicht SC-3(3)). Related (spaeter, supports): SC-3(3), AC-6, SI-16.", "version": "2026-06-25", "obligation_id": "attack_surface_minimization"} diff --git a/ai-compliance-sdk/data/evidence_requirements/nist_evidence.jsonl b/ai-compliance-sdk/data/evidence_requirements/nist_evidence.jsonl index 16d37e3e..7cd78773 100644 --- a/ai-compliance-sdk/data/evidence_requirements/nist_evidence.jsonl +++ b/ai-compliance-sdk/data/evidence_requirements/nist_evidence.jsonl @@ -2,9 +2,9 @@ // WICHTIG: evidence_type ist FRAMEWORK-AGNOSTISCH (geteilter Katalog config_export/test_report/repo_scan/sbom/...) — // dieselben Typen tragen CRA, NIST, ISO 27001, IEC 62443, BSI. (framework, control) ist nur der Verweis, nicht der Typ. // Stand 2026-06-25, Basis: die 3 accepted CRA->NIST primary_implementation-Mappings (SI-7 Integritaet, SI-2 Updates, CM-7 Angriffsflaeche). +{"framework": "NIST SP 800-53", "control": "SI-7", "evidence_type": "sbom", "evidence_source": "ci", "freshness_requirement": "per_release", "required": true, "rationale": "SBOM weist die Integritaet/Herkunft der Software-Bestandteile nach (bekannte, unmanipulierte Komponenten).", "version": "2026-06-25"} {"framework": "NIST SP 800-53", "control": "SI-7", "evidence_type": "config_export", "evidence_source": "github", "freshness_requirement": "per_release", "required": true, "rationale": "Secure-Boot-/Code-Signing-Konfiguration als Nachweis der Integritaetspruefung.", "version": "2026-06-25"} -{"framework": "NIST SP 800-53", "control": "SI-7", "evidence_type": "test_report", "evidence_source": "ci", "freshness_requirement": "per_release", "required": true, "rationale": "Signatur-/Integritaets-Verifikationstest (CI) belegt funktionierende Manipulationserkennung.", "version": "2026-06-25"} {"framework": "NIST SP 800-53", "control": "SI-2", "evidence_type": "config_export", "evidence_source": "github", "freshness_requirement": "per_release", "required": true, "rationale": "Konfiguration des sicheren Update-/Patch-Mechanismus (signierte/automatische Updates) als technischer Nachweis.", "version": "2026-06-25"} {"framework": "NIST SP 800-53", "control": "SI-2", "evidence_type": "test_report", "evidence_source": "ci", "freshness_requirement": "per_release", "required": true, "rationale": "Update-/Patch-Verifikationstest (CI) belegt, dass Sicherheitsupdates greifen.", "version": "2026-06-25"} {"framework": "NIST SP 800-53", "control": "CM-7", "evidence_type": "config_export", "evidence_source": "github", "freshness_requirement": "per_release", "required": true, "rationale": "Konfiguration deaktivierter Ports/Dienste/Funktionen als Nachweis minimierter Angriffsflaeche.", "version": "2026-06-25"} -{"framework": "NIST SP 800-53", "control": "CM-7", "evidence_type": "repo_scan", "evidence_source": "scanner", "freshness_requirement": "quarterly", "required": false, "rationale": "Angriffsflaechen-Scan (offene Ports/Dienste) — vertiefend, nicht Pflicht je Release.", "version": "2026-06-25"} +{"framework": "NIST SP 800-53", "control": "CM-7", "evidence_type": "repo_scan", "evidence_source": "scanner", "freshness_requirement": "per_release", "required": true, "rationale": "Angriffsflaechen-Scan (offene Ports/Dienste) als Nachweis tatsaechlich minimierter Angriffsflaeche.", "version": "2026-06-25"} diff --git a/ai-compliance-sdk/internal/api/handlers/compliance_graph_handlers_test.go b/ai-compliance-sdk/internal/api/handlers/compliance_graph_handlers_test.go index 4d7da14b..360d5990 100644 --- a/ai-compliance-sdk/internal/api/handlers/compliance_graph_handlers_test.go +++ b/ai-compliance-sdk/internal/api/handlers/compliance_graph_handlers_test.go @@ -49,6 +49,8 @@ func TestObligationStatus(t *testing.T) { {"unknown id -> unknown_obligation", "?obligation_id=does_not_exist", http.StatusOK, "unknown_obligation", false}, {"mapped (OWASP V6) -> not_assessed", "?obligation_id=user_authentication_required", http.StatusOK, "not_assessed", true}, {"NIST adopted (SI-2) -> not_assessed", "?obligation_id=provide_security_updates", http.StatusOK, "not_assessed", true}, + {"CORE attack_surface_minimization -> CM-7", "?obligation_id=attack_surface_minimization", http.StatusOK, "not_assessed", true}, + {"CORE software_integrity_protection -> SI-7", "?obligation_id=software_integrity_protection", http.StatusOK, "not_assessed", true}, {"in registry, no control -> unmapped", "?obligation_id=sbom_creation", http.StatusOK, "unmapped", false}, } for _, tt := range tests { @@ -93,3 +95,39 @@ func TestObligationStatus_NoFulfillmentClaim(t *testing.T) { } } } + +// Pin the curated evidence_required set per NIST obligation. A required:false row silently +// drops from evidence_required, which the table test above (control-count only) would miss. +func TestObligationStatus_NISTEvidenceTypes(t *testing.T) { + r := newComplianceGraphTestRouter(t) + want := map[string][]string{ + "attack_surface_minimization": {"config_export", "repo_scan"}, + "software_integrity_protection": {"sbom", "config_export"}, + "provide_security_updates": {"config_export", "test_report"}, + } + for ob, exp := range want { + _, resp := getObligationStatus(t, r, "?obligation_id="+ob) + if len(resp.Controls) != 1 { + t.Fatalf("%s: want 1 control, got %d", ob, len(resp.Controls)) + } + if got := resp.Controls[0].EvidenceRequired; !sameStringSet(got, exp) { + t.Errorf("%s evidence_required = %v, want %v", ob, got, exp) + } + } +} + +func sameStringSet(a, b []string) bool { + if len(a) != len(b) { + return false + } + m := make(map[string]bool, len(a)) + for _, x := range a { + m[x] = true + } + for _, x := range b { + if !m[x] { + return false + } + } + return true +} diff --git a/obligations/controls_for_obligation_mapping.json b/obligations/controls_for_obligation_mapping.json index adac66d4..d3b3c98c 100644 --- a/obligations/controls_for_obligation_mapping.json +++ b/obligations/controls_for_obligation_mapping.json @@ -68,9 +68,9 @@ "framework": "NIST SP 800-53", "control": "SI-7", "source_norm": "CRA Annex I Part I (2)(e) — Integritaet", "citation_unit": "Annex I (2)(e)", "family": "integrity", "mapping_type": "primary_implementation", - "proposed_obligation_id": "signed_update_integrity", + "proposed_obligation_id": "software_integrity_protection", "mapping_method": "semantic", - "mapping_note": "NIST SI-7 = Software/Firmware/Information Integrity (Signaturpruefung, Manipulationserkennung, Secure Boot, Runtime-Integritaet). Naechster vorhandener Treffer (93-Stand): signed_update_integrity (updates-Familie, Annex I (1)(3)(f)) — deckt aber NUR Update-Signatur. SI-7 ist BREITER (gesamte Produkt-Integritaet). Falls keine generische Integritaets-Obligation existiert: neue noetig (Vorschlag software_integrity_protection); sonst SI-7 primary_implementation fuer signed_update_integrity (update-scoped) + supports fuers Breitere. NICHT log_integrity_immutability (Audit-Log-Schutz, andere Ebene)." + "mapping_note": "NIST SI-7 = Software/Firmware/Information Integrity (gesamte Produkt-Integritaet). #6 ADOPTIERT (2026-06-26) auf CORE software_integrity_protection (Annex I (2)(f)) — die in #5b materialisierte generische Integritaets-Obligation. Die domaenen-scoped signed_update_integrity (Update-Signatur, (1)(3)(f)) bleibt gueltig als DOMAIN, specializes->CORE. NICHT log_integrity_immutability (Audit-Log-Schutz, andere Ebene)." }, { "framework": "NIST SP 800-53", "control": "SI-2", @@ -84,9 +84,9 @@ "framework": "NIST SP 800-53", "control": "CM-7", "source_norm": "CRA Annex I Part I (2)(i) — Angriffsflaeche minimieren", "citation_unit": "Annex I (2)(i)", "family": "attack_surface", "mapping_type": "primary_implementation", - "proposed_obligation_id": "remote_access_attack_surface_min", + "proposed_obligation_id": "attack_surface_minimization", "mapping_method": "semantic", - "mapping_note": "NIST CM-7 = Least Functionality (deaktivierte Ports/Dienste/Funktionen, GESAMTE Angriffsflaeche). Naechster vorhandener Treffer (93-Stand): remote_access_attack_surface_min (remote_access-Familie) — deckt aber NUR Remote-Access-Flaeche. CM-7 ist BREITER. Vermutlich generische Obligation noetig (Vorschlag attack_surface_minimization); sonst CM-7 supports fuer remote_access_attack_surface_min. related (supports): SC-3(3)/AC-6/SI-16." + "mapping_note": "NIST CM-7 = Least Functionality (deaktivierte Ports/Dienste/Funktionen, GESAMTE Angriffsflaeche). #6 ADOPTIERT (2026-06-26) auf CORE attack_surface_minimization (Annex I (2)(j)) — die in #5b materialisierte generische Obligation. Die domaenen-scoped remote_access_attack_surface_min (nur Remote-Access-Flaeche) bleibt gueltig als DOMAIN, specializes->CORE. related (supports): SC-3(3)/AC-6/SI-16." } ] }