Files
mesh-controller/internal/broker/announced_test.go
T
jschoubben d543ff7126 Judge each read for its reader with mesh-sdk's ReadsAnnouncedBy, so the parts named for the lease are granted it, and say a refusal once (issue 774)
2536 reads of mesh-controller.lease were refused on 2026-10-30 (mesh-vault, mesh-grants, the assigner,
artifact-store-tools, the watchman, mesh-config). The controller composed the bus's users with its own
copy of a reader-less judgement (internal/broker ReadsAnnounced), which knows no named readers: the lease
is announced readable by nobody and read by the parts named for it (ADR 0547 clause 9, ADR 0561 §3). The
copy is deleted; BusRecords judges each read for its module with buscompose.ReadsAnnouncedBy. Each
refusal was also printed on every composition, about 420 times a read; it is now said once per process.

mesh-config's read of the lease stays refused: it reads the lease for its take-over (hand-back ends at
the lease write, ADR 0561 §3) and is not among the named readers. That is mesh-sdk's NamedReaders,
routed to the lead.

Quick fix: mark the lease readable in the controller's announcement (tried and reverted: it would open
the lease to every module and contradict ADR 0561 §3). Thorough fix: one judgement, the SDK's, for every
composer. Chose thorough.

Research 072 piece: 03-domains, mesh-grants (bus membership and grants leave the controller): the
controller composes reads with the same SDK function the grants part uses.
2026-10-30 18:15:17 +01:00

76 lines
2.7 KiB
Go

package broker
import (
"slices"
"testing"
"git.novox.be/novox/mesh-sdk/go/announce"
)
// D1 (ADR 0495 clause 2): the controller announces every bucket of its own, and readable exactly the record mirrors (the
// declared packages the pacman module reads among them, ADR 0507 §5), the chain's buckets, the checks running and the
// plans building.
func TestTheControllerAnnouncesWhatItKeeps(t *testing.T) {
s := ControllerAnnouncement("novox")
if _, err := announce.Encode(s); err != nil {
t.Fatal(err)
}
var readable []string
for _, k := range s.States {
if k.Readable {
readable = append(readable, k.Name)
}
}
want := []string{ChainBuilds, MirrorDeclaredConfig, MirrorPredefined, ChainRollouts,
MirrorAssignments, MirrorDeclaredPackages, ControllerGrants, ControllerComposed}
slices.Sort(want)
if !slices.Equal(readable, want) {
t.Fatalf("readable %v, want %v", readable, want)
}
for _, name := range []string{"lease", "calls", "states-announced"} {
if !s.Keeps(name) || s.Readable(name) {
t.Errorf("%s: kept %v, readable %v", name, s.Keeps(name), s.Readable(name))
}
}
// The buckets of plan state release 6 deleted are no longer kept (ADR 0539 clause 13).
for _, name := range []string{"merge-window", "rollout-silent", "plans-building"} {
if s.Keeps(name) {
t.Errorf("%s is still kept", name)
}
}
perms, err := PermissionsFor(Principal{Kind: KindController})
if err != nil {
t.Fatal(err)
}
if !slices.Contains(perms.Publish, announce.Subject(ControllerSeat)) {
t.Fatal("the controller may not say what it keeps")
}
}
// D2: every account that keeps state may say so on its own subject, a process account included, and no other's.
func TestAnAccountKeepingStateMaySayWhatItKeeps(t *testing.T) {
keeper, err := PermissionsFor(Principal{Kind: KindModule, Node: "one", Module: "keeper", PasswordHash: "x",
State: []string{"things"}})
if err != nil {
t.Fatal(err)
}
if !slices.Contains(keeper.Publish, announce.Subject("keeper")) || slices.Contains(keeper.Publish, announce.Subject("other")) {
t.Fatalf("the keeper's announcement grants: %v", keeper.Publish)
}
process, err := PermissionsFor(Principal{Kind: KindProcess, Node: "one", Module: "keeper", Process: "send",
PasswordHash: "x", State: []string{"sends"}})
if err != nil {
t.Fatal(err)
}
if !slices.Contains(process.Publish, announce.Subject("keeper")) {
t.Fatal("a process keeping state may not say what it keeps")
}
none, err := PermissionsFor(Principal{Kind: KindModule, Node: "one", Module: "stateless", PasswordHash: "x"})
if err != nil {
t.Fatal(err)
}
if slices.Contains(none.Publish, announce.Subject("stateless")) {
t.Fatal("a module keeping nothing may say it keeps something")
}
}