89af88ef7d
- Übersicht: Completeness Gates durch Projektfortschritts-Tracker ersetzt (6 CE-Prozessschritte mit Status + Naechster-Schritt Empfehlung) - Verifikation: GET/POST/DELETE /verifications Endpoints + Alias-Handler - Tech-File: Anhang IV Struktur-Erweiterung - Maßnahmen: Expandable Details vorbereitet Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
161 lines
4.5 KiB
Go
161 lines
4.5 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
|
|
"github.com/breakpilot/ai-compliance-sdk/internal/rbac"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Mitigations
|
|
// ============================================================================
|
|
|
|
// ListProjectMitigations handles GET /projects/:id/mitigations
|
|
// Returns all mitigations for all hazards in a project.
|
|
func (h *IACEHandler) ListProjectMitigations(c *gin.Context) {
|
|
projectID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
|
|
return
|
|
}
|
|
|
|
mitigations, err := h.store.ListMitigationsByProject(c.Request.Context(), projectID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if mitigations == nil {
|
|
mitigations = []iace.Mitigation{}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"mitigations": mitigations,
|
|
"total": len(mitigations),
|
|
})
|
|
}
|
|
|
|
// CreateMitigation handles POST /projects/:id/hazards/:hid/mitigations
|
|
// Creates a new mitigation measure for a hazard.
|
|
func (h *IACEHandler) CreateMitigation(c *gin.Context) {
|
|
projectID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"})
|
|
return
|
|
}
|
|
|
|
hazardID, err := uuid.Parse(c.Param("hid"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid hazard ID"})
|
|
return
|
|
}
|
|
|
|
var req iace.CreateMitigationRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Override hazard ID from URL path
|
|
req.HazardID = hazardID
|
|
|
|
mitigation, err := h.store.CreateMitigation(c.Request.Context(), req)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Update hazard status to mitigated
|
|
h.store.UpdateHazard(c.Request.Context(), hazardID, map[string]interface{}{
|
|
"status": string(iace.HazardStatusMitigated),
|
|
})
|
|
|
|
// Audit trail
|
|
userID := rbac.GetUserID(c)
|
|
newVals, _ := json.Marshal(mitigation)
|
|
h.store.AddAuditEntry(
|
|
c.Request.Context(), projectID, "mitigation", mitigation.ID,
|
|
iace.AuditActionCreate, userID.String(), nil, newVals,
|
|
)
|
|
|
|
c.JSON(http.StatusCreated, gin.H{"mitigation": mitigation})
|
|
}
|
|
|
|
// UpdateMitigation handles PUT /mitigations/:mid
|
|
// Updates a mitigation measure with the provided fields.
|
|
func (h *IACEHandler) UpdateMitigation(c *gin.Context) {
|
|
mitigationID, err := uuid.Parse(c.Param("mid"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid mitigation ID"})
|
|
return
|
|
}
|
|
|
|
var updates map[string]interface{}
|
|
if err := c.ShouldBindJSON(&updates); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
mitigation, err := h.store.UpdateMitigation(c.Request.Context(), mitigationID, updates)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
if mitigation == nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "mitigation not found"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"mitigation": mitigation})
|
|
}
|
|
|
|
// DeleteMitigation handles DELETE /projects/:id/mitigations/:mid
|
|
// Deletes a mitigation by ID.
|
|
func (h *IACEHandler) DeleteMitigation(c *gin.Context) {
|
|
mitigationID, err := uuid.Parse(c.Param("mid"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid mitigation ID"})
|
|
return
|
|
}
|
|
|
|
if err := h.store.DeleteMitigation(c.Request.Context(), mitigationID); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "mitigation deleted"})
|
|
}
|
|
|
|
// VerifyMitigation handles POST /mitigations/:mid/verify
|
|
// Marks a mitigation as verified with a verification result.
|
|
func (h *IACEHandler) VerifyMitigation(c *gin.Context) {
|
|
mitigationID, err := uuid.Parse(c.Param("mid"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid mitigation ID"})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
VerificationResult string `json:"verification_result" binding:"required"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
userID := rbac.GetUserID(c)
|
|
|
|
if err := h.store.VerifyMitigation(
|
|
c.Request.Context(), mitigationID, req.VerificationResult, userID.String(),
|
|
); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "mitigation verified"})
|
|
}
|