feat(gap): IST-Zustand Assessment — IACE + Normen + Prozesse

Gap Analysis v2: statt 500 generische Gaps → nur die ECHTEN Lücken.

Backend:
- ProductProfile um 15 IST-Felder erweitert (Normen, Doku, Prozesse, CE)
- assessGapStatus prüft: IACE-Mitigations → Zertifizierungen → Normen → IST-Felder
- norm_mapping.go: 20 Normen → MC-Topic Mapping (ISO 12100, IEC 62443, etc.)
- IACE-Integration: CheckIACECoverage() matcht verified Mitigations gegen MCs

Frontend:
- 2-Step Wizard: Produkt beschreiben → IST-Zustand erfassen
- IstAssessment.tsx: CE-Jahr, Normen-Multiselect, Doku+Prozess Checkboxen
- Step-Navigation mit visuellen Indikatoren

Migration 025 erweitert um IST-Felder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-11 08:33:17 +02:00
parent 285b74382a
commit 8f169cbae3
7 changed files with 473 additions and 19 deletions
+65 -3
View File
@@ -35,19 +35,29 @@ func (s *Store) CreateProfile(p *ProductProfile) error {
marketsJSON, _ := json.Marshal(p.Markets)
certsJSON, _ := json.Marshal(p.ExistingCertifications)
normsJSON, _ := json.Marshal(p.AppliedNorms)
_, err := s.pool.Exec(ctx, `
INSERT INTO compliance.gap_projects
(id, tenant_id, name, description, product_type,
technologies, data_processing, markets,
connected_to_internet, has_software_updates, uses_ai,
processes_personal_data, is_critical_infra_supplier,
existing_certifications, created_at, updated_at)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)`,
existing_certifications, applied_norms,
has_risk_assessment, has_technical_file, has_operating_manual, has_sbom,
has_vuln_management, has_update_mechanism, has_incident_response, has_supply_chain_mgmt,
ce_marking_since, product_age, iace_project_id,
created_at, updated_at)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28)`,
p.ID, p.TenantID, p.Name, p.Description, p.ProductType,
techJSON, dataJSON, marketsJSON,
p.ConnectedToInternet, p.HasSoftwareUpdates, p.UsesAI,
p.ProcessesPersonalData, p.IsCriticalInfraSupplier,
certsJSON, p.CreatedAt, p.UpdatedAt,
certsJSON, normsJSON,
p.HasRiskAssessment, p.HasTechnicalFile, p.HasOperatingManual, p.HasSBOM,
p.HasVulnManagement, p.HasUpdateMechanism, p.HasIncidentResponse, p.HasSupplyChainMgmt,
p.CEMarkingSince, p.ProductAge, p.IACEProjectID,
p.CreatedAt, p.UpdatedAt,
)
return err
}
@@ -227,6 +237,58 @@ func sourceToRegID(source string) RegulationID {
}
}
// CheckIACECoverage checks if an IACE project has verified mitigations
// covering the given MC topic.
func (s *Store) CheckIACECoverage(projectID uuid.UUID, mcTopic string) string {
ctx := context.Background()
// Map MC topics to IACE hazard categories
iaceCategory := mcTopicToIACECategory(mcTopic)
if iaceCategory == "" {
return ""
}
var verifiedCount, implementedCount int
err := s.pool.QueryRow(ctx, `
SELECT
COUNT(CASE WHEN m.status = 'verified' THEN 1 END),
COUNT(CASE WHEN m.status = 'implemented' THEN 1 END)
FROM iace_mitigations m
JOIN iace_hazards h ON h.id = m.hazard_id
WHERE h.project_id = $1
AND (h.category ILIKE $2 OR h.sub_category ILIKE $2)`,
projectID, "%"+iaceCategory+"%",
).Scan(&verifiedCount, &implementedCount)
if err != nil || (verifiedCount == 0 && implementedCount == 0) {
return ""
}
if verifiedCount > 0 {
return "verified"
}
return "implemented"
}
func mcTopicToIACECategory(topic string) string {
mapping := map[string]string{
"encryption": "cyber",
"access_control": "software",
"network_security": "cyber",
"vulnerability": "cyber",
"product_safety": "mechanical",
"physical_security": "electrical",
"monitoring": "software",
"incident": "organizational",
"risk_management": "general",
}
for prefix, cat := range mapping {
if strings.HasPrefix(topic, prefix) {
return cat
}
}
return ""
}
func formatTitle(name string) string {
return strings.ReplaceAll(
strings.ReplaceAll(name, "_", " "),