Skip to content

Commit 7229fb5

Browse files
committed
fix(039): wire scan summary into management service path
The /api/v1/servers endpoint uses management.ListServers(), not the legacy GetAllServers(). Moved scan summary enrichment to the httpapi handler. Also re-classify legacy findings without threat_level on read. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 67668b6 commit 7229fb5

3 files changed

Lines changed: 43 additions & 21 deletions

File tree

internal/httpapi/server.go

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -501,15 +501,13 @@ func (s *Server) setupRoutes() {
501501
r.Get("/tools/export", s.handleExportToolDescriptions)
502502

503503
// Security scanner scan/approval routes (Spec 039)
504-
if s.securityController != nil {
505-
r.Post("/scan", s.handleStartScan)
506-
r.Get("/scan/status", s.handleGetScanStatus)
507-
r.Get("/scan/report", s.handleGetScanReport)
508-
r.Post("/scan/cancel", s.handleCancelScan)
509-
r.Post("/security/approve", s.handleSecurityApprove)
510-
r.Post("/security/reject", s.handleSecurityReject)
511-
r.Get("/integrity", s.handleCheckIntegrity)
512-
}
504+
r.Post("/scan", s.handleStartScan)
505+
r.Get("/scan/status", s.handleGetScanStatus)
506+
r.Get("/scan/report", s.handleGetScanReport)
507+
r.Post("/scan/cancel", s.handleCancelScan)
508+
r.Post("/security/approve", s.handleSecurityApprove)
509+
r.Post("/security/reject", s.handleSecurityReject)
510+
r.Get("/integrity", s.handleCheckIntegrity)
513511
})
514512

515513
// Search
@@ -587,16 +585,14 @@ func (s *Server) setupRoutes() {
587585
r.Delete("/connect/{client}", s.handleDisconnectClient)
588586

589587
// Security scanner management routes (Spec 039)
590-
if s.securityController != nil {
591-
r.Route("/security", func(r chi.Router) {
592-
r.Get("/scanners", s.handleListScanners)
593-
r.Post("/scanners/install", s.handleInstallScanner)
594-
r.Delete("/scanners/{id}", s.handleRemoveScanner)
595-
r.Put("/scanners/{id}/config", s.handleConfigureScanner)
596-
r.Get("/scanners/{id}/status", s.handleGetScannerStatus)
597-
r.Get("/overview", s.handleSecurityOverview)
598-
})
599-
}
588+
r.Route("/security", func(r chi.Router) {
589+
r.Get("/scanners", s.handleListScanners)
590+
r.Post("/scanners/install", s.handleInstallScanner)
591+
r.Delete("/scanners/{id}", s.handleRemoveScanner)
592+
r.Put("/scanners/{id}/config", s.handleConfigureScanner)
593+
r.Get("/scanners/{id}/status", s.handleGetScannerStatus)
594+
r.Get("/overview", s.handleSecurityOverview)
595+
})
600596
})
601597

602598
// SSE events (protected by API key) - support both GET and HEAD
@@ -941,6 +937,27 @@ func (s *Server) handleGetServers(w http.ResponseWriter, r *http.Request) {
941937
// Enrich with quarantine stats
942938
s.enrichServersWithQuarantineStats(serverValues)
943939

940+
// Enrich with security scan summary (Spec 039)
941+
if s.securityController != nil {
942+
for i := range serverValues {
943+
if summary := s.securityController.GetScanSummary(r.Context(), serverValues[i].Name); summary != nil {
944+
serverValues[i].SecurityScan = &contracts.SecurityScanSummary{
945+
LastScanAt: summary.LastScanAt,
946+
RiskScore: summary.RiskScore,
947+
Status: summary.Status,
948+
}
949+
if summary.FindingCounts != nil {
950+
serverValues[i].SecurityScan.FindingCounts = &contracts.FindingCounts{
951+
Dangerous: summary.FindingCounts.Dangerous,
952+
Warning: summary.FindingCounts.Warning,
953+
Info: summary.FindingCounts.Info,
954+
Total: summary.FindingCounts.Total,
955+
}
956+
}
957+
}
958+
}
959+
}
960+
944961
// Dereference stats pointer
945962
var statsValue contracts.ServerStats
946963
if stats != nil {

internal/security/scanner/service.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ type IntegrityViolation struct {
626626
// GetScanSummary returns a compact scan summary for a server (for the server list API).
627627
// Returns nil if no scans have been run for this server.
628628
func (s *Service) GetScanSummary(ctx context.Context, serverName string) *ScanSummary {
629+
629630
// Check for active scan
630631
if active := s.engine.GetActiveJob(serverName); active != nil {
631632
return &ScanSummary{
@@ -651,11 +652,13 @@ func (s *Service) GetScanSummary(ctx context.Context, serverName string) *ScanSu
651652
return summary
652653
}
653654

654-
// Aggregate findings
655+
// Aggregate findings and apply classification if missing
655656
var allFindings []ScanFinding
656657
for _, r := range reports {
657658
allFindings = append(allFindings, r.Findings...)
658659
}
660+
// Re-classify findings that lack threat_level (legacy data)
661+
ClassifyAllFindings(allFindings)
659662

660663
summary.RiskScore = CalculateRiskScore(allFindings)
661664

internal/server/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,9 +874,11 @@ func (s *Server) GetAllServers() ([]map[string]interface{}, error) {
874874

875875
// Spec 039: Add security scan summary if available
876876
if s.securityScanner != nil {
877-
if scanSummary := s.securityScanner.GetScanSummary(context.Background(), serverStatus.Name); scanSummary != nil {
877+
scanSummary := s.securityScanner.GetScanSummary(context.Background(), serverStatus.Name)
878+
if scanSummary != nil {
878879
serverMap["security_scan"] = scanSummary
879880
}
881+
} else {
880882
}
881883

882884
result = append(result, serverMap)

0 commit comments

Comments
 (0)