Files
LINUX-AETHERFORGE/internal/api/handlers/fleet.go
drjones 3678b199d0
Some checks failed
Test / test (push) Has been cancelled
Initial commit: AetherForge Linux (forge-mesh) v0.1.0-dev
2026-07-04 09:31:23 +00:00

102 lines
2.4 KiB
Go

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,
})
}