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 34s
CI / test-python-backend-compliance (push) Successful in 28s
CI / test-python-document-crawler (push) Successful in 24s
CI / test-python-dsms-gateway (push) Successful in 17s
Implements the 4-level GCI scoring model (Module -> Risk-Weighted -> Regulation Area -> Final GCI) with DSGVO, NIS2, ISO 27001, and EU AI Act integration. Backend: - 9 Go files: engine, models, weights, validity, NIS2 roles/scoring, ISO mapping/gap-analysis, mock data - GCI handlers with 13 API endpoints under /sdk/v1/gci/ - Routes registered in main.go Frontend: - TypeScript types, API client, Next.js API proxy - Dashboard page with 6 tabs (Overview, Breakdown, NIS2, ISO 27001, Matrix, Audit Trail) - Sidebar navigation entry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
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
|
|
}
|