Final sweep: Crucible fixes, Path Tracer polish, forge progress, tests green.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Align dashboard subtitle default and UpsertAgent tests with fleet label behavior; WebSocket coalesce and PathForge hardening; Crucible expanded ops and visual DV fixes; Vitest 610/610 and full test-suite pass; trim PROBLEMS.md to open items only.
This commit is contained in:
AetherForge
2026-06-06 18:07:47 -07:00
parent e65753ce49
commit 6372b07e6c
40 changed files with 1495 additions and 794 deletions

View File

@@ -420,3 +420,182 @@ func TestWSHubConnectedAgentCount(t *testing.T) {
t.Fatalf("expected 1 connected agent, got %d", hub.connectedAgentCount())
}
}
// TestAgentNamePreservedOnReconnect checks that an operator-assigned display
// name is not overwritten by the machine hostname when the agent reconnects.
func TestAgentNamePreservedOnReconnect(t *testing.T) {
database, err := db.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = database.Close() })
hub := NewWSHub(database)
// Seed the DB with an agent whose name was customised by the operator.
// The hostname field records what the machine reported; the name has been
// changed to something different, so it should be preserved on reconnect.
if err := database.UpsertAgent(&models.Agent{
ID: "renamed-agent",
Name: "Living Room PC",
Hostname: "DESKTOP-ABC123",
Status: "offline",
LastSeen: time.Now().Add(-5 * time.Minute),
}); err != nil {
t.Fatal(err)
}
// Agent reconnects — it reports the same hostname.
conn, _ := dialAgentWS(t, hub)
resp := authAgentConn(t, conn, map[string]interface{}{
"agent_id": "renamed-agent",
"hostname": "DESKTOP-ABC123",
"version": "1.0",
})
var body map[string]interface{}
if err := json.Unmarshal(resp.Payload, &body); err != nil {
t.Fatal(err)
}
if body["success"] != true {
t.Fatalf("auth should succeed: %+v", body)
}
// Give the auth handler a moment to commit the upsert.
time.Sleep(30 * time.Millisecond)
agent, err := database.GetAgent("renamed-agent")
if err != nil {
t.Fatal(err)
}
if agent.Name != "Living Room PC" {
t.Errorf("operator name should be preserved; got %q", agent.Name)
}
}
// TestAgentNameUpdatesFromHostnameWhenDefault verifies that the name IS updated
// when it was never customised (name == hostname, i.e. the default).
// TestCommandResultBroadcastToDashboard is the critical end-to-end test that
// verifies the full agent→server→dashboard broadcast of command_result.
// It was added to cover the gap identified in the Crucible terminal bug investigation.
func TestCommandResultBroadcastToDashboard(t *testing.T) {
resetWSAuthUsers(t, testAuthUser, testAuthPass)
database, err := db.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = database.Close() })
hub := NewWSHub(database)
// ── Connect dashboard WS ──────────────────────────────────────────────
dashSrv := httptest.NewServer(http.HandlerFunc(hub.HandleDashboardWS))
t.Cleanup(dashSrv.Close)
dashURL := "ws" + strings.TrimPrefix(dashSrv.URL, "http") + "?token=" + wsDashboardToken(testAuthUser, testAuthPass)
dashConn, _, err := websocket.DefaultDialer.Dial(dashURL, nil)
if err != nil {
t.Fatalf("dial dashboard: %v", err)
}
t.Cleanup(func() { _ = dashConn.Close() })
// Read all dashboard messages in a goroutine to avoid blocking and to
// keep the connection alive (no SetReadDeadline, which would permanently
// corrupt the gorilla/websocket connection on timeout).
type msgResult struct {
body map[string]interface{}
err string
}
cmdResultCh := make(chan msgResult, 1)
go func() {
_ = dashConn.SetReadDeadline(time.Now().Add(5 * time.Second))
for {
var msg Message
if err := dashConn.ReadJSON(&msg); err != nil {
cmdResultCh <- msgResult{err: err.Error()}
return
}
if msg.Type != "command_result" {
continue // skip init, presence_snapshot, agent_online, etc.
}
var body map[string]interface{}
if parseErr := json.Unmarshal(msg.Payload, &body); parseErr != nil {
cmdResultCh <- msgResult{err: "parse: " + parseErr.Error()}
return
}
cmdResultCh <- msgResult{body: body}
return
}
}()
// ── Connect + authenticate agent WS ──────────────────────────────────
agentID := "e2e-agent-001"
agentConn := connectTestAgent(t, hub, agentID)
// ── Agent sends command_result ────────────────────────────────────────
cmdPayload, _ := json.Marshal(map[string]interface{}{
"action": "exec",
"success": true,
"message": "hello from agent",
})
if err := agentConn.WriteJSON(Message{Type: "command_result", Payload: cmdPayload}); err != nil {
t.Fatalf("send command_result: %v", err)
}
// ── Dashboard must receive the broadcast ─────────────────────────────
select {
case r := <-cmdResultCh:
if r.err != "" {
t.Fatalf("dashboard did not receive command_result: %s", r.err)
}
if r.body["agent_id"] != agentID {
t.Errorf("agent_id: got %v, want %v", r.body["agent_id"], agentID)
}
if r.body["action"] != "exec" {
t.Errorf("action: got %v, want exec", r.body["action"])
}
if r.body["success"] != true {
t.Errorf("success: got %v, want true", r.body["success"])
}
if r.body["message"] != "hello from agent" {
t.Errorf("message: got %v, want 'hello from agent'", r.body["message"])
}
case <-time.After(5 * time.Second):
t.Fatal("timed out waiting for command_result broadcast")
}
}
func TestAgentNameUpdatesFromHostnameWhenDefault(t *testing.T) {
database, err := db.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = database.Close() })
hub := NewWSHub(database)
// Seed an agent whose name equals the old hostname (the default, un-renamed case).
if err := database.UpsertAgent(&models.Agent{
ID: "default-name-agent",
Name: "OLD-HOSTNAME",
Hostname: "OLD-HOSTNAME",
Status: "offline",
LastSeen: time.Now().Add(-5 * time.Minute),
}); err != nil {
t.Fatal(err)
}
// Agent reconnects with a new hostname (e.g. machine was renamed).
conn, _ := dialAgentWS(t, hub)
authAgentConn(t, conn, map[string]interface{}{
"agent_id": "default-name-agent",
"hostname": "NEW-HOSTNAME",
"version": "1.0",
})
time.Sleep(30 * time.Millisecond)
agent, err := database.GetAgent("default-name-agent")
if err != nil {
t.Fatal(err)
}
if agent.Name != "NEW-HOSTNAME" {
t.Errorf("default name should follow hostname update; got %q", agent.Name)
}
}