a5b4d29af4
When the box reports the vouched agent version, its running binary's sha256 is compared with the vouched AgentSHA256: same bytes -> "matches vouched", different -> amber DRIFT. An empty hash (older agent) or another version is not comparable and shows nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
64 lines
3.2 KiB
Go
64 lines
3.2 KiB
Go
package web
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
|
|
)
|
|
|
|
// R-349 (hub half): the agent reports the sha256 of the binary it RUNS (top-level agent_sha256). The
|
|
// hub compares it with the vouched AgentSHA256 only when the reported version IS the vouched version;
|
|
// an empty hash is UNKNOWN and never drift.
|
|
const r349Vouched = "a56a92a7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
const r349Hand = "256e0829bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
|
|
func TestR349_AgentBinaryDrift(t *testing.T) {
|
|
m := store.ArtifactManifest{AgentVersion: "0.130.0", AgentSHA256: strings.ToUpper(r349Vouched)}
|
|
cases := []struct{ name, report, want string }{
|
|
{"same version, same bytes", `{"agent_version":"0.130.0","agent_sha256":"` + r349Vouched + `"}`, "ok"},
|
|
{"same version, different bytes (the R-349 case)", `{"agent_version":"0.130.0","agent_sha256":"` + r349Hand + `"}`, "mismatch"},
|
|
{"v-prefixed version still compares", `{"agent_version":"v0.130.0","agent_sha256":"` + r349Hand + `"}`, "mismatch"},
|
|
{"older agent: no hash = unknown", `{"agent_version":"0.130.0"}`, ""},
|
|
{"empty hash = unknown", `{"agent_version":"0.130.0","agent_sha256":""}`, ""},
|
|
{"other version = not comparable", `{"agent_version":"0.129.0","agent_sha256":"` + r349Hand + `"}`, ""},
|
|
{"nested host.agent_sha256 is not the field", `{"agent_version":"0.130.0","host":{"agent_sha256":"` + r349Hand + `"}}`, ""},
|
|
{"no report", ``, ""},
|
|
{"malformed", `{nope`, ""},
|
|
}
|
|
for _, tc := range cases {
|
|
if got, _ := agentBinaryDrift(tc.report, m); got != tc.want {
|
|
t.Errorf("%s: drift = %q, want %q", tc.name, got, tc.want)
|
|
}
|
|
}
|
|
if got, _ := agentBinaryDrift(`{"agent_version":"0.130.0","agent_sha256":"`+r349Hand+`"}`, store.ArtifactManifest{AgentVersion: "0.130.0"}); got != "" {
|
|
t.Errorf("un-vouched hash: drift = %q, want unknown", got)
|
|
}
|
|
}
|
|
|
|
// The page, per branch of the template gate: drift (amber, both hashes), ok, and the unknown case
|
|
// (no line at all).
|
|
func TestR349_HostPageShowsAgentBinaryDrift(t *testing.T) {
|
|
s, st, _ := newRevealServer(t)
|
|
cookie, _ := newRevealSession(t, s)
|
|
if err := st.SetArtifactManifest(store.ArtifactManifest{AgentVersion: "0.130.0", AgentSHA256: r349Vouched}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
seedNetHost(t, st, "h-drift", "0.130.0", `{"agent_version":"0.130.0","agent_sha256":"`+r349Hand+`"}`, "")
|
|
seedNetHost(t, st, "h-ok", "0.130.0", `{"agent_version":"0.130.0","agent_sha256":"`+r349Vouched+`"}`, "")
|
|
seedNetHost(t, st, "h-old", "0.130.0", `{"agent_version":"0.130.0"}`, "")
|
|
|
|
b := getHostPage(t, s, cookie, "h-drift")
|
|
if !strings.Contains(b, `id="agent-binary-drift"`) || !strings.Contains(b, r349Hand[:12]) || !strings.Contains(b, r349Vouched[:12]) {
|
|
t.Fatal("same version, different bytes: the host page shows no agent-binary DRIFT with both hashes")
|
|
}
|
|
b = getHostPage(t, s, cookie, "h-ok")
|
|
if !strings.Contains(b, `id="agent-binary"`) || strings.Contains(b, `id="agent-binary-drift"`) {
|
|
t.Fatal("matching bytes: want the 'matches vouched' line and no drift")
|
|
}
|
|
b = getHostPage(t, s, cookie, "h-old")
|
|
if strings.Contains(b, `id="agent-binary"`) {
|
|
t.Fatal("an agent that reports no hash must show no agent-binary line (unknown, never drift)")
|
|
}
|
|
}
|