diff --git a/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go b/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go index 188a48e3..ec7bdd42 100644 --- a/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go +++ b/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go @@ -16,6 +16,7 @@ import ( "git.novox.be/novox/mesh-delivery/modules/mesh-grants/grantsstate" "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/membership" "git.novox.be/novox/mesh-sdk/go/process" "git.novox.be/novox/mesh-sdk/go/seal" "github.com/nats-io/nats-server/v2/server" @@ -37,7 +38,10 @@ func theBusNodeFollowsTheSealedListUnderTheComposedGrants(t *testing.T) { "novox": {{Module: buscompose.GrantsModule, State: []buscompose.Bucket{{Module: buscompose.GrantsModule, Name: "user-list"}}}}, "ace": {{Module: "plex", Reads: []string{buscompose.ComposedRead}}, {Module: "mesh-delivery-view", Reads: []string{buscompose.ComposedRead}, ReadsObjects: []string{"mesh-knowledge_sections"}}, - {Module: "mesh-knowledge", Objects: []buscompose.ObjectBucket{{Module: "mesh-knowledge", Name: "sections", MaxMiB: 1, Restricted: true}}}}, + {Module: "mesh-knowledge", Objects: []buscompose.ObjectBucket{{Module: "mesh-knowledge", Name: "sections", MaxMiB: 1, Restricted: true}}}, + // Issue 1966: a module whose state is asked in `requires`, bound as the bus module said it created it. + {Module: "mod-c", Bindings: []membership.BusBinding{{Local: "kept", Storage: catalogue.StorageKeyValue, + Template: catalogue.TemplateState, Bucket: "mod-c_kept"}}}}, }, } // The bus module and the router as the part composes them from their own manifests (testdata: the catalogue's @@ -50,6 +54,10 @@ func theBusNodeFollowsTheSealedListUnderTheComposedGrants(t *testing.T) { } records.Assigned["novox"] = append(records.Assigned["novox"], fromManifests.Assigned["novox"]...) records.BusState = fromManifests.BusState + if records.BusState == nil { + records.BusState = map[string][]catalogue.BusStateEntry{} + } + records.BusState["mod-c"] = []catalogue.BusStateEntry{{Name: "kept", Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState}} // The node-engine's state as the part's records carry it: every node's compositions (ADR 0593 §6). records.Engine = &buscompose.Declared{Module: buscompose.EngineModule, State: buscompose.EngineComposedBuckets(records.Nodes)} users, err := buscompose.Users(records) @@ -388,6 +396,34 @@ func theBusNodeFollowsTheSealedListUnderTheComposedGrants(t *testing.T) { if _, err := plex.GetLastMsg(sections.Stream(), "$O."+sections.Bucket()+".M.x", nats.DirectGet()); err == nil { t.Error("a module the grant does not name read the bucket") } + // Issue 1966 (ADR 0595 §1, design 25 § 12.7, the binding's usable half): the bus module's keeper creates a key-value + // entry asked in `requires` under its own account, and the module's own account, granted it from its binding, binds the + // bucket by its bus name and writes and reads a key; another module reads nothing of it. + keeperJS, err := jetstream.New(dial("novox.nats.keeper")) + if err != nil { + t.Fatal(err) + } + if _, err := keeperJS.CreateStream(ctx, jetstream.StreamConfig{Name: "KV_mod-c_kept", Subjects: []string{"$KV.mod-c_kept.>"}, + MaxMsgsPerSubject: 1, AllowDirect: true, AllowRollup: true, DenyDelete: true, Discard: jetstream.DiscardNew}); err != nil { + t.Fatalf("the keeper creates mod-c's bound bucket: %v", err) + } + modC, err := jetstream.New(dial("ace.mod-c")) + if err != nil { + t.Fatal(err) + } + bound, err := modC.KeyValue(ctx, "mod-c_kept") + if err != nil { + t.Fatalf("mod-c's own account binds its bound bucket: %v", err) + } + if _, err := bound.Put(ctx, "k", []byte("v")); err != nil { + t.Fatalf("mod-c's own account writes its bound bucket: %v", err) + } + if e, err := bound.Get(ctx, "k"); err != nil || string(e.Value()) != "v" { + t.Errorf("mod-c reads back %v, %v", e, err) + } + if _, err := plex.GetLastMsg("KV_mod-c_kept", "$KV.mod-c_kept.k", nats.DirectGet()); err == nil { + t.Error("another module read mod-c's bound bucket") + } } // manifestIn is a module's manifest as testdata keeps it.