From fdbb3d578450b56b0baddd61057226de40bcebae Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 2 Nov 2026 00:12:08 +0100 Subject: [PATCH] Add the seat mesh-grants, so the grants part can claim the lease write as a seat verb ADR 0582 clause 1 makes the lease write a verb of the seat mesh-grants: lease-write and lease-hand-back, each taking a why, and the events lease-handed, lease-altered and removal-failed. The indexer's judge reads seats through catalogue.SeatNamed, so it accepts mesh-grants' claim once it pins this head. Test: TestTheGrantsSeatPromisesTheLeaseWrite (new), paid by merging the two ssh tests of filtering_test.go into TestSSHIsOpenFromTheMeshEvenWhenNothingIsAssigned. (issue 774, 774/S1) Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- go/catalogue/filtering_test.go | 9 ++--- go/catalogue/grants_seat.go | 53 +++++++++++++++++++++++++ go/catalogue/grants_seat_test.go | 67 ++++++++++++++++++++++++++++++++ go/catalogue/seats.go | 3 ++ 4 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 go/catalogue/grants_seat.go create mode 100644 go/catalogue/grants_seat_test.go diff --git a/go/catalogue/filtering_test.go b/go/catalogue/filtering_test.go index 8bf1e00..81f3765 100644 --- a/go/catalogue/filtering_test.go +++ b/go/catalogue/filtering_test.go @@ -744,12 +744,9 @@ func TestSSHIsOpenFromTheMeshEvenWhenNothingIsAssigned(t *testing.T) { if strings.Contains(nft, "\t\ttcp dport 22 accept") { t.Fatalf("ssh is open to everywhere on a machine that faces inward only:\n%s", nft) } -} - -// And from outside as well, on a machine that faces outward — because that is the way in when the -// private network is the thing that broke. -func TestSSHIsOpenFromOutsideOnAMachineThatFacesIt(t *testing.T) { - nft := AsNftables(nil, []string{"198.51.100.2"}, true, nil, nil, "mesh0") + // And from outside as well, on a machine that faces outward — because that is the way in when the + // private network is the thing that broke. + nft = AsNftables(nil, []string{"198.51.100.2"}, true, nil, nil, "mesh0") if !strings.Contains(nft, "\t\ttcp dport 22 accept") { t.Fatalf("a machine reachable from outside does not answer ssh there:\n%s", nft) } diff --git a/go/catalogue/grants_seat.go b/go/catalogue/grants_seat.go new file mode 100644 index 0000000..5d12b55 --- /dev/null +++ b/go/catalogue/grants_seat.go @@ -0,0 +1,53 @@ +package catalogue + +// **The lease write, a verb of the seat `mesh-grants`** (novox/hq ADR 0582 clause 1, issue 774): the grants part +// holds the seat once for the mesh and, on the operator's warrant, hands the controller's lease to itself and back. +// It serves two verbs and says three events, none carrying a secret: +// +// - lease-handed: the lease names mesh-grants, written on the operator's warrant (clause 3); +// - lease-altered: the lease key or its bucket's expiry differs from what mesh-grants wrote (clause 4); +// - removal-failed: the day-later removal of the controller's consumer or stream failed (clause 6). + +// GrantsSeat is the seat the grants part (mesh-grants) holds. +const GrantsSeat = "mesh-grants" + +// The seat's verbs. +const ( + GrantsVerbLeaseWrite = "lease-write" + GrantsVerbLeaseHandBack = "lease-hand-back" +) + +// The seat's events. +const ( + GrantsEventLeaseHanded = "lease-handed" + GrantsEventLeaseAltered = "lease-altered" + GrantsEventRemovalFailed = "removal-failed" +) + +// grantsDecision is the record that made the seat. +const grantsDecision = "novox/hq ADR 0582" + +// grantsEvents are the seat's events, in the order the write meets them. +func grantsEvents() []string { + return []string{GrantsEventLeaseHanded, GrantsEventLeaseAltered, GrantsEventRemovalFailed} +} + +// grantsVerbs are the seat's verbs (ADR 0582 clauses 1, 2, 3, 5). +func grantsVerbs() []Verb { + return []Verb{ + {Name: GrantsVerbLeaseWrite, Description: "Hand the controller's lease to mesh-grants, kept for good. Refused, " + + "naming the check, until the lease check at phase write passes and every condition it does not judge reads " + + "green. Otherwise the operator is asked once; on the warrant the checks are read again, the controller's " + + "service is stopped, the bus's user list is composed without the controller's write on the lease, the lease's " + + "expiry is removed and the key holder names mesh-grants, said as lease-handed and recorded as a hand act. A no " + + "or an expiry of the ask acts on nothing.", + Input: schema(map[string]string{"why": "why the lease is handed now, shown to the operator and kept"}, + []string{"why"})}, + {Name: GrantsVerbLeaseHandBack, Description: "Give the lease back to the controller, for a day after the write: " + + "asked and warranted the same way, it restores the lease's fifteen-second expiry, deletes the key holder, " + + "gives the controller its rights back once the list is loaded, and starts the controller. Refused once the " + + "day-later removal ran: the controller would start without its consumer and stream.", + Input: schema(map[string]string{"why": "why the lease goes back, shown to the operator and kept"}, + []string{"why"})}, + } +} diff --git a/go/catalogue/grants_seat_test.go b/go/catalogue/grants_seat_test.go new file mode 100644 index 0000000..fe45b76 --- /dev/null +++ b/go/catalogue/grants_seat_test.go @@ -0,0 +1,67 @@ +package catalogue + +import ( + "reflect" + "strings" + "testing" +) + +// The seat mesh-grants (novox/hq ADR 0582 clause 1, issue 774): its holder serves lease-write and lease-hand-back, both +// a condition of holding, and nothing else; the seat says lease-handed, lease-altered and removal-failed. +func TestTheGrantsSeatPromisesTheLeaseWrite(t *testing.T) { + seat, ok := SeatNamed(GrantsSeat) + if !ok { + t.Fatal("the seat mesh-grants is not in the set") + } + if seat.Scope != ScopeMesh || seat.Delivers != "" { + t.Errorf("mesh-grants is at scope %q delivering %q, want mesh and nothing", seat.Scope, seat.Delivers) + } + if got, want := VerbNames(seat.Serves), []string{"lease-write", "lease-hand-back"}; !reflect.DeepEqual(got, want) { + t.Errorf("mesh-grants serves %v, want %v", got, want) + } + if want := []string{"lease-handed", "lease-altered", "removal-failed"}; !reflect.DeepEqual(seat.Emits, want) { + t.Errorf("mesh-grants says %v, want %v", seat.Emits, want) + } + for _, v := range seat.Serves { + if v.Optional { + t.Errorf("%s is optional: the holder ships with the seat, so every verb is a condition of holding", v.Name) + } + props, _ := v.Input["properties"].(map[string]any) + if req, _ := v.Input["required"].([]string); len(props) != 1 || !reflect.DeepEqual(req, []string{"why"}) { + t.Errorf("%s takes %v requiring %v, want only a why", v.Name, props, req) + } + } + + claim := func(serves ...string) Manifest { + return Manifest{Module: "mesh-grants", Claims: []Claim{{Name: GrantsSeat, Scope: ScopeMesh, Serves: serves}}} + } + for _, c := range []struct { + name string + m Manifest + refuse string // empty: held + }{ + {"both verbs", claim("lease-write", "lease-hand-back"), ""}, + {"without the hand-back", claim("lease-write"), "lease-hand-back"}, + {"a verb the seat does not promise", claim("lease-write", "lease-hand-back", "lease-take"), "lease-take"}, + {"at node scope", Manifest{Module: "mesh-grants", Claims: []Claim{{Name: GrantsSeat, Scope: ScopeNode, + Serves: []string{"lease-write", "lease-hand-back"}}}}, "scope"}, + } { + err := CanHold(c.m, seat) + switch { + case c.refuse == "" && err != nil: + t.Errorf("%s: refused: %v", c.name, err) + case c.refuse != "" && (err == nil || !strings.Contains(err.Error(), c.refuse)): + t.Errorf("%s: %v, want a refusal naming %q", c.name, err, c.refuse) + } + } + + // No other seat changed: the set is the one before it with mesh-grants added beside mesh-hand-acts. + var names []string + for _, s := range DefaultSeats() { + names = append(names, s.Name) + } + at := strings.Index(strings.Join(names, " "), HandActsSeat+" "+GrantsSeat+" ") + if at < 0 { + t.Errorf("mesh-grants does not follow mesh-hand-acts in the seat set: %v", names) + } +} diff --git a/go/catalogue/seats.go b/go/catalogue/seats.go index bef2fc7..4dc4536 100644 --- a/go/catalogue/seats.go +++ b/go/catalogue/seats.go @@ -302,6 +302,9 @@ var defaultSeats = append([]Seat{ // policy and the bus step at the assigner, and the hand-act log. {Name: WantsSeat, Scope: ScopeMesh, Decision: controlRecordsDecision, Emits: []string{"policy-changed"}, Serves: wantsVerbs()}, {Name: HandActsSeat, Scope: ScopeMesh, Decision: controlRecordsDecision, Emits: []string{"act-recorded"}, Serves: handActsVerbs()}, + // The lease write (novox/hq ADR 0582 clause 1, grants_seat.go): the grants part hands the controller's lease to + // itself and back on the operator's warrant. + {Name: GrantsSeat, Scope: ScopeMesh, Decision: grantsDecision, Emits: grantsEvents(), Serves: grantsVerbs()}, // The artifact sweep (novox/hq ADR 0571 clause 2, artifact_sweep_seat.go). {Name: ArtifactSweepSeat, Scope: ScopeMesh, Decision: "novox/hq ADR 0571", Emits: []string{"artifacts-gone"}, Serves: artifactSweepVerbs()},