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 }