feat(iace): Hazard-Library v2, Controls-Library, SEPA Avoidance, CE RAG-Ingest
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 35s
CI / test-python-backend-compliance (push) Successful in 33s
CI / test-python-document-crawler (push) Successful in 21s
CI / test-python-dsms-gateway (push) Successful in 19s

- Hazard-Library: +79 neue Eintraege in 12 Kategorien (software_fault,
  hmi_error, mechanical_hazard, electrical_hazard, thermal_hazard,
  emc_hazard, configuration_error, safety_function_failure,
  logging_audit_failure, integration_error, environmental_hazard,
  maintenance_hazard) — Gesamtanzahl: ~116 Eintraege in 24 Kategorien
- Controls-Library: neue Datei controls_library.go mit 200 Eintraegen
  in 6 Domaenen (REQ/ARCH/SWDEV/VER/CYBER/DOC)
- Handler: GET /sdk/v1/iace/controls-library (?domain=, ?category=)
- SEPA: CalculateInherentRisk() + 4. Param Avoidance (0=disabled,
  1-5: 3=neutral); RiskComputeInput.Avoidance, RiskAssessment.Avoidance,
  AssessRiskRequest.Avoidance — backward-kompatibel (A=0 → S×E×P)
- Tests: engine_test.go + hazard_library_test.go aktualisiert
- Scripts: ingest-ce-corpus.sh — 15 CE/Safety-Dokumente (EUR-Lex,
  NIST, ENISA, NASA, OWASP, MITRE CWE) in bp_compliance_ce und
  bp_compliance_datenschutz
- Docs: docs-src/services/sdk-modules/iace.md + mkdocs.yml Nav-Eintrag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-05 17:13:01 +01:00
parent 3ed8300daf
commit efeacc1619
11 changed files with 2410 additions and 17 deletions

View File

@@ -9,9 +9,9 @@ import (
func TestGetBuiltinHazardLibrary_EntryCount(t *testing.T) {
entries := GetBuiltinHazardLibrary()
// Expected: 4+3+2+3+3+3+4+3+4+3+2+3 = 37
if len(entries) != 37 {
t.Fatalf("GetBuiltinHazardLibrary returned %d entries, want 37", len(entries))
// Original 37 + 12 new categories (10+8+6+6+4+5+8+8+5+8+5+6 = 79) = 116
if len(entries) < 100 {
t.Fatalf("GetBuiltinHazardLibrary returned %d entries, want at least 100", len(entries))
}
}
@@ -46,6 +46,7 @@ func TestGetBuiltinHazardLibrary_UniqueNonZeroUUIDs(t *testing.T) {
func TestGetBuiltinHazardLibrary_AllCategoriesPresent(t *testing.T) {
entries := GetBuiltinHazardLibrary()
// All 24 categories (12 original + 12 new)
expectedCategories := map[string]bool{
"false_classification": false,
"timing_error": false,
@@ -59,6 +60,19 @@ func TestGetBuiltinHazardLibrary_AllCategoriesPresent(t *testing.T) {
"mode_confusion": false,
"unintended_bias": false,
"update_failure": false,
// New categories
"software_fault": false,
"hmi_error": false,
"mechanical_hazard": false,
"electrical_hazard": false,
"thermal_hazard": false,
"emc_hazard": false,
"configuration_error": false,
"safety_function_failure": false,
"logging_audit_failure": false,
"integration_error": false,
"environmental_hazard": false,
"maintenance_hazard": false,
}
for _, e := range entries {
@@ -78,7 +92,8 @@ func TestGetBuiltinHazardLibrary_AllCategoriesPresent(t *testing.T) {
func TestGetBuiltinHazardLibrary_CategoryCounts(t *testing.T) {
entries := GetBuiltinHazardLibrary()
expectedCounts := map[string]int{
// Original 12 categories: exact counts must remain unchanged
originalCounts := map[string]int{
"false_classification": 4,
"timing_error": 3,
"data_poisoning": 2,
@@ -92,15 +107,26 @@ func TestGetBuiltinHazardLibrary_CategoryCounts(t *testing.T) {
"unintended_bias": 2,
"update_failure": 3,
}
// New 12 categories: must each have at least 1 entry
newCategories := []string{
"software_fault", "hmi_error", "mechanical_hazard", "electrical_hazard",
"thermal_hazard", "emc_hazard", "configuration_error", "safety_function_failure",
"logging_audit_failure", "integration_error", "environmental_hazard", "maintenance_hazard",
}
actualCounts := make(map[string]int)
for _, e := range entries {
actualCounts[e.Category]++
}
for cat, expected := range expectedCounts {
for cat, expected := range originalCounts {
if actualCounts[cat] != expected {
t.Errorf("category %q: count = %d, want %d", cat, actualCounts[cat], expected)
t.Errorf("original category %q: count = %d, want %d", cat, actualCounts[cat], expected)
}
}
for _, cat := range newCategories {
if actualCounts[cat] < 1 {
t.Errorf("new category %q: count = %d, want >= 1", cat, actualCounts[cat])
}
}
}