feat(ucca): Pflichtendatenbank v2 (325 Obligations), Trigger-Engine, TOM-Control-Mapping
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 32s
CI / test-python-backend-compliance (push) Successful in 29s
CI / test-python-document-crawler (push) Successful in 20s
CI / test-python-dsms-gateway (push) Successful in 18s
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 32s
CI / test-python-backend-compliance (push) Successful in 29s
CI / test-python-document-crawler (push) Successful in 20s
CI / test-python-dsms-gateway (push) Successful in 18s
- 9 Regulation-JSON-Dateien (DSGVO 80, AI Act 60, NIS2 40, BDSG 30, TTDSG 20, DSA 35, Data Act 25, EU-Maschinen 15, DORA 20) - Condition-Tree-Engine fuer automatische Pflichtenselektion (all_of/any_of, 80+ Field-Paths) - Generischer JSONRegulationModule-Loader mit YAML-Fallback - Bidirektionales TOM-Control-Mapping (291 Obligation→Control, 92 Control→Obligation) - Gap-Analyse-Engine (Compliance-%, Priority Actions, Domain Breakdown) - ScopeDecision→UnifiedFacts Bridge fuer Auto-Profiling - 4 neue API-Endpoints (assess-from-scope, tom-controls, gap-analysis, reverse-lookup) - Frontend: Auto-Profiling Button, Regulation-Filter Chips, TOM-Panel, Gap-Analyse-View - 18 Unit Tests (Condition Engine, v2 Loader, TOM Mapper) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
233
ai-compliance-sdk/internal/ucca/v2_loader.go
Normal file
233
ai-compliance-sdk/internal/ucca/v2_loader.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package ucca
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// V2Manifest represents the registry of all v2 obligation files
|
||||
type V2Manifest struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
Regulations []V2RegulationEntry `json:"regulations"`
|
||||
TOMMappingFile string `json:"tom_mapping_file"`
|
||||
TotalObl int `json:"total_obligations"`
|
||||
}
|
||||
|
||||
// V2RegulationEntry is a single regulation in the manifest
|
||||
type V2RegulationEntry struct {
|
||||
ID string `json:"id"`
|
||||
File string `json:"file"`
|
||||
Version string `json:"version"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// V2RegulationFile is the top-level structure of a v2 regulation JSON file
|
||||
type V2RegulationFile struct {
|
||||
Regulation string `json:"regulation"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
EffectiveDate string `json:"effective_date,omitempty"`
|
||||
Obligations []V2Obligation `json:"obligations"`
|
||||
Controls []V2Control `json:"controls,omitempty"`
|
||||
IncidentDL []V2IncidentDL `json:"incident_deadlines,omitempty"`
|
||||
}
|
||||
|
||||
// V2Obligation is the extended obligation structure
|
||||
type V2Obligation struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
AppliesWhen string `json:"applies_when"`
|
||||
AppliesWhenCondition *ConditionNode `json:"applies_when_condition,omitempty"`
|
||||
LegalBasis []V2LegalBasis `json:"legal_basis"`
|
||||
Sources []V2Source `json:"sources,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Responsible string `json:"responsible"`
|
||||
Deadline *V2Deadline `json:"deadline,omitempty"`
|
||||
Sanctions *V2Sanctions `json:"sanctions,omitempty"`
|
||||
Evidence []interface{} `json:"evidence,omitempty"`
|
||||
Priority string `json:"priority"`
|
||||
TOMControlIDs []string `json:"tom_control_ids,omitempty"`
|
||||
BreakpilotFeature string `json:"breakpilot_feature,omitempty"`
|
||||
ValidFrom string `json:"valid_from,omitempty"`
|
||||
ValidUntil *string `json:"valid_until"`
|
||||
Version string `json:"version,omitempty"`
|
||||
ISO27001Mapping []string `json:"iso27001_mapping,omitempty"`
|
||||
HowToImplement string `json:"how_to_implement,omitempty"`
|
||||
}
|
||||
|
||||
// V2LegalBasis is a legal reference in v2 format
|
||||
type V2LegalBasis struct {
|
||||
Norm string `json:"norm"`
|
||||
Article string `json:"article"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Erwaegungsgrund string `json:"erwaegungsgrund,omitempty"`
|
||||
}
|
||||
|
||||
// V2Source is an external source reference
|
||||
type V2Source struct {
|
||||
Type string `json:"type"`
|
||||
Ref string `json:"ref"`
|
||||
}
|
||||
|
||||
// V2Deadline is a deadline in v2 format
|
||||
type V2Deadline struct {
|
||||
Type string `json:"type"`
|
||||
Date string `json:"date,omitempty"`
|
||||
Duration string `json:"duration,omitempty"`
|
||||
Interval string `json:"interval,omitempty"`
|
||||
Event string `json:"event,omitempty"`
|
||||
}
|
||||
|
||||
// V2Sanctions is sanctions info in v2 format
|
||||
type V2Sanctions struct {
|
||||
MaxFine string `json:"max_fine,omitempty"`
|
||||
PersonalLiability bool `json:"personal_liability,omitempty"`
|
||||
CriminalLiability bool `json:"criminal_liability,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// V2Control is a control in v2 format
|
||||
type V2Control struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Category string `json:"category"`
|
||||
WhatToDo string `json:"what_to_do,omitempty"`
|
||||
ISO27001Mapping []string `json:"iso27001_mapping,omitempty"`
|
||||
Priority string `json:"priority,omitempty"`
|
||||
}
|
||||
|
||||
// V2IncidentDL is an incident deadline in v2 format
|
||||
type V2IncidentDL struct {
|
||||
Phase string `json:"phase"`
|
||||
Deadline string `json:"deadline"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Recipient string `json:"recipient,omitempty"`
|
||||
LegalBasis []V2LegalBasis `json:"legal_basis,omitempty"`
|
||||
}
|
||||
|
||||
// ConditionNode represents a condition tree node for obligation applicability
|
||||
type ConditionNode struct {
|
||||
AllOf []ConditionNode `json:"all_of,omitempty"`
|
||||
AnyOf []ConditionNode `json:"any_of,omitempty"`
|
||||
Field string `json:"field,omitempty"`
|
||||
Operator string `json:"operator,omitempty"`
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// V2TOMMapping is the bidirectional mapping file
|
||||
type V2TOMMapping struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
ObligationToControl map[string][]string `json:"obligation_to_control"`
|
||||
ControlToObligation map[string][]string `json:"control_to_obligation"`
|
||||
}
|
||||
|
||||
// getV2BasePath returns the base path for v2 obligation files
|
||||
func getV2BasePath() string {
|
||||
// Try relative to the binary
|
||||
candidates := []string{
|
||||
"policies/obligations/v2",
|
||||
"../policies/obligations/v2",
|
||||
"../../policies/obligations/v2",
|
||||
}
|
||||
|
||||
// Also try relative to the source file
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
if ok {
|
||||
srcDir := filepath.Dir(filename)
|
||||
candidates = append(candidates,
|
||||
filepath.Join(srcDir, "../../policies/obligations/v2"),
|
||||
)
|
||||
}
|
||||
|
||||
for _, p := range candidates {
|
||||
abs, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if info, err := os.Stat(abs); err == nil && info.IsDir() {
|
||||
return abs
|
||||
}
|
||||
}
|
||||
|
||||
return "policies/obligations/v2"
|
||||
}
|
||||
|
||||
// LoadV2Manifest loads the v2 manifest file
|
||||
func LoadV2Manifest() (*V2Manifest, error) {
|
||||
basePath := getV2BasePath()
|
||||
manifestPath := filepath.Join(basePath, "_manifest.json")
|
||||
|
||||
data, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read v2 manifest: %w", err)
|
||||
}
|
||||
|
||||
var manifest V2Manifest
|
||||
if err := json.Unmarshal(data, &manifest); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse v2 manifest: %w", err)
|
||||
}
|
||||
|
||||
return &manifest, nil
|
||||
}
|
||||
|
||||
// LoadV2RegulationFile loads a single v2 regulation JSON file
|
||||
func LoadV2RegulationFile(filename string) (*V2RegulationFile, error) {
|
||||
basePath := getV2BasePath()
|
||||
filePath := filepath.Join(basePath, filename)
|
||||
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read v2 regulation file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
var regFile V2RegulationFile
|
||||
if err := json.Unmarshal(data, ®File); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse v2 regulation file %s: %w", filename, err)
|
||||
}
|
||||
|
||||
return ®File, nil
|
||||
}
|
||||
|
||||
// LoadV2TOMMapping loads the bidirectional TOM mapping
|
||||
func LoadV2TOMMapping() (*V2TOMMapping, error) {
|
||||
basePath := getV2BasePath()
|
||||
mappingPath := filepath.Join(basePath, "_tom_mapping.json")
|
||||
|
||||
data, err := os.ReadFile(mappingPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read TOM mapping: %w", err)
|
||||
}
|
||||
|
||||
var mapping V2TOMMapping
|
||||
if err := json.Unmarshal(data, &mapping); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse TOM mapping: %w", err)
|
||||
}
|
||||
|
||||
return &mapping, nil
|
||||
}
|
||||
|
||||
// LoadAllV2Regulations loads all v2 regulation files from the manifest
|
||||
func LoadAllV2Regulations() (map[string]*V2RegulationFile, error) {
|
||||
manifest, err := LoadV2Manifest()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]*V2RegulationFile)
|
||||
for _, entry := range manifest.Regulations {
|
||||
regFile, err := LoadV2RegulationFile(entry.File)
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: Could not load v2 regulation %s: %v\n", entry.ID, err)
|
||||
continue
|
||||
}
|
||||
result[entry.ID] = regFile
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user