Files
breakpilot-compliance/breakpilot-compliance-sdk/services/security-scanner/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

217 lines
5.1 KiB
Go

// Package api provides HTTP handlers for the Security Scanner
package api
import (
"net/http"
"github.com/breakpilot/compliance-sdk/services/security-scanner/internal/scanner"
"github.com/gin-gonic/gin"
)
// ScanRequest represents a scan request
type ScanRequest struct {
Tools []string `json:"tools"`
TargetPath string `json:"target_path"`
ExcludePaths []string `json:"exclude_paths"`
}
// StartScan starts a new security scan
func StartScan(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
var req ScanRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
tools := req.Tools
if len(tools) == 0 {
tools = manager.AvailableTools()
}
scan := manager.StartScan(tools, req.TargetPath)
c.JSON(http.StatusAccepted, gin.H{
"scan_id": scan.ID,
"status": scan.Status,
"tools": scan.Tools,
"started_at": scan.StartedAt,
})
}
}
// GetScanStatus returns the status of a scan
func GetScanStatus(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
scanID := c.Param("scanId")
scan := manager.GetScan(scanID)
if scan == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Scan not found"})
return
}
c.JSON(http.StatusOK, gin.H{
"scan_id": scan.ID,
"status": scan.Status,
"started_at": scan.StartedAt,
"completed_at": scan.CompletedAt,
"summary": scan.Summary,
})
}
}
// GetScanResults returns the results of a scan
func GetScanResults(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
scanID := c.Param("scanId")
scan := manager.GetScan(scanID)
if scan == nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Scan not found"})
return
}
c.JSON(http.StatusOK, scan)
}
}
// GetFindings returns all findings
func GetFindings(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
findings := manager.GetAllFindings()
severity := c.Query("severity")
tool := c.Query("tool")
status := c.Query("status")
// Filter findings
filtered := []scanner.Finding{}
for _, f := range findings {
if severity != "" && f.Severity != severity {
continue
}
if tool != "" && f.Tool != tool {
continue
}
if status != "" && f.Status != status {
continue
}
filtered = append(filtered, f)
}
c.JSON(http.StatusOK, gin.H{
"findings": filtered,
"total": len(filtered),
})
}
}
// GetFinding returns a specific finding
func GetFinding(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
findingID := c.Param("findingId")
findings := manager.GetAllFindings()
for _, f := range findings {
if f.ID == findingID {
c.JSON(http.StatusOK, f)
return
}
}
c.JSON(http.StatusNotFound, gin.H{"error": "Finding not found"})
}
}
// UpdateFindingStatus updates the status of a finding
func UpdateFindingStatus(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
findingID := c.Param("findingId")
var req struct {
Status string `json:"status" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if manager.UpdateFindingStatus(findingID, req.Status) {
c.JSON(http.StatusOK, gin.H{
"id": findingID,
"status": req.Status,
})
} else {
c.JSON(http.StatusNotFound, gin.H{"error": "Finding not found"})
}
}
}
// GenerateSBOM generates a Software Bill of Materials
func GenerateSBOM(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
var req struct {
TargetPath string `json:"target_path"`
}
c.ShouldBindJSON(&req)
sbom := manager.GenerateSBOM(req.TargetPath)
c.JSON(http.StatusOK, sbom)
}
}
// GetSBOM returns an SBOM by ID
func GetSBOM(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
// In production, retrieve from storage
sbom := manager.GenerateSBOM("")
c.JSON(http.StatusOK, sbom)
}
}
// ExportSBOM exports an SBOM in the specified format
func ExportSBOM(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
format := c.Param("format")
sbom := manager.GenerateSBOM("")
sbom.Format = format
var contentType string
switch format {
case "cyclonedx":
contentType = "application/vnd.cyclonedx+json"
case "spdx":
contentType = "application/spdx+json"
default:
c.JSON(http.StatusBadRequest, gin.H{"error": "Unsupported format"})
return
}
c.Header("Content-Type", contentType)
c.Header("Content-Disposition", "attachment; filename=sbom."+format+".json")
c.JSON(http.StatusOK, sbom)
}
}
// GetRecommendations returns security recommendations
func GetRecommendations(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
recs := manager.GetRecommendations()
c.JSON(http.StatusOK, gin.H{
"recommendations": recs,
"total": len(recs),
})
}
}
// GetToolsStatus returns the status of all tools
func GetToolsStatus(manager *scanner.Manager) gin.HandlerFunc {
return func(c *gin.Context) {
tools := manager.GetTools()
c.JSON(http.StatusOK, gin.H{"tools": tools})
}
}