Files
breakpilot-compliance/ai-compliance-sdk/internal/api/handlers/iace_handler_compliance.go
T
Benjamin Admin 56892cf7dc feat: CE × Compliance Crossover Engine
Automatische Erkennung von DSGVO/AI Act/CRA/NIS2/Data Act
Implikationen bei CE-Gefaehrdungen. 50 Trigger-Mappings auf
Hazard-Patterns → Compliance-Module mit Modul-Links.

- compliance_triggers.go: 50 Pattern→Regulation Mappings
- compliance_crossover.go: Engine die Projekt-Hazards gegen Trigger prueft
- iace_handler_compliance.go: GET /compliance-triggers API
- ComplianceAlerts.tsx: Frontend Alert-Panel auf Projekt-Uebersicht

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 15:07:22 +02:00

87 lines
2.9 KiB
Go

package handlers
import (
"net/http"
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// ============================================================================
// CE x Compliance Crossover Engine
// ============================================================================
// GetComplianceTriggers handles GET /projects/:id/compliance-triggers.
// It analyses the project's hazards and component patterns to determine
// which DSGVO, AI Act, CRA, NIS2, and EU Data Act obligations are triggered.
// The response includes deduplicated triggers sorted by severity, plus boolean
// summary flags (dsfa_required, ai_act_relevant, cra_relevant, etc.).
func (h *IACEHandler) GetComplianceTriggers(c *gin.Context) {
projectID, err := uuid.Parse(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
return
}
// Verify project exists
project, err := h.store.GetProject(c.Request.Context(), projectID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if project == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "project not found"})
return
}
// Fetch all hazards for this project
hazards, err := h.store.ListHazards(c.Request.Context(), projectID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to load hazards: " + err.Error()})
return
}
// Also run pattern matching with component tags to catch tag-based triggers.
// Collect tags from the project's components (reuse the norms handler logic).
componentTags := collectComponentTags(h, c, projectID)
// Get all patterns from the pattern library
allPatterns := iace.AllPatterns()
// Additionally derive extra fired patterns by re-matching component tags
// against the pattern engine. This ensures patterns that are not yet
// applied as hazards still contribute their compliance triggers.
engine := iace.NewPatternEngine()
matchInput := iace.MatchInput{
CustomTags: componentTags,
}
matchResult := engine.Match(matchInput)
// Merge matched pattern IDs into a pseudo-hazard list so the crossover
// engine picks them up. We create lightweight Hazard structs with the
// pattern ID embedded in the Description field.
mergedHazards := make([]iace.Hazard, len(hazards))
copy(mergedHazards, hazards)
for _, pm := range matchResult.MatchedPatterns {
mergedHazards = append(mergedHazards, iace.Hazard{
Name: pm.PatternName,
Description: "Pattern " + pm.PatternID,
Category: firstOrEmpty(pm.HazardCats),
})
}
// Run the crossover engine
summary := iace.GetProjectComplianceTriggers(mergedHazards, allPatterns)
c.JSON(http.StatusOK, summary)
}
// firstOrEmpty returns the first element of a string slice or "".
func firstOrEmpty(ss []string) string {
if len(ss) > 0 {
return ss[0]
}
return ""
}