diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index fb2896e0..9a64e6fa 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -2271,6 +2271,37 @@ func TestGrants(t *testing.T) { } }) + // TLS-5 (A7's request; ADR 0615 §5): the tool runner, which consumes the owners' views events and keeps a findings state, + // gets its durable consumer on each views stream, made by the part, and its own findings bucket, as any manifest's. + t.Run("the tool runner's consumes of the owners' views get their consumers, and its findings state its grant", func(t *testing.T) { + b := fixture() + b.manifestOf("mesh-delivery-indexer", `{"module":"mesh-delivery-indexer","version":"1","own-secrets":{"broker":"/var/lib/i/broker"},`+ + `"emits":["views.manifests","views.modules"],"streams":[{"name":"indexer-views","events":["views.*"],"max-age-days":7,"max-mib":256}]}`) + b.manifestOf("mesh-delivery-assigner", `{"module":"mesh-delivery-assigner","version":"1","own-secrets":{"broker":"/var/lib/as/broker"},`+ + `"emits":["views.placement","views.seat-holders"],"streams":[{"name":"assigner-views","events":["views.*"],"max-age-days":7,"max-mib":256}]}`) + b.manifestOf("node-tools", `{"module":"node-tools","version":"1","tool-runner":true,"own-secrets":{"broker":"/var/lib/nt/broker"},`+ + `"consumes":["mesh-delivery-assigner.views.placement","mesh-delivery-assigner.views.seat-holders","mesh-delivery-indexer.views.manifests",`+ + `"mesh-delivery-indexer.views.modules"],"state":[{"name":"findings","history":5}]}`) + for _, m := range []string{"mesh-delivery-indexer", "mesh-delivery-assigner", "node-tools"} { + b.assign("a", m) + } + p := partOn(b) + p.Consumers = b + p.Compose() + for _, c := range []string{"INDEXER_VIEWS.a_node-tools", "ASSIGNER_VIEWS.a_node-tools"} { + if !slices.Contains(b.consumerCreates, c) { + t.Errorf("the tool runner's consumer %s was not made: %v", c, b.consumerCreates) + } + } + users := shadowOf(t, b) + runner := users[slices.IndexFunc(users, func(u grants.User) bool { return u.User == "a.node-tools" })] + for _, s := range []string{"$JS.API.CONSUMER.MSG.NEXT.INDEXER_VIEWS.a_node-tools", "$KV.node-tools_findings.>"} { + if !slices.ContainsFunc(runner.Publish, func(g string) bool { return buscompose.SubjectsOverlap(g, s) }) { + t.Errorf("the tool runner may not publish %s: %v", s, runner.Publish) + } + } + }) + // 774/AC4 (novox/hq ADR 0561 §2): every account the vault mints that the records compose is written to the state // accounts once, with the bus's address and a module's claims, read by the vault alone; a key is deleted when placement // no longer names its user, and never in a pass whose reads failed.