Files
breakpilot-compliance/breakpilot-compliance-sdk/services/compliance-engine/internal/api/handlers.go
Benjamin Boenisch 4435e7ea0a Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance,
AI-Compliance-SDK, Consent-SDK, Developer-Portal,
PCA-Platform, DSMS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:28 +01:00

330 lines
8.3 KiB
Go

// Package api provides HTTP handlers for the Compliance Engine
package api
import (
"net/http"
"time"
"github.com/breakpilot/compliance-sdk/services/compliance-engine/internal/ucca"
"github.com/gin-gonic/gin"
)
// Assess performs a full compliance assessment
func Assess(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
var state map[string]interface{}
if err := c.ShouldBindJSON(&state); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result := engine.Assess(state)
result.Timestamp = time.Now().Format(time.RFC3339)
c.JSON(http.StatusOK, result)
}
}
// AssessControl assesses a single control
func AssessControl(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
var req struct {
ControlID string `json:"control_id" binding:"required"`
State map[string]interface{} `json:"state"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
controls := engine.GetControls()
ctrl, exists := controls[req.ControlID]
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "Control not found"})
return
}
c.JSON(http.StatusOK, gin.H{
"control": ctrl,
"status": "ASSESSED",
"compliance": true,
"recommendations": []string{},
})
}
}
// AssessRegulation assesses compliance with a specific regulation
func AssessRegulation(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
var req struct {
RegulationCode string `json:"regulation_code" binding:"required"`
State map[string]interface{} `json:"state"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
regulations := engine.GetRegulations()
reg, exists := regulations[req.RegulationCode]
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "Regulation not found"})
return
}
result := engine.Assess(req.State)
c.JSON(http.StatusOK, gin.H{
"regulation": reg,
"score": result.ByRegulation[req.RegulationCode],
"findings": filterFindings(result.Findings, req.RegulationCode),
"assessed_at": time.Now().Format(time.RFC3339),
})
}
}
// CalculateScore calculates the compliance score
func CalculateScore(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
var state map[string]interface{}
if err := c.ShouldBindJSON(&state); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result := engine.Assess(state)
c.JSON(http.StatusOK, gin.H{
"overall": result.OverallScore,
"trend": result.Trend,
"by_regulation": result.ByRegulation,
"by_domain": result.ByDomain,
"calculated_at": time.Now().Format(time.RFC3339),
})
}
}
// ScoreBreakdown provides a detailed score breakdown
func ScoreBreakdown(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
var state map[string]interface{}
if err := c.ShouldBindJSON(&state); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
result := engine.Assess(state)
// Calculate detailed breakdown
breakdown := gin.H{
"overall": gin.H{
"score": result.OverallScore,
"max": 100,
"trend": result.Trend,
"description": getScoreDescription(result.OverallScore),
},
"by_regulation": []gin.H{},
"by_domain": []gin.H{},
"by_category": gin.H{
"documentation": 75,
"technical": 80,
"organizational": 70,
},
}
for reg, score := range result.ByRegulation {
breakdown["by_regulation"] = append(
breakdown["by_regulation"].([]gin.H),
gin.H{"code": reg, "score": score, "status": getStatus(score)},
)
}
for domain, score := range result.ByDomain {
breakdown["by_domain"] = append(
breakdown["by_domain"].([]gin.H),
gin.H{"domain": domain, "score": score, "status": getStatus(score)},
)
}
c.JSON(http.StatusOK, breakdown)
}
}
// GetObligations returns all regulatory obligations
func GetObligations(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
regulations := engine.GetRegulations()
obligations := []gin.H{}
for code, reg := range regulations {
for _, article := range reg.Articles {
obligations = append(obligations, gin.H{
"id": code + "-" + article,
"regulation_code": code,
"regulation_name": reg.Name,
"article": article,
"status": "PENDING",
})
}
}
c.JSON(http.StatusOK, gin.H{
"obligations": obligations,
"total": len(obligations),
})
}
}
// GetObligationsByRegulation returns obligations for a specific regulation
func GetObligationsByRegulation(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
regCode := c.Param("regulation")
regulations := engine.GetRegulations()
reg, exists := regulations[regCode]
if !exists {
c.JSON(http.StatusNotFound, gin.H{"error": "Regulation not found"})
return
}
obligations := []gin.H{}
for _, article := range reg.Articles {
obligations = append(obligations, gin.H{
"id": regCode + "-" + article,
"regulation_code": regCode,
"article": article,
"status": "PENDING",
})
}
c.JSON(http.StatusOK, gin.H{
"regulation": reg,
"obligations": obligations,
"total": len(obligations),
})
}
}
// GetControlsCatalog returns the controls catalog
func GetControlsCatalog(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
controls := engine.GetControls()
result := []gin.H{}
for _, ctrl := range controls {
result = append(result, gin.H{
"id": ctrl.ID,
"name": ctrl.Name,
"description": ctrl.Description,
"domain": ctrl.Domain,
"category": ctrl.Category,
"objective": ctrl.Objective,
})
}
c.JSON(http.StatusOK, gin.H{
"controls": result,
"total": len(result),
})
}
}
// GetControlsByDomain returns controls for a specific domain
func GetControlsByDomain(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
domain := c.Param("domain")
controls := engine.GetControlsByDomain(domain)
result := []gin.H{}
for _, ctrl := range controls {
result = append(result, gin.H{
"id": ctrl.ID,
"name": ctrl.Name,
"description": ctrl.Description,
"category": ctrl.Category,
"objective": ctrl.Objective,
"guidance": ctrl.Guidance,
"evidence": ctrl.Evidence,
})
}
c.JSON(http.StatusOK, gin.H{
"domain": domain,
"controls": result,
"total": len(result),
})
}
}
// ListPolicies lists all loaded policies
func ListPolicies(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"total_rules": engine.RuleCount(),
"total_regulations": len(engine.GetRegulations()),
"total_controls": len(engine.GetControls()),
"regulations": getRegulationCodes(engine),
})
}
}
// GetPolicy returns details of a specific policy
func GetPolicy(engine *ucca.Engine) gin.HandlerFunc {
return func(c *gin.Context) {
policyID := c.Param("id")
regulations := engine.GetRegulations()
if reg, exists := regulations[policyID]; exists {
c.JSON(http.StatusOK, reg)
return
}
c.JSON(http.StatusNotFound, gin.H{"error": "Policy not found"})
}
}
// Helper functions
func filterFindings(findings []ucca.Finding, regulation string) []ucca.Finding {
result := []ucca.Finding{}
for _, f := range findings {
if f.Regulation == regulation {
result = append(result, f)
}
}
return result
}
func getScoreDescription(score int) string {
switch {
case score >= 90:
return "Excellent - Full compliance achieved"
case score >= 75:
return "Good - Minor improvements needed"
case score >= 50:
return "Fair - Significant work required"
default:
return "Poor - Major compliance gaps exist"
}
}
func getStatus(score int) string {
switch {
case score >= 80:
return "COMPLIANT"
case score >= 60:
return "PARTIAL"
default:
return "NON_COMPLIANT"
}
}
func getRegulationCodes(engine *ucca.Engine) []string {
regulations := engine.GetRegulations()
codes := make([]string, 0, len(regulations))
for code := range regulations {
codes = append(codes, code)
}
return codes
}