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>
458 lines
18 KiB
Go
458 lines
18 KiB
Go
package ucca
|
|
|
|
// ============================================================================
|
|
// Unified Facts Model
|
|
// ============================================================================
|
|
//
|
|
// UnifiedFacts aggregates all facts about an organization that are needed
|
|
// to determine which regulations apply and what obligations arise.
|
|
// This model is regulation-agnostic and serves as input for all modules.
|
|
//
|
|
// ============================================================================
|
|
|
|
// UnifiedFacts is the comprehensive facts model for all regulatory assessments
|
|
type UnifiedFacts struct {
|
|
// Existing UCCA Facts (for backwards compatibility)
|
|
UCCAFacts *UseCaseIntake `json:"ucca_facts,omitempty"`
|
|
|
|
// Organization facts
|
|
Organization OrganizationFacts `json:"organization"`
|
|
|
|
// Sector/Industry facts (for NIS2, sector-specific regulations)
|
|
Sector SectorFacts `json:"sector"`
|
|
|
|
// Data protection facts (for DSGVO)
|
|
DataProtection DataProtectionFacts `json:"data_protection"`
|
|
|
|
// AI usage facts (for AI Act)
|
|
AIUsage AIUsageFacts `json:"ai_usage"`
|
|
|
|
// Financial sector facts (for MaRisk, DORA)
|
|
Financial FinancialFacts `json:"financial"`
|
|
|
|
// IT Security facts (for NIS2)
|
|
ITSecurity ITSecurityFacts `json:"it_security"`
|
|
|
|
// Supply chain facts
|
|
SupplyChain SupplyChainFacts `json:"supply_chain"`
|
|
|
|
// Personnel facts
|
|
Personnel PersonnelFacts `json:"personnel"`
|
|
}
|
|
|
|
// OrganizationFacts contains basic organizational information
|
|
type OrganizationFacts struct {
|
|
// Basic info
|
|
Name string `json:"name,omitempty"`
|
|
LegalForm string `json:"legal_form,omitempty"` // e.g., "GmbH", "AG", "e.V."
|
|
Country string `json:"country"` // e.g., "DE", "AT", "CH"
|
|
EUMember bool `json:"eu_member"`
|
|
|
|
// Organization type
|
|
IsPublicAuthority bool `json:"is_public_authority"` // Public authority or body
|
|
|
|
// Size metrics (KMU criteria)
|
|
EmployeeCount int `json:"employee_count"`
|
|
AnnualRevenue float64 `json:"annual_revenue"` // in EUR
|
|
BalanceSheetTotal float64 `json:"balance_sheet_total"` // in EUR
|
|
|
|
// Calculated size category
|
|
SizeCategory string `json:"size_category,omitempty"` // "micro", "small", "medium", "large"
|
|
|
|
// Group structure
|
|
IsPartOfGroup bool `json:"is_part_of_group"`
|
|
ParentCompany string `json:"parent_company,omitempty"`
|
|
GroupEmployees int `json:"group_employees,omitempty"`
|
|
GroupRevenue float64 `json:"group_revenue,omitempty"`
|
|
}
|
|
|
|
// SectorFacts contains industry/sector information for regulatory classification
|
|
type SectorFacts struct {
|
|
// Primary sector classification
|
|
PrimarySector string `json:"primary_sector"` // NIS2 Annex I/II sector codes
|
|
SubSector string `json:"sub_sector,omitempty"`
|
|
NACECode string `json:"nace_code,omitempty"`
|
|
|
|
// KRITIS classification (German critical infrastructure)
|
|
IsKRITIS bool `json:"is_kritis"`
|
|
KRITISThresholdMet bool `json:"kritis_threshold_met"`
|
|
KRITISSector string `json:"kritis_sector,omitempty"`
|
|
|
|
// Special services (NIS2-specific)
|
|
SpecialServices []string `json:"special_services,omitempty"` // "dns", "tld", "cloud", "datacenter", "cdn", "msp", "mssp", "trust_service", "public_network", "electronic_comms"
|
|
|
|
// Public administration
|
|
IsPublicAdministration bool `json:"is_public_administration"`
|
|
PublicAdminLevel string `json:"public_admin_level,omitempty"` // "federal", "state", "municipal"
|
|
|
|
// NIS2 classification (v2)
|
|
NIS2Classification string `json:"nis2_classification,omitempty"` // wichtige_einrichtung, besonders_wichtige_einrichtung, nicht_betroffen
|
|
IsAnnexI bool `json:"is_annex_i"`
|
|
IsAnnexII bool `json:"is_annex_ii"`
|
|
|
|
// Healthcare specific
|
|
IsHealthcareProvider bool `json:"is_healthcare_provider"`
|
|
HasPatientData bool `json:"has_patient_data"`
|
|
|
|
// Financial specific
|
|
IsFinancialInstitution bool `json:"is_financial_institution"`
|
|
FinancialEntityType string `json:"financial_entity_type,omitempty"` // DORA entity types
|
|
}
|
|
|
|
// DataProtectionFacts contains GDPR-relevant information
|
|
type DataProtectionFacts struct {
|
|
// Data processing basics
|
|
ProcessesPersonalData bool `json:"processes_personal_data"`
|
|
ProcessesSpecialCategories bool `json:"processes_special_categories"` // Art. 9 DSGVO
|
|
ProcessesMinorData bool `json:"processes_minor_data"`
|
|
ProcessesCriminalData bool `json:"processes_criminal_data"` // Art. 10 DSGVO
|
|
|
|
// Controller/Processor role
|
|
IsController bool `json:"is_controller"` // Acts as controller
|
|
IsProcessor bool `json:"is_processor"` // Acts as processor for others
|
|
|
|
// Territorial scope (Art. 3)
|
|
OffersToEU bool `json:"offers_to_eu"` // Offers goods/services to EU
|
|
MonitorsEUIndividuals bool `json:"monitors_eu_individuals"` // Monitors behavior of EU individuals
|
|
|
|
// Scale of processing
|
|
LargeScaleProcessing bool `json:"large_scale_processing"`
|
|
SystematicMonitoring bool `json:"systematic_monitoring"`
|
|
Profiling bool `json:"profiling"`
|
|
AutomatedDecisionMaking bool `json:"automated_decision_making"` // Art. 22 DSGVO
|
|
AutomatedDecisions bool `json:"automated_decisions"` // Alias for automated_decision_making
|
|
LegalEffects bool `json:"legal_effects"` // Automated decisions with legal effects
|
|
|
|
// Special categories (Art. 9) - detailed
|
|
SpecialCategories []string `json:"special_categories,omitempty"` // racial_ethnic_origin, political_opinions, etc.
|
|
|
|
// High-risk activities (Art. 35)
|
|
HighRiskActivities []string `json:"high_risk_activities,omitempty"` // systematic_monitoring, automated_decisions, etc.
|
|
|
|
// Data subjects
|
|
DataSubjectCount int `json:"data_subject_count"` // Approximate number
|
|
DataSubjectCountRange string `json:"data_subject_count_range,omitempty"` // "< 1000", "1000-10000", "> 10000", "> 100000"
|
|
|
|
// Data transfers
|
|
TransfersToThirdCountries bool `json:"transfers_to_third_countries"`
|
|
CrossBorderProcessing bool `json:"cross_border_processing"` // Processing across EU borders
|
|
SCCsInPlace bool `json:"sccs_in_place"`
|
|
BindingCorporateRules bool `json:"binding_corporate_rules"`
|
|
|
|
// External processing
|
|
UsesExternalProcessor bool `json:"uses_external_processor"`
|
|
|
|
// DSB requirement triggers
|
|
RequiresDSBByLaw bool `json:"requires_dsb_by_law"`
|
|
HasAppointedDSB bool `json:"has_appointed_dsb"`
|
|
DSBIsInternal bool `json:"dsb_is_internal"`
|
|
|
|
// Extended data categories (v2)
|
|
ProcessesEmployeeData bool `json:"processes_employee_data"`
|
|
ProcessesFinancialData bool `json:"processes_financial_data"`
|
|
ProcessesHealthData bool `json:"processes_health_data"`
|
|
ProcessesBiometricData bool `json:"processes_biometric_data"`
|
|
|
|
// Online / Platform processing (v2)
|
|
UsesCookies bool `json:"uses_cookies"`
|
|
UsesTracking bool `json:"uses_tracking"`
|
|
UsesVideoSurveillance bool `json:"uses_video_surveillance"`
|
|
OperatesPlatform bool `json:"operates_platform"`
|
|
PlatformUserCount int `json:"platform_user_count,omitempty"`
|
|
}
|
|
|
|
// AIUsageFacts contains AI Act relevant information
|
|
type AIUsageFacts struct {
|
|
// Basic AI usage
|
|
UsesAI bool `json:"uses_ai"`
|
|
AIApplications []string `json:"ai_applications,omitempty"`
|
|
|
|
// AI Act role
|
|
IsAIProvider bool `json:"is_ai_provider"` // Develops/provides AI systems
|
|
IsAIDeployer bool `json:"is_ai_deployer"` // Uses AI systems
|
|
IsAIDistributor bool `json:"is_ai_distributor"`
|
|
IsAIImporter bool `json:"is_ai_importer"`
|
|
|
|
// Risk categories (pre-classification)
|
|
HasHighRiskAI bool `json:"has_high_risk_ai"`
|
|
HasLimitedRiskAI bool `json:"has_limited_risk_ai"`
|
|
HasMinimalRiskAI bool `json:"has_minimal_risk_ai"`
|
|
|
|
// Specific high-risk categories (Annex III)
|
|
BiometricIdentification bool `json:"biometric_identification"` // Real-time, remote
|
|
CriticalInfrastructure bool `json:"critical_infrastructure"` // AI in CI
|
|
EducationAccess bool `json:"education_access"` // Admission, assessment
|
|
EmploymentDecisions bool `json:"employment_decisions"` // Recruitment, evaluation
|
|
EssentialServices bool `json:"essential_services"` // Credit, benefits
|
|
LawEnforcement bool `json:"law_enforcement"`
|
|
MigrationAsylum bool `json:"migration_asylum"`
|
|
JusticeAdministration bool `json:"justice_administration"`
|
|
|
|
// Prohibited practices (Art. 5)
|
|
SocialScoring bool `json:"social_scoring"`
|
|
EmotionRecognition bool `json:"emotion_recognition"` // Workplace/education
|
|
PredictivePolicingIndividual bool `json:"predictive_policing_individual"`
|
|
|
|
// GPAI (General Purpose AI)
|
|
UsesGPAI bool `json:"uses_gpai"`
|
|
GPAIWithSystemicRisk bool `json:"gpai_with_systemic_risk"`
|
|
|
|
// Transparency obligations
|
|
AIInteractsWithNaturalPersons bool `json:"ai_interacts_with_natural_persons"`
|
|
GeneratesDeepfakes bool `json:"generates_deepfakes"`
|
|
}
|
|
|
|
// FinancialFacts contains financial regulation specific information
|
|
type FinancialFacts struct {
|
|
// Entity type (DORA scope)
|
|
EntityType string `json:"entity_type,omitempty"` // Credit institution, payment service provider, etc.
|
|
IsRegulated bool `json:"is_regulated"`
|
|
|
|
// DORA specific
|
|
DORAApplies bool `json:"dora_applies"`
|
|
HasCriticalICT bool `json:"has_critical_ict"`
|
|
ICTOutsourced bool `json:"ict_outsourced"`
|
|
ICTProviderLocation string `json:"ict_provider_location,omitempty"` // "EU", "EEA", "third_country"
|
|
ConcentrationRisk bool `json:"concentration_risk"`
|
|
|
|
// MaRisk/BAIT specific (Germany)
|
|
MaRiskApplies bool `json:"marisk_applies"`
|
|
BAITApplies bool `json:"bait_applies"`
|
|
|
|
// AI in financial services
|
|
AIAffectsCustomers bool `json:"ai_affects_customers"`
|
|
AlgorithmicTrading bool `json:"algorithmic_trading"`
|
|
AIRiskAssessment bool `json:"ai_risk_assessment"`
|
|
AIAMLKYC bool `json:"ai_aml_kyc"`
|
|
}
|
|
|
|
// ITSecurityFacts contains IT security posture information
|
|
type ITSecurityFacts struct {
|
|
// ISMS status
|
|
HasISMS bool `json:"has_isms"`
|
|
ISO27001Certified bool `json:"iso27001_certified"`
|
|
ISO27001CertExpiry string `json:"iso27001_cert_expiry,omitempty"`
|
|
|
|
// Security processes
|
|
HasIncidentProcess bool `json:"has_incident_process"`
|
|
HasVulnerabilityMgmt bool `json:"has_vulnerability_mgmt"`
|
|
HasPatchMgmt bool `json:"has_patch_mgmt"`
|
|
HasAccessControl bool `json:"has_access_control"`
|
|
HasMFA bool `json:"has_mfa"`
|
|
HasEncryption bool `json:"has_encryption"`
|
|
HasBackup bool `json:"has_backup"`
|
|
HasDisasterRecovery bool `json:"has_disaster_recovery"`
|
|
|
|
// BCM
|
|
HasBCM bool `json:"has_bcm"`
|
|
BCMTested bool `json:"bcm_tested"`
|
|
|
|
// Network security
|
|
HasNetworkSegmentation bool `json:"has_network_segmentation"`
|
|
HasFirewall bool `json:"has_firewall"`
|
|
HasIDS bool `json:"has_ids"`
|
|
|
|
// Monitoring
|
|
HasSecurityMonitoring bool `json:"has_security_monitoring"`
|
|
Has24x7SOC bool `json:"has_24x7_soc"`
|
|
|
|
// Awareness
|
|
SecurityAwarenessTraining bool `json:"security_awareness_training"`
|
|
RegularSecurityTraining bool `json:"regular_security_training"`
|
|
|
|
// Certifications
|
|
OtherCertifications []string `json:"other_certifications,omitempty"` // SOC2, BSI C5, etc.
|
|
}
|
|
|
|
// SupplyChainFacts contains supply chain security information
|
|
type SupplyChainFacts struct {
|
|
// Supply chain basics
|
|
HasSupplyChainRiskMgmt bool `json:"has_supply_chain_risk_mgmt"`
|
|
SupplierCount int `json:"supplier_count,omitempty"`
|
|
CriticalSupplierCount int `json:"critical_supplier_count,omitempty"`
|
|
|
|
// Third party risk
|
|
ThirdPartyAudits bool `json:"third_party_audits"`
|
|
SupplierSecurityReqs bool `json:"supplier_security_reqs"`
|
|
|
|
// ICT supply chain (NIS2)
|
|
HasICTSupplyChainPolicy bool `json:"has_ict_supply_chain_policy"`
|
|
ICTSupplierDiversity bool `json:"ict_supplier_diversity"`
|
|
}
|
|
|
|
// PersonnelFacts contains workforce-related information
|
|
type PersonnelFacts struct {
|
|
// Security personnel
|
|
HasCISO bool `json:"has_ciso"`
|
|
HasDedicatedSecurityTeam bool `json:"has_dedicated_security_team"`
|
|
SecurityTeamSize int `json:"security_team_size,omitempty"`
|
|
|
|
// Compliance personnel
|
|
HasComplianceOfficer bool `json:"has_compliance_officer"`
|
|
HasDPO bool `json:"has_dpo"`
|
|
DPOIsExternal bool `json:"dpo_is_external"`
|
|
|
|
// AI personnel (AI Act)
|
|
HasAICompetence bool `json:"has_ai_competence"`
|
|
HasAIGovernance bool `json:"has_ai_governance"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Methods
|
|
// ============================================================================
|
|
|
|
// CalculateSizeCategory determines the organization size based on EU SME criteria
|
|
func (o *OrganizationFacts) CalculateSizeCategory() string {
|
|
// Use group figures if part of a group
|
|
employees := o.EmployeeCount
|
|
revenue := o.AnnualRevenue
|
|
balance := o.BalanceSheetTotal
|
|
|
|
if o.IsPartOfGroup && o.GroupEmployees > 0 {
|
|
employees = o.GroupEmployees
|
|
}
|
|
if o.IsPartOfGroup && o.GroupRevenue > 0 {
|
|
revenue = o.GroupRevenue
|
|
}
|
|
|
|
// EU SME Criteria (Recommendation 2003/361/EC)
|
|
// Micro: <10 employees AND (revenue OR balance) <= €2m
|
|
// Small: <50 employees AND (revenue OR balance) <= €10m
|
|
// Medium: <250 employees AND revenue <= €50m OR balance <= €43m
|
|
// Large: everything else
|
|
|
|
if employees < 10 && (revenue <= 2_000_000 || balance <= 2_000_000) {
|
|
return "micro"
|
|
}
|
|
if employees < 50 && (revenue <= 10_000_000 || balance <= 10_000_000) {
|
|
return "small"
|
|
}
|
|
if employees < 250 && (revenue <= 50_000_000 || balance <= 43_000_000) {
|
|
return "medium"
|
|
}
|
|
return "large"
|
|
}
|
|
|
|
// IsSME returns true if the organization qualifies as an SME
|
|
func (o *OrganizationFacts) IsSME() bool {
|
|
category := o.CalculateSizeCategory()
|
|
return category == "micro" || category == "small" || category == "medium"
|
|
}
|
|
|
|
// MeetsNIS2SizeThreshold checks if organization meets NIS2 size threshold
|
|
// (>= 50 employees OR >= €10m revenue AND >= €10m balance)
|
|
func (o *OrganizationFacts) MeetsNIS2SizeThreshold() bool {
|
|
employees := o.EmployeeCount
|
|
revenue := o.AnnualRevenue
|
|
balance := o.BalanceSheetTotal
|
|
|
|
if o.IsPartOfGroup && o.GroupEmployees > 0 {
|
|
employees = o.GroupEmployees
|
|
}
|
|
if o.IsPartOfGroup && o.GroupRevenue > 0 {
|
|
revenue = o.GroupRevenue
|
|
}
|
|
|
|
// NIS2 size threshold: medium+ enterprises
|
|
// >= 50 employees OR (>= €10m revenue AND >= €10m balance)
|
|
if employees >= 50 {
|
|
return true
|
|
}
|
|
if revenue >= 10_000_000 && balance >= 10_000_000 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// MeetsNIS2LargeThreshold checks if organization meets NIS2 "large" threshold
|
|
// (>= 250 employees OR >= €50m revenue)
|
|
func (o *OrganizationFacts) MeetsNIS2LargeThreshold() bool {
|
|
employees := o.EmployeeCount
|
|
revenue := o.AnnualRevenue
|
|
|
|
if o.IsPartOfGroup && o.GroupEmployees > 0 {
|
|
employees = o.GroupEmployees
|
|
}
|
|
if o.IsPartOfGroup && o.GroupRevenue > 0 {
|
|
revenue = o.GroupRevenue
|
|
}
|
|
|
|
return employees >= 250 || revenue >= 50_000_000
|
|
}
|
|
|
|
// NewUnifiedFacts creates a new UnifiedFacts with default values
|
|
func NewUnifiedFacts() *UnifiedFacts {
|
|
return &UnifiedFacts{
|
|
Organization: OrganizationFacts{Country: "DE", EUMember: true},
|
|
Sector: SectorFacts{},
|
|
DataProtection: DataProtectionFacts{},
|
|
AIUsage: AIUsageFacts{},
|
|
Financial: FinancialFacts{},
|
|
ITSecurity: ITSecurityFacts{},
|
|
SupplyChain: SupplyChainFacts{},
|
|
Personnel: PersonnelFacts{},
|
|
}
|
|
}
|
|
|
|
// FromUseCaseIntake creates UnifiedFacts from an existing UseCaseIntake
|
|
func (f *UnifiedFacts) FromUseCaseIntake(intake *UseCaseIntake) {
|
|
f.UCCAFacts = intake
|
|
|
|
// Map data types
|
|
f.DataProtection.ProcessesPersonalData = intake.DataTypes.PersonalData
|
|
f.DataProtection.ProcessesSpecialCategories = intake.DataTypes.Article9Data
|
|
f.DataProtection.ProcessesMinorData = intake.DataTypes.MinorData
|
|
f.DataProtection.Profiling = intake.Purpose.Profiling
|
|
f.DataProtection.AutomatedDecisionMaking = intake.Purpose.DecisionMaking
|
|
|
|
// Map AI usage
|
|
if intake.ModelUsage.RAG || intake.ModelUsage.Training || intake.ModelUsage.Finetune || intake.ModelUsage.Inference {
|
|
f.AIUsage.UsesAI = true
|
|
f.AIUsage.IsAIDeployer = true
|
|
}
|
|
|
|
// Map sector from domain
|
|
f.MapDomainToSector(string(intake.Domain))
|
|
}
|
|
|
|
// MapDomainToSector maps a UCCA domain to sector facts
|
|
func (f *UnifiedFacts) MapDomainToSector(domain string) {
|
|
// Map common domains to NIS2 sectors
|
|
sectorMap := map[string]string{
|
|
"energy": "energy",
|
|
"utilities": "energy",
|
|
"oil_gas": "energy",
|
|
"banking": "banking_financial",
|
|
"finance": "banking_financial",
|
|
"insurance": "banking_financial",
|
|
"investment": "banking_financial",
|
|
"healthcare": "health",
|
|
"pharma": "health",
|
|
"medical_devices": "health",
|
|
"logistics": "transport",
|
|
"telecom": "digital_infrastructure",
|
|
"it_services": "ict_service_mgmt",
|
|
"cybersecurity": "ict_service_mgmt",
|
|
"public_sector": "public_administration",
|
|
"defense": "public_administration",
|
|
"food_beverage": "food",
|
|
"chemicals": "chemicals",
|
|
"research": "research",
|
|
"education": "education",
|
|
"higher_education": "education",
|
|
}
|
|
|
|
if sector, ok := sectorMap[domain]; ok {
|
|
f.Sector.PrimarySector = sector
|
|
} else {
|
|
f.Sector.PrimarySector = "other"
|
|
}
|
|
|
|
// Set financial flags
|
|
if domain == "banking" || domain == "finance" || domain == "insurance" || domain == "investment" {
|
|
f.Sector.IsFinancialInstitution = true
|
|
f.Financial.IsRegulated = true
|
|
f.Financial.DORAApplies = true
|
|
}
|
|
}
|