From 58b3b030db7280ed13094dd60d4c0de76ac29fc0 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 14:42:03 +0100 Subject: [PATCH] GR7: test that a seat's events are published by its holder alone (the holder half of 24149354; its node-backup grant is left out) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds: design 47 G §24, §227, §383, §260 --- .../internal/buscompose/buscompose_test.go | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/modules/mesh-grants/internal/buscompose/buscompose_test.go b/modules/mesh-grants/internal/buscompose/buscompose_test.go index c6cc96e7..43644ab7 100644 --- a/modules/mesh-grants/internal/buscompose/buscompose_test.go +++ b/modules/mesh-grants/internal/buscompose/buscompose_test.go @@ -1337,3 +1337,46 @@ func TestAMachineEventNamesItsNodeWhereTheDefinitionSaysSo(t *testing.T) { t.Errorf("the engine does not hear every node's running: %v", sub) } } + +// Design 47 (W8.6): the events of a seat held once (`freed`, `pinned`, `owed`) are published by the account of the module that +// holds it alone, so the gate's is the one that says them and the checker's the one that says its own seat's `owed`; a module +// that holds neither, and one that only uses the seat, is granted neither. +func TestASeatsEventsArePublishedByItsHolderAlone(t *testing.T) { + gate := Seat{Name: "mesh-delivery", Scope: "mesh", Emits: []string{"freed", "pinned", "owed.*.*"}} + checker := Seat{Name: "mesh-delivery-checker", Scope: "mesh", Emits: []string{"owed.*.*"}} + records := Records{Nodes: []string{"one"}, Assigned: map[string][]Declared{"one": { + {Module: "gate", Holds: []Seat{gate}, Uses: []Seat{checker}}, + {Module: "checker", Holds: []Seat{checker}, Uses: []Seat{gate}}, + {Module: "forge", Uses: []Seat{gate, checker}}, + }}} + users, err := Users(records) + if err != nil { + t.Fatal(err) + } + perms := map[string]Permissions{} + for _, u := range users { + p, err := PermissionsFor(u) + if err != nil { + t.Fatal(err) + } + perms[u.Username()] = p + } + for _, row := range []struct { + who, subject string + may bool + }{ + {"one.gate", "mesh.seat.mesh-delivery.event.freed", true}, + {"one.gate", "mesh.seat.mesh-delivery.event.pinned", true}, + {"one.gate", "mesh.seat.mesh-delivery.event.owed.r.1", true}, + {"one.gate", "mesh.seat.mesh-delivery-checker.event.owed.r.1", false}, + {"one.checker", "mesh.seat.mesh-delivery-checker.event.owed.r.1", true}, + {"one.checker", "mesh.seat.mesh-delivery.event.owed.r.1", false}, + {"one.checker", "mesh.seat.mesh-delivery.event.freed", false}, + {"one.forge", "mesh.seat.mesh-delivery.event.freed", false}, + {"one.forge", "mesh.seat.mesh-delivery-checker.event.owed.r.1", false}, + } { + if got := MayPublish(perms[row.who], row.subject); got != row.may { + t.Errorf("%s may publish %s = %v, want %v", row.who, row.subject, got, row.may) + } + } +}