Files
breakpilot-compliance/ai-compliance-sdk/internal/ucca/canonical_control_loader.go
Benjamin Admin 050f353192
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 40s
CI/CD / test-python-backend-compliance (push) Successful in 41s
CI/CD / test-python-document-crawler (push) Successful in 26s
CI/CD / test-python-dsms-gateway (push) Successful in 23s
CI/CD / validate-canonical-controls (push) Successful in 18s
CI/CD / deploy-hetzner (push) Successful in 2m26s
feat(canonical-controls): Canonical Control Library — rechtssichere Security Controls
Eigenstaendig formulierte Security Controls mit unabhaengiger Taxonomie
und Open-Source-Verankerung (OWASP, NIST, ENISA). Keine BSI-Nomenklatur.

- Migration 044: 5 DB-Tabellen (frameworks, controls, sources, licenses, mappings)
- 10 Seed Controls mit 39 Open-Source-Referenzen
- License Gate: Quellen-Berechtigungspruefung (analysis/excerpt/embeddings/product)
- Too-Close-Detektor: 5 Metriken (exact-phrase, token-overlap, ngram, embedding, LCS)
- REST API: 8 Endpoints unter /v1/canonical/
- Go Loader mit Multi-Index (ID, domain, severity, framework)
- Frontend: Control Library Browser + Provenance Wiki
- CI/CD: validate-controls.py Job (schema, no-leak, open-anchors)
- 67 Tests (8 Go + 59 Python), alle PASS
- MkDocs Dokumentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 19:55:06 +01:00

183 lines
5.8 KiB
Go

package ucca
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
)
// CanonicalControl represents a single independently authored security control.
type CanonicalControl struct {
ControlID string `json:"control_id"`
Title string `json:"title"`
Domain string `json:"domain"`
Severity string `json:"severity"` // low, medium, high, critical
RiskScore float64 `json:"risk_score"`
ImplementationEffort string `json:"implementation_effort"` // s, m, l, xl
Objective string `json:"objective"`
Rationale string `json:"rationale"`
Scope CanonicalScope `json:"scope"`
Requirements []string `json:"requirements"`
TestProcedure []string `json:"test_procedure"`
Evidence []CanonicalEvidence `json:"evidence"`
OpenAnchors []OpenAnchor `json:"open_anchors"`
Tags []string `json:"tags"`
}
// CanonicalScope defines where a control applies.
type CanonicalScope struct {
Platforms []string `json:"platforms"`
Components []string `json:"components"`
DataClasses []string `json:"data_classes"`
}
// CanonicalEvidence describes a required evidence item.
type CanonicalEvidence struct {
Type string `json:"type"`
Description string `json:"description"`
}
// OpenAnchor links a control to an open-source framework reference.
type OpenAnchor struct {
Framework string `json:"framework"`
Ref string `json:"ref"`
URL string `json:"url"`
}
// CanonicalDomain groups controls by security domain.
type CanonicalDomain struct {
ID string `json:"id"`
Name string `json:"name"`
Objective string `json:"objective"`
}
// CanonicalFramework is the framework metadata.
type CanonicalFramework struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
}
// CanonicalControlLibrary is the top-level JSON structure.
type CanonicalControlLibrary struct {
Version string `json:"version"`
Schema string `json:"schema"`
Generated string `json:"generated"`
Framework CanonicalFramework `json:"framework"`
TotalControls int `json:"total_controls"`
Domains []CanonicalDomain `json:"domains"`
Controls []CanonicalControl `json:"controls"`
}
// CanonicalControlIndex provides fast lookup of canonical controls.
type CanonicalControlIndex struct {
ByID map[string]*CanonicalControl
ByDomain map[string][]*CanonicalControl
BySeverity map[string][]*CanonicalControl
ByFramework map[string][]*CanonicalControl // framework ref -> controls
Domains []CanonicalDomain
Framework CanonicalFramework
AllControls []*CanonicalControl
}
// LoadCanonicalControls loads the canonical control library from JSON.
func LoadCanonicalControls() (*CanonicalControlIndex, error) {
data, err := readCanonicalControlsFile()
if err != nil {
return nil, err
}
var library CanonicalControlLibrary
if err := json.Unmarshal(data, &library); err != nil {
return nil, fmt.Errorf("failed to parse canonical controls: %w", err)
}
return buildCanonicalIndex(&library), nil
}
func readCanonicalControlsFile() ([]byte, error) {
candidates := []string{
"policies/canonical_controls_v1.json",
"../policies/canonical_controls_v1.json",
"../../policies/canonical_controls_v1.json",
}
_, filename, _, ok := runtime.Caller(0)
if ok {
srcDir := filepath.Dir(filename)
candidates = append(candidates,
filepath.Join(srcDir, "../../policies/canonical_controls_v1.json"),
)
}
for _, p := range candidates {
abs, err := filepath.Abs(p)
if err != nil {
continue
}
data, err := os.ReadFile(abs)
if err == nil {
return data, nil
}
}
return nil, fmt.Errorf("canonical_controls_v1.json not found in any candidate path")
}
func buildCanonicalIndex(library *CanonicalControlLibrary) *CanonicalControlIndex {
idx := &CanonicalControlIndex{
ByID: make(map[string]*CanonicalControl),
ByDomain: make(map[string][]*CanonicalControl),
BySeverity: make(map[string][]*CanonicalControl),
ByFramework: make(map[string][]*CanonicalControl),
Domains: library.Domains,
Framework: library.Framework,
}
for i := range library.Controls {
ctrl := &library.Controls[i]
idx.ByID[ctrl.ControlID] = ctrl
idx.ByDomain[ctrl.Domain] = append(idx.ByDomain[ctrl.Domain], ctrl)
idx.BySeverity[ctrl.Severity] = append(idx.BySeverity[ctrl.Severity], ctrl)
idx.AllControls = append(idx.AllControls, ctrl)
for _, anchor := range ctrl.OpenAnchors {
idx.ByFramework[anchor.Framework] = append(idx.ByFramework[anchor.Framework], ctrl)
}
}
return idx
}
// GetControl returns a control by its ID (e.g. "AUTH-001").
func (idx *CanonicalControlIndex) GetControl(id string) (*CanonicalControl, bool) {
ctrl, ok := idx.ByID[strings.ToUpper(id)]
return ctrl, ok
}
// GetControlsByDomain returns all controls for a domain (e.g. "AUTH").
func (idx *CanonicalControlIndex) GetControlsByDomain(domain string) []*CanonicalControl {
return idx.ByDomain[strings.ToUpper(domain)]
}
// GetControlsBySeverity returns all controls with a given severity.
func (idx *CanonicalControlIndex) GetControlsBySeverity(severity string) []*CanonicalControl {
return idx.BySeverity[strings.ToLower(severity)]
}
// GetControlsByFramework returns all controls anchored to a framework (e.g. "OWASP ASVS").
func (idx *CanonicalControlIndex) GetControlsByFramework(framework string) []*CanonicalControl {
return idx.ByFramework[framework]
}
// ValidateControlID checks if a control ID exists.
func (idx *CanonicalControlIndex) ValidateControlID(id string) bool {
_, ok := idx.ByID[strings.ToUpper(id)]
return ok
}