Files
Agent-System/internal/controlcenter/server/audit_handlers.go
T

84 lines
2.5 KiB
Go

package server
import (
"errors"
"log/slog"
"net/http"
"strconv"
"chat-agent-system/internal/controlcenter/audit"
)
// SetAudit attaches the audit runner used by the /api/v1/audits routes.
func (s *Server) SetAudit(r *audit.Runner) { s.audit = r }
func (s *Server) handleAuditRunList(w http.ResponseWriter, r *http.Request) {
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
out, err := audit.ListRuns(r.Context(), s.store, limit)
if err != nil {
writeAuditError(w, err)
return
}
writeJSON(w, http.StatusOK, out)
}
func (s *Server) handleAuditFindingList(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
limit, _ := strconv.Atoi(q.Get("limit"))
out, err := audit.ListFindings(r.Context(), s.store, q.Get("status"), q.Get("severity"), limit)
if err != nil {
writeAuditError(w, err)
return
}
writeJSON(w, http.StatusOK, out)
}
// handleAuditRun triggers a manual run in the background and returns the run
// id immediately; a second trigger while one is running gets 409.
func (s *Server) handleAuditRun(w http.ResponseWriter, r *http.Request) {
if s.audit == nil {
writeError(w, http.StatusServiceUnavailable, "audit runner not configured")
return
}
runID, err := audit.StartManual(r.Context(), s.audit)
if err != nil {
writeAuditError(w, err)
return
}
writeJSON(w, http.StatusAccepted, map[string]any{"run_id": runID})
}
func (s *Server) handleAuditFindingConvert(w http.ResponseWriter, r *http.Request) {
fi, err := audit.ConvertFinding(r.Context(), s.store, r.PathValue("id"))
if err != nil {
writeAuditError(w, err)
return
}
slog.Info("audit finding converted", "finding", fi.ID, "task", fi.TaskID)
writeJSON(w, http.StatusOK, fi)
}
func (s *Server) handleAuditFindingDismiss(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if err := audit.DismissFinding(r.Context(), s.store, id); err != nil {
writeAuditError(w, err)
return
}
slog.Info("audit finding dismissed", "finding", id)
writeJSON(w, http.StatusOK, map[string]string{"status": "dismissed"})
}
func writeAuditError(w http.ResponseWriter, err error) {
switch {
case errors.Is(err, audit.ErrAlreadyRunning):
writeError(w, http.StatusConflict, err.Error())
case errors.Is(err, audit.ErrNotFound):
writeError(w, http.StatusNotFound, err.Error())
case errors.Is(err, audit.ErrBadState):
writeError(w, http.StatusConflict, err.Error())
default:
slog.Error("audit handler", "err", err)
writeError(w, http.StatusInternalServerError, "internal error")
}
}