Files
felhom.eu/hub/internal/store/declared_floor_test.go
T
admin f181efd6a7
gates / gates (push) Successful in 18s
hub v0.112.0: a floor carries a declared MinAgent past the golden (R-472)
Operator ruling 2026-09-13. Above the vouched golden, a floor saved with a
declared MinAgent is served under the same agent comparison; an undeclared
one is still held beyond the golden. The declaration is stored beside each
floor as FLOOR=MINAGENT so it never carries to a later floor. Both floor
forms require min_agent above the golden (flash floor_needs_min_agent,
nothing stored). The Hosts page and the API log name the source.

Vouch path and R-120 gate untouched. Scenarios A-E tested; red-proofs A
and C in documentation/audits/rulings-r472-r475-2026-09-13/.
2026-09-13 16:47:11 +02:00

117 lines
5.2 KiB
Go

package store
import (
"strings"
"testing"
)
// R-472 (hub v0.112.0) — a floor above the vouched golden carries its own declared MinAgent.
//
// The golden is 0.236.0 with manifest MinAgent 0.129.0 in every case — the live numbers of
// 2026-09-13 — so the tests exercise the exact shape that was HELD in production.
func declaredBase(t *testing.T, agent string) *Store {
t.Helper()
s := newTestStore(t)
if err := s.SetArtifactManifest(ArtifactManifest{GoldenVersion: "0.236.0", MinAgent: "0.129.0"}); err != nil {
t.Fatal(err)
}
setHostAgent(t, s, "c1", "h1", agent)
return s
}
// SCENARIO A — above the golden, MinAgent declared, agent new enough → SERVED, source "declared".
//
// COMPANION RED-PROOF A (REPORT.md): delete the `beyondGolden && d.DeclaredMinAgent != ""` branch
// from ResolveManagedFloor. The floor is then held beyond the golden and this test fails.
func TestDeclaredMinAgent_A_AboveGoldenServedWhenAgentMeetsIt(t *testing.T) {
s := declaredBase(t, "0.129.0")
_ = s.SetGlobalMinControllerVersion("0.239.0")
_ = s.SetGlobalFloorDeclaredMinAgent("0.239.0", "0.129.0")
fd := s.ResolveManagedFloor("c1")
if fd.Held || fd.Floor != "0.239.0" {
t.Fatalf("a declared floor above the golden must be SERVED: %+v (reason %q)", fd, fd.HoldReason())
}
if fd.MinAgentSource != MinAgentSourceDeclared || fd.MinAgent != "0.129.0" {
t.Errorf("the decision must say the requirement was declared: %+v", fd)
}
}
// SCENARIO B — declared, but the agent is too old → HELD with the ORIGINAL agent sentence.
func TestDeclaredMinAgent_B_AgentBelowDeclaredIsHeldWithTheOriginalText(t *testing.T) {
s := declaredBase(t, "0.128.0")
_ = s.SetGlobalMinControllerVersion("0.239.0")
_ = s.SetGlobalFloorDeclaredMinAgent("0.239.0", "0.129.0")
fd := s.ResolveManagedFloor("c1")
if !fd.Held || fd.Floor != "" || fd.HeldBeyondGolden {
t.Fatalf("an agent below the declared MinAgent must be HELD for the agent reason: %+v", fd)
}
if want := "held: agent 0.128.0 < MinAgent 0.129.0"; fd.HoldReason() != want {
t.Errorf("hold text = %q, want %q", fd.HoldReason(), want)
}
}
// SCENARIO C — the NEGATIVE CONTROL: above the golden with NO declaration → held beyond golden,
// exactly today's text.
//
// COMPANION RED-PROOF C (REPORT.md): make an undeclared floor above the golden fall through to the
// agent comparison. It is then SERVED and this test fails.
func TestDeclaredMinAgent_C_UndeclaredAboveGoldenIsHeldExactlyAsBefore(t *testing.T) {
s := declaredBase(t, "0.130.0")
_ = s.SetGlobalMinControllerVersion("0.239.0")
fd := s.ResolveManagedFloor("c1")
if !fd.Held || !fd.HeldBeyondGolden || fd.Floor != "" {
t.Fatalf("an UNDECLARED floor above the golden must stay held beyond the golden: %+v", fd)
}
if !strings.Contains(fd.HoldReason(), "is ABOVE the vouched golden 0.236.0, so its agent requirement is unknown") {
t.Errorf("the hold text must be unchanged: %q", fd.HoldReason())
}
}
// SCENARIO D — at/below the golden with a declaration anyway → the MANIFEST governs, the
// declaration is recorded and not used.
func TestDeclaredMinAgent_D_InsideTheGoldenTheManifestGoverns(t *testing.T) {
s := declaredBase(t, "0.129.5")
_ = s.SetGlobalMinControllerVersion("0.236.0")
_ = s.SetGlobalFloorDeclaredMinAgent("0.236.0", "0.130.0") // stricter than the manifest, on purpose
fd := s.ResolveManagedFloor("c1")
if fd.Held || fd.Floor != "0.236.0" {
t.Fatalf("inside the golden the manifest's 0.129.0 governs, so agent 0.129.5 is served: %+v", fd)
}
if fd.MinAgentSource != MinAgentSourceManifest || fd.MinAgent != "0.129.0" || fd.DeclaredMinAgent != "0.130.0" {
t.Errorf("the declaration must be recorded but not used inside the golden: %+v", fd)
}
}
// A declaration describes ONE release. Raising the floor without re-declaring must not inherit it.
func TestDeclaredMinAgent_DoesNotCarryToADifferentFloor(t *testing.T) {
s := declaredBase(t, "0.130.0")
_ = s.SetGlobalMinControllerVersion("0.239.0")
_ = s.SetGlobalFloorDeclaredMinAgent("0.239.0", "0.129.0")
_ = s.SetGlobalMinControllerVersion("0.240.0") // raised by another path, no new declaration
if got := s.GlobalFloorDeclaredMinAgent(); got != "" {
t.Fatalf("a declaration made for 0.239.0 must not apply to 0.240.0, got %q", got)
}
if fd := s.ResolveManagedFloor("c1"); !fd.HeldBeyondGolden {
t.Errorf("the undeclared 0.240.0 must be held beyond the golden: %+v", fd)
}
}
// The per-customer override's OWN declaration wins where the override wins — never the global one.
func TestDeclaredMinAgent_PerCustomerDeclarationWinsWithItsOverride(t *testing.T) {
s := declaredBase(t, "0.129.0")
if err := s.SaveCustomerConfig(&CustomerConfig{CustomerID: "c1", RetrievalPassword: "x", APIKey: "y"}); err != nil {
t.Fatal(err)
}
_ = s.SetGlobalMinControllerVersion("0.239.0")
_ = s.SetGlobalFloorDeclaredMinAgent("0.239.0", "0.129.0")
_ = s.SetMinControllerVersion("c1", "0.241.0") // override, undeclared
if fd := s.ResolveManagedFloor("c1"); !fd.HeldBeyondGolden {
t.Fatalf("an undeclared OVERRIDE must not borrow the global floor's declaration: %+v", fd)
}
_ = s.SetCustomerFloorDeclaredMinAgent("c1", "0.241.0", "0.129.0")
if fd := s.ResolveManagedFloor("c1"); fd.Held || fd.Floor != "0.241.0" || fd.MinAgentSource != MinAgentSourceDeclared {
t.Fatalf("the override's own declaration must serve it: %+v", fd)
}
}