package handlers import ( "encoding/json" "fmt" "net/http" "strings" "forge-mesh/internal/alerts" "forge-mesh/internal/auth" "forge-mesh/internal/config" "forge-mesh/internal/fleet" ) // FleetHandler serves fleet REST endpoints. type FleetHandler struct { Store *fleet.Store Hub *fleet.Hub Alerts *alerts.Notifier Cfg *config.Config OperatorClearance int } func (h *FleetHandler) List(w http.ResponseWriter, r *http.Request) { summary, err := h.Store.BuildFleetSummary() if err != nil { http.Error(w, "internal error", http.StatusInternalServerError) return } auth.JSON(w, http.StatusOK, summary) } type registerRequest struct { Hostname string `json:"hostname"` Fingerprint string `json:"fingerprint"` Arch string `json:"arch"` } func (h *FleetHandler) Register(w http.ResponseWriter, r *http.Request) { var req registerRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "bad request", http.StatusBadRequest) return } if req.Hostname == "" { req.Hostname = "enrolled-host" } host, err := h.Store.TouchHost(req.Hostname, req.Fingerprint, req.Arch) if err != nil { http.Error(w, "register failed", http.StatusInternalServerError) return } auth.JSON(w, http.StatusOK, map[string]any{ "ok": true, "host_id": host.ID, "host": fleet.ToFleetCard(host), }) } func (h *FleetHandler) Command(w http.ResponseWriter, r *http.Request) { hostID := r.PathValue("id") if hostID == "" { http.Error(w, "host id required", http.StatusBadRequest) return } var req struct { Action string `json:"action"` Args map[string]any `json:"args"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "bad request", http.StatusBadRequest) return } action := strings.ToLower(req.Action) if err := fleet.CheckAction(h.OperatorClearance, action); err != nil { auth.JSON(w, http.StatusForbidden, map[string]any{ "error": err.Error(), "required_clearance": fleet.RequiredClearanceOrZero(action), }) return } cmd, err := h.Hub.DispatchCommand(hostID, action, req.Args) if err != nil { http.Error(w, "dispatch failed", http.StatusInternalServerError) return } if h.Alerts != nil && h.Alerts.Enabled() { h.Alerts.Send(alerts.FleetEvent(action, hostID, fmt.Sprintf("cmd: `%s`", cmd.ID))) } auth.JSON(w, http.StatusOK, map[string]any{ "ok": true, "command": cmd, }) }