package gci import "math" // NIS2Score represents the NIS2-specific compliance score type NIS2Score struct { TenantID string `json:"tenant_id"` OverallScore float64 `json:"overall_score"` MaturityLevel string `json:"maturity_level"` MaturityLabel string `json:"maturity_label"` AreaScores []NIS2AreaScore `json:"area_scores"` RoleCompliance []NIS2RoleScore `json:"role_compliance"` } // NIS2AreaScore represents a NIS2 compliance area type NIS2AreaScore struct { AreaID string `json:"area_id"` AreaName string `json:"area_name"` Score float64 `json:"score"` Weight float64 `json:"weight"` ModuleIDs []string `json:"module_ids"` } // NIS2RoleScore represents completion per NIS2 role type NIS2RoleScore struct { RoleID string `json:"role_id"` RoleName string `json:"role_name"` AssignedUsers int `json:"assigned_users"` CompletionRate float64 `json:"completion_rate"` MandatoryTotal int `json:"mandatory_total"` MandatoryDone int `json:"mandatory_done"` } // NIS2 scoring areas with weights // NIS2Score = 25% Management + 25% Incident + 30% IT Security + 20% Supply Chain var nis2Areas = []struct { ID string Name string Weight float64 ModuleIDs []string }{ { ID: "management", Name: "Management & Governance", Weight: 0.25, ModuleIDs: []string{"nis2-management", "dsgvo-grundlagen", "iso-isms"}, }, { ID: "incident", Name: "Vorfallsbehandlung", Weight: 0.25, ModuleIDs: []string{"nis2-incident-response"}, }, { ID: "it_security", Name: "IT-Sicherheit", Weight: 0.30, ModuleIDs: []string{"nis2-risikomanagement", "iso-zugangssteuerung", "iso-kryptografie"}, }, { ID: "supply_chain", Name: "Lieferkettensicherheit", Weight: 0.20, ModuleIDs: []string{"nis2-supply-chain", "dsgvo-auftragsverarbeitung"}, }, } // CalculateNIS2Score computes the NIS2-specific compliance score func CalculateNIS2Score(tenantID string) *NIS2Score { modules := MockModuleData(tenantID) moduleMap := map[string]ModuleScore{} for _, m := range modules { moduleMap[m.ModuleID] = m } areaScores := []NIS2AreaScore{} totalWeighted := 0.0 for _, area := range nis2Areas { areaScore := NIS2AreaScore{ AreaID: area.ID, AreaName: area.Name, Weight: area.Weight, ModuleIDs: area.ModuleIDs, } scoreSum := 0.0 count := 0 for _, modID := range area.ModuleIDs { if m, ok := moduleMap[modID]; ok { if m.Assigned > 0 { scoreSum += float64(m.Completed) / float64(m.Assigned) * 100 } count++ } } if count > 0 { areaScore.Score = math.Round(scoreSum/float64(count)*10) / 10 } totalWeighted += areaScore.Score * areaScore.Weight areaScores = append(areaScores, areaScore) } overallScore := math.Round(totalWeighted*10) / 10 // Calculate role compliance roleAssignments := MockNIS2RoleAssignments(tenantID) roleScores := calculateNIS2RoleScores(roleAssignments, moduleMap) return &NIS2Score{ TenantID: tenantID, OverallScore: overallScore, MaturityLevel: determineMaturityLevel(overallScore), MaturityLabel: MaturityLabels[determineMaturityLevel(overallScore)], AreaScores: areaScores, RoleCompliance: roleScores, } } func calculateNIS2RoleScores(assignments []NIS2RoleAssignment, moduleMap map[string]ModuleScore) []NIS2RoleScore { // Count users per role roleCounts := map[string]int{} for _, a := range assignments { roleCounts[a.RoleID]++ } scores := []NIS2RoleScore{} for roleID, role := range NIS2Roles { rs := NIS2RoleScore{ RoleID: roleID, RoleName: role.Name, AssignedUsers: roleCounts[roleID], MandatoryTotal: len(role.MandatoryModules), } completionSum := 0.0 for _, modID := range role.MandatoryModules { if m, ok := moduleMap[modID]; ok { if m.Assigned > 0 { rate := float64(m.Completed) / float64(m.Assigned) completionSum += rate if rate >= 0.8 { // 80%+ = considered done rs.MandatoryDone++ } } } } if rs.MandatoryTotal > 0 { rs.CompletionRate = math.Round(completionSum/float64(rs.MandatoryTotal)*100*10) / 10 } scores = append(scores, rs) } return scores }