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>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
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 ""
|
||||
}
|
||||
Reference in New Issue
Block a user