Files
breakpilot-compliance/ai-compliance-sdk/internal/iace/controls_library_test.go
Benjamin Admin 9c1355c05f
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 34s
CI/CD / test-python-backend-compliance (push) Successful in 33s
CI/CD / test-python-document-crawler (push) Successful in 23s
CI/CD / test-python-dsms-gateway (push) Successful in 19s
CI/CD / validate-canonical-controls (push) Successful in 13s
CI/CD / Deploy (push) Successful in 2s
feat(iace): Phase 5+6 — frontend integration, RAG library search, comprehensive tests
Phase 5 — Frontend Integration:
- components/page.tsx: ComponentLibraryModal with 120 components + 20 energy sources
- hazards/page.tsx: AutoSuggestPanel with 3-column pattern matching review
- mitigations/page.tsx: SuggestMeasuresModal per hazard with 3-level grouping
- verification/page.tsx: SuggestEvidenceModal per mitigation with evidence types

Phase 6 — RAG Library Search:
- Added bp_iace_libraries to AllowedCollections whitelist in rag_handlers.go
- SearchLibrary endpoint: POST /iace/library-search (semantic search across libraries)
- EnrichTechFileSection endpoint: POST /projects/:id/tech-file/:section/enrich
- Created ingest-iace-libraries.sh ingestion script for Qdrant collection

Tests (123 passing):
- tag_taxonomy_test.go: 8 tests for taxonomy entries, domains, essential tags
- controls_library_test.go: 7 tests for measures, reduction types, subtypes
- integration_test.go: 7 integration tests for full match flow and library consistency
- Extended tag_resolver_test.go: 9 new tests for FindByTags and cross-category resolution

Documentation:
- Updated iace.md with Hazard-Matching-Engine, RAG enrichment, and new DB tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:22:49 +01:00

96 lines
2.8 KiB
Go

package iace
import "testing"
// TestControlsLibrary_UniqueIDs verifies all control IDs are unique.
func TestControlsLibrary_UniqueIDs(t *testing.T) {
seen := make(map[string]bool)
for _, e := range GetControlsLibrary() {
if e.ID == "" {
t.Errorf("control has empty ID")
continue
}
if seen[e.ID] {
t.Errorf("duplicate control ID: %s", e.ID)
}
seen[e.ID] = true
}
}
// TestProtectiveMeasures_HasExamples verifies measures have examples.
func TestProtectiveMeasures_HasExamples(t *testing.T) {
withExamples := 0
for _, e := range GetProtectiveMeasureLibrary() {
if len(e.Examples) > 0 {
withExamples++
}
}
total := len(GetProtectiveMeasureLibrary())
threshold := total * 80 / 100
if withExamples < threshold {
t.Errorf("only %d/%d measures have examples, want at least %d", withExamples, total, threshold)
}
}
// TestProtectiveMeasures_ThreeReductionTypesPresent verifies all 3 types exist.
func TestProtectiveMeasures_ThreeReductionTypesPresent(t *testing.T) {
types := make(map[string]int)
for _, e := range GetProtectiveMeasureLibrary() {
types[e.ReductionType]++
}
// Accept both naming variants
designCount := types["design"]
protectiveCount := types["protective"] + types["protection"]
infoCount := types["information"]
if designCount == 0 {
t.Error("no measures with reduction type design")
}
if protectiveCount == 0 {
t.Error("no measures with reduction type protective/protection")
}
if infoCount == 0 {
t.Error("no measures with reduction type information")
}
}
// TestProtectiveMeasures_TagFieldAccessible verifies the Tags field is accessible.
func TestProtectiveMeasures_TagFieldAccessible(t *testing.T) {
measures := GetProtectiveMeasureLibrary()
if len(measures) == 0 {
t.Fatal("no measures returned")
}
// Tags field exists but may not be populated yet
_ = measures[0].Tags
}
// TestProtectiveMeasures_HazardCategoryNotEmpty verifies HazardCategory is populated.
func TestProtectiveMeasures_HazardCategoryNotEmpty(t *testing.T) {
for _, e := range GetProtectiveMeasureLibrary() {
if e.HazardCategory == "" {
t.Errorf("measure %s (%s): HazardCategory is empty", e.ID, e.Name)
}
}
}
// TestProtectiveMeasures_Count160 verifies at least 160 measures exist.
func TestProtectiveMeasures_Count160(t *testing.T) {
entries := GetProtectiveMeasureLibrary()
if len(entries) < 160 {
t.Fatalf("got %d protective measures, want at least 160", len(entries))
}
}
// TestProtectiveMeasures_SubTypesPresent verifies subtypes are used.
func TestProtectiveMeasures_SubTypesPresent(t *testing.T) {
subtypes := make(map[string]int)
for _, e := range GetProtectiveMeasureLibrary() {
if e.SubType != "" {
subtypes[e.SubType]++
}
}
if len(subtypes) < 3 {
t.Errorf("expected at least 3 different subtypes, got %d: %v", len(subtypes), subtypes)
}
}