Files
felhom.eu/hub/internal/web/agent_only_vouch_test.go
T
admin 7d64038f02
gates / gates (push) Successful in 6m45s
Hub v0.158.0 code (built, NOT deployed): agent-only vouch, R-895 snapshot alarms, the hub's own 90-day access log (R-1140 A); installer --rotate-recovery-only (R-1141); 02/03/05/09 + break-glass
Hub: the R-120 golden guard judges only a CHANGED golden selection; offsite_snapshots_vanished /
_unexplained (operator-only, hub-origin) on the 07:10 listing; internal/accesslog writes path-only
lines to /data/access-log, 90 days. Installer: --rotate-recovery-only runs step 4b alone (rides
the next installer tag). 03: the orphan check runs after a failed backup (agent 6545ccc). 02: the
allow-list is empty, appdata_folders (controller v0.329.0). All red-proofed.
2026-10-17 23:31:34 +02:00

83 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package web
import (
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
)
// Agent-only vouch (`09` §3 decision 250 items 3–4, hub v0.158.0). The golden is baked weekly while the floor carries
// controller releases, so mid-week the vouched golden is behind the fleet. The R-120 gate guards a golden SELECTION:
// an unchanged golden (same version, same sha) is not a selection and must not block an agent-only save; a changed
// golden is judged exactly as before. Both tests drive handleSetArtifacts — the only UI writer of the manifest.
func postArtifacts(t *testing.T, s *Server, form url.Values) *httptest.ResponseRecorder {
t.Helper()
r := httptest.NewRequest(http.MethodPost, "/configuration/artifacts", strings.NewReader(form.Encode()))
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
s.handleSetArtifacts(w, r)
return w
}
// The mid-week situation: golden 0.330.0 vouched on Sunday, the floor has since carried the fleet to 0.335.0, and the
// operator vouches a new agent. RED-PROOF (REPORT, 2026-10-17 night): with the `!goldenUnchanged` condition removed
// from the gate, this fails: `agent-only vouch refused: Location="/configuration?flash=golden_behind_fleet"`.
func TestVouchAgentOnlyWithStaleGoldenIsSaved(t *testing.T) {
s, st := newTestServer(t)
seedReport(t, st, "demo", "0.335.0")
golden := strings.Repeat("b", 64)
if err := st.SetArtifactManifest(store.ArtifactManifest{
AgentVersion: "0.159.0", AgentSHA256: strings.Repeat("a", 64),
GoldenVersion: "0.330.0", GoldenSHA256: golden, MinAgent: "0.150.0",
}); err != nil {
t.Fatal(err)
}
w := postArtifacts(t, s, url.Values{
"agent_version": {"0.160.0"}, "agent_sha256": {strings.Repeat("c", 64)},
"golden_version": {"0.330.0"}, "golden_sha256": {golden}, "min_agent": {"0.150.0"},
})
if loc := w.Header().Get("Location"); !strings.Contains(loc, "flash=artifacts_set") {
t.Fatalf("agent-only vouch refused: Location=%q, want flash=artifacts_set", loc)
}
m := st.GetArtifactManifest()
if m.AgentVersion != "0.160.0" || m.AgentSHA256 != strings.Repeat("c", 64) {
t.Fatalf("agent not saved: agent=%s sha=%s…", m.AgentVersion, m.AgentSHA256[:4])
}
if m.GoldenVersion != "0.330.0" || m.GoldenSHA256 != golden || m.MinAgent != "0.150.0" {
t.Fatalf("golden/MinAgent moved on an agent-only save: %+v", m)
}
}
// A golden CHANGED to an older one is still refused, even though the agent changes in the same save — and nothing is
// written. Also the same version under a different sha (a re-push) is a changed golden.
func TestVouchGoldenChangedToOlderIsStillRefused(t *testing.T) {
s, st := newTestServer(t)
seedReport(t, st, "demo", "0.335.0")
cur := store.ArtifactManifest{
AgentVersion: "0.159.0", AgentSHA256: strings.Repeat("a", 64),
GoldenVersion: "0.330.0", GoldenSHA256: strings.Repeat("b", 64),
}
if err := st.SetArtifactManifest(cur); err != nil {
t.Fatal(err)
}
for name, form := range map[string]url.Values{
"older version": {"agent_version": {"0.160.0"}, "agent_sha256": {strings.Repeat("c", 64)},
"golden_version": {"0.329.0"}, "golden_sha256": {strings.Repeat("d", 64)}},
"same version, other sha": {"agent_version": {"0.160.0"}, "agent_sha256": {strings.Repeat("c", 64)},
"golden_version": {"0.330.0"}, "golden_sha256": {strings.Repeat("e", 64)}},
} {
w := postArtifacts(t, s, form)
if loc := w.Header().Get("Location"); !strings.Contains(loc, "golden_behind_fleet") {
t.Errorf("%s: Location=%q, want the golden_behind_fleet refusal", name, loc)
}
if m := st.GetArtifactManifest(); m != cur {
t.Errorf("%s: refused but the manifest changed: %+v", name, m)
}
}
}