EE-D2: the tool runner's runtime hears every event subject
Where the runtime's permissions are composed, a runtime carrying the tool runner subscribes mesh-sdk's EveryEvent (every seat's, module's and module stream's events) and nothing else for it, replacing the per-family list. Builds: design 34 every-event §6, §8, §25, §27 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/buildstep"
|
||||
"git.novox.be/novox/mesh-sdk/go/announce"
|
||||
sdkbc "git.novox.be/novox/mesh-sdk/go/buscompose"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
@@ -60,6 +61,7 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
|
||||
t.Run("a module's ledger is written by its ledger account alone", aLedgerIsWrittenByItsLedgerAccountAlone)
|
||||
t.Run("the bus module's process alone keeps every module's bus state and serves the broker's verbs", theBusModulesProcessKeepsBusState)
|
||||
t.Run("a process serving a verb is granted its calls and chunk subjects, and the reverse goes to an account naming it", chunkSubjectsFollowTheAnswerer)
|
||||
t.Run("the tool runner's runtime hears every event subject and nothing wider", theToolRunnerHearsEveryEvent)
|
||||
// ADR 0567 §3, §9: a node reads every key of the seat's assignments and its candidates (it composes with the whole
|
||||
// proposal laid over), and none of its open proposals; it writes neither.
|
||||
reads := strings.Join(NodeComposeReads("laptop"), " ")
|
||||
@@ -1447,3 +1449,70 @@ func chunkSubjectsFollowTheAnswerer(t *testing.T) {
|
||||
t.Errorf("the keeper's restore grant reaches a stream that is not restricted")
|
||||
}
|
||||
}
|
||||
|
||||
// EE-D2 (design 34 every-event §6, §8, §25, §27; ADR 0670 §1, §3, ADR 0671 §1): the runtime carrying the tool runner
|
||||
// subscribes the three event subjects of mesh-sdk's EveryEvent, beside a module with a restricted stream, and nothing
|
||||
// wider; it publishes no other module's or seat's event and derives no durable consumer or acknowledgement on that
|
||||
// stream; a runtime carrying no tool runner gets none of the three.
|
||||
func theToolRunnerHearsEveryEvent(t *testing.T) {
|
||||
shop := func() Declared {
|
||||
return Declared{Module: "shop", Serves: []string{"sell"}, Emits: []string{"sold"},
|
||||
Streams: []ModuleStream{{Module: "shop", Name: "LEDGER", Events: []string{"booked"}, Restricted: true}}}
|
||||
}
|
||||
r := Records{Nodes: []string{"a", "b"}, Assigned: map[string][]Declared{
|
||||
"a": {{Module: "node-tools", ToolRunner: true}, shop()},
|
||||
"b": {shop()}}}
|
||||
users, err := Users(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
every := sdkbc.EveryEvent()
|
||||
if len(every) != 3 {
|
||||
t.Fatalf("EveryEvent answers %v, want three subjects", every)
|
||||
}
|
||||
wider := []string{">", "mesh.>", "mesh.*.>", "mesh.seat.>", "mesh.mod.>", "mesh.stream.>"}
|
||||
runners := 0
|
||||
for _, u := range users {
|
||||
p, err := PermissionsFor(u)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", u.Username(), err)
|
||||
}
|
||||
runs := false
|
||||
for _, d := range u.Carries {
|
||||
runs = runs || d.ToolRunner
|
||||
}
|
||||
for _, e := range every {
|
||||
if slices.Contains(p.Subscribe, e) != runs {
|
||||
t.Errorf("%s (tool runner %v) subscribes %s: %v", u.Username(), runs, e, !runs)
|
||||
}
|
||||
}
|
||||
for _, s := range p.Subscribe {
|
||||
if slices.Contains(wider, s) {
|
||||
t.Errorf("%s subscribes %s, wider than every event", u.Username(), s)
|
||||
}
|
||||
}
|
||||
if !runs {
|
||||
continue
|
||||
}
|
||||
runners++
|
||||
for _, s := range p.Subscribe {
|
||||
if strings.HasPrefix(s, "$JS.") && strings.Contains(s, "LEDGER") {
|
||||
t.Errorf("the tool runner's runtime hears %s on the restricted stream", s)
|
||||
}
|
||||
}
|
||||
for _, s := range []string{"mesh.mod.other.event.x", "mesh.seat.mesh-catalog.event.manifest-accepted",
|
||||
"mesh.stream.other.event.x"} {
|
||||
if MayPublish(p, s) {
|
||||
t.Errorf("the tool runner's runtime may publish another's event %s", s)
|
||||
}
|
||||
}
|
||||
for _, s := range p.Publish {
|
||||
if strings.Contains(s, "LEDGER") || strings.HasPrefix(s, "$JS.ACK.") {
|
||||
t.Errorf("the tool runner's runtime may %s on the restricted stream", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
if runners != 1 {
|
||||
t.Errorf("%d runtimes carry the tool runner, want 1", runners)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1192,6 +1192,13 @@ func permissionsFor(p Principal) (Permissions, error) {
|
||||
pub = append(pub, logGrants(d.Module, logNames(d.Logs))...)
|
||||
pub = append(pub, readLogGrants(d.ReadLogs)...)
|
||||
}
|
||||
// **And every event subject** (design 34 every-event §6, §25; novox/hq ADR 0670 §1, ADR 0671 §1): the runtime
|
||||
// carrying the tool runner hears every seat's, module's and module stream's events, a restricted stream
|
||||
// included, as a plain subscription: no publish, no durable consumer, no acknowledgement and no deny is added
|
||||
// for it, and a runtime carrying no tool runner gets none of them.
|
||||
if slices.ContainsFunc(p.Carries, func(d Declared) bool { return d.ToolRunner }) {
|
||||
sub = append(sub, sdkbc.EveryEvent()...)
|
||||
}
|
||||
// **Never the traffic of a trusted holder** (novox/hq ADR 0259 §8): the machine's runtime runs as the
|
||||
// operator's account, which every agent runs as, so a module saying warrants or speaking for a kind
|
||||
// that proves its sender is never composed into it — refused here, naming it, whatever registration
|
||||
|
||||
@@ -589,7 +589,7 @@ func Composed(d Declared) bool { return d.Module != EngineModule }
|
||||
func CarriedByRunner(d Declared) bool { return Composed(d) && d.RunsAs == "" && runnerServes(d) }
|
||||
|
||||
// runnerServes says the machine's tool runner has something of this module to serve (novox/hq ADR 0436 §1,
|
||||
// ADR 0437 §4, issue 1329): tools or loads it answers, a seat it holds, event families a session waits on,
|
||||
// ADR 0437 §4, issue 1329): tools or loads it answers, a seat it holds,
|
||||
// a bundle the runtime loads (Loads), or a check its health asks. A module with none of these is a process of its own on its own credential, and
|
||||
// carrying it would hand every session on the machine the runner's account with that module's state, seat
|
||||
// traffic and streams. A module with no account of its own (NoAccount) is spoken for by the runner, so it
|
||||
|
||||
Reference in New Issue
Block a user