From ea3bfa5e6e507406211f215f231e5791a04bcfc3 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 27 Oct 2026 21:02:49 +0100 Subject: [PATCH 1/3] Grant every node the keys a provider elsewhere serves from, and give the composition check frombus's new reads, pinning mesh-sdk cebc651 (issue 1126) mesh-grants declares each module's served settings (catalogue.ServedSettings), so the user list grants every other node's agent those keys of mesh-config_resolved alone: shanks then settles what novox's mailu serves. The assigner's check of every node reads no build, archive or served value: it composes as before. --- .../cmd/mesh-delivery-assigner/world.go | 14 ++++++++++++++ modules/mesh-delivery-assigner/go.mod | 2 +- modules/mesh-delivery-assigner/go.sum | 2 ++ modules/mesh-grants/go.mod | 2 +- modules/mesh-grants/go.sum | 2 ++ modules/mesh-grants/grants_test.go | 13 +++++++++++++ modules/mesh-grants/internal/grants/records.go | 2 ++ 7 files changed, 35 insertions(+), 2 deletions(-) diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/world.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/world.go index f0d2949..6ebbe6a 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/world.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/world.go @@ -368,6 +368,20 @@ func (worldReader) Credentials(context.Context, string, []compose.CredentialKey, return nil, nil, nil } +// Build, Archive and Served are read only for a node composing itself (frombus.Scope without Every): the check of every +// node composes from the manifests the indexer read, reads no build and no archive, and reads no config value. +func (worldReader) Build(context.Context, string, string) (*delivery.BuilderBuild, error) { + return nil, nil +} + +func (worldReader) Archive(_ context.Context, url, _ string) ([]byte, error) { + return nil, fmt.Errorf("the composition check reads no archive (%s)", url) +} + +func (worldReader) Served(context.Context, string, string, []string) (map[string]any, error) { + return nil, nil +} + // change is a candidate's change for the composition check, or why the composition waits for it. func (w *world) change(ctx context.Context, manifests getter, c delivery.Candidate, trunk map[string]delivery.Module) (assign.Change, string) { ch := assign.Change{Group: c.Group, Heads: c.HeadsHash, Manifests: map[string]catalogue.Manifest{}, Unreadable: map[string]string{}, diff --git a/modules/mesh-delivery-assigner/go.mod b/modules/mesh-delivery-assigner/go.mod index 73e5df7..5685a33 100644 --- a/modules/mesh-delivery-assigner/go.mod +++ b/modules/mesh-delivery-assigner/go.mod @@ -3,7 +3,7 @@ module mesh-delivery-assigner go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-delivery-assigner/go.sum b/modules/mesh-delivery-assigner/go.sum index 0082dd1..38b8a0c 100644 --- a/modules/mesh-delivery-assigner/go.sum +++ b/modules/mesh-delivery-assigner/go.sum @@ -12,6 +12,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027012704-062c29c3a22f h1:AKzV973U git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027012704-062c29c3a22f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f h1:mimAGERguQmCGYVNdRTrFcZ1dhpU6GWo+Q3EDhHOrVk= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 h1:9B7B38e3RtjbtX1uGP9dRgU9VY1/J2yAfnb5Ajoq4/s= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-grants/go.mod b/modules/mesh-grants/go.mod index b6cf662..5cd03af 100644 --- a/modules/mesh-grants/go.mod +++ b/modules/mesh-grants/go.mod @@ -3,7 +3,7 @@ module mesh-grants go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-grants/go.sum b/modules/mesh-grants/go.sum index f93723f..de2f4ff 100644 --- a/modules/mesh-grants/go.sum +++ b/modules/mesh-grants/go.sum @@ -4,6 +4,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027012704-062c29c3a22f h1:AKzV973U git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027012704-062c29c3a22f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f h1:mimAGERguQmCGYVNdRTrFcZ1dhpU6GWo+Q3EDhHOrVk= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 h1:9B7B38e3RtjbtX1uGP9dRgU9VY1/J2yAfnb5Ajoq4/s= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index 4a0aaa6..8203289 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -606,6 +606,19 @@ func TestGrants(t *testing.T) { if !slices.Contains(names(users), "b.mod-p") { t.Errorf("b.mod-p is not composed, so its module counts as placed nowhere: %v", names(users)) } + // Issue 1126: a key a module's served value fills from its settings (mailu's smtp domain) is granted to every other + // node's agent, that key alone, so a node composing a consumer elsewhere settles what it serves. + bs := fixture() + bs.manifestOf("mod-s", `{"module":"mod-s","version":"1","own-secrets":{"broker":"/var/lib/s/broker"},`+ + `"config":{"domain":{"type":"string","description":"The mail domain.","required":true}},`+ + `"provides":[{"name":"smtp","scope":"mesh"}],"serves":{"smtp":{"port":587,"domain":"${config:domain}"}}}`) + bs.assign("b", "mod-s") + served := "$JS.API.DIRECT.GET.KV_mesh-config_resolved.$KV.mesh-config_resolved.b.mod-s.domain" + for _, u := range shadowOf(t, bs) { + if (u.User == "node.a") != slices.Contains(u.Publish, served) { + t.Errorf("%s is granted b's mod-s domain: %v (node a alone)", u.User, slices.Contains(u.Publish, served)) + } + } // The pass, the tool listing held memberships, and the log each say the refusal. part := partOn(b) res := part.Pass() diff --git a/modules/mesh-grants/internal/grants/records.go b/modules/mesh-grants/internal/grants/records.go index e92e11c..2e6696b 100644 --- a/modules/mesh-grants/internal/grants/records.go +++ b/modules/mesh-grants/internal/grants/records.go @@ -104,6 +104,8 @@ func declaredFor(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaratio Invokes: m.Invokes, Waits: waitsOf(m, seats), State: bucketsOf(m), Reads: m.Reads, Logs: logsOf(m), Streams: streamsOf(m), Queues: queueOwnersOf(m), Processes: processesOf(m), Checks: catalogue.HealthChecks(m), RunsAs: m.RunsAs, Issued: issuedTools(m), + // The keys its served values fill, which every node may read where it runs (issue 1126). + Served: catalogue.ServedSettings(m), } d.Loads = loadsABundle(m) if _, reads := m.OwnSecrets["broker"]; !reads { From a7d03f7c82cb95f09b3733ec6f24e23d06c25945 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 27 Oct 2026 21:04:08 +0100 Subject: [PATCH 2/3] Pin mesh-sdk 538ffba, the group's head, in the assigner and mesh-grants (issue 1126) --- modules/mesh-delivery-assigner/go.mod | 2 +- modules/mesh-delivery-assigner/go.sum | 2 ++ modules/mesh-grants/go.mod | 2 +- modules/mesh-grants/go.sum | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/mesh-delivery-assigner/go.mod b/modules/mesh-delivery-assigner/go.mod index 5685a33..74cf007 100644 --- a/modules/mesh-delivery-assigner/go.mod +++ b/modules/mesh-delivery-assigner/go.mod @@ -3,7 +3,7 @@ module mesh-delivery-assigner go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-delivery-assigner/go.sum b/modules/mesh-delivery-assigner/go.sum index 38b8a0c..01355cc 100644 --- a/modules/mesh-delivery-assigner/go.sum +++ b/modules/mesh-delivery-assigner/go.sum @@ -14,6 +14,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f h1:mimAGERg git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 h1:9B7B38e3RtjbtX1uGP9dRgU9VY1/J2yAfnb5Ajoq4/s= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b h1:LuBK5dtBgm978krhj41N2MKA07Yv4zetRPOdHRTB6L8= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-grants/go.mod b/modules/mesh-grants/go.mod index 5cd03af..a6741ec 100644 --- a/modules/mesh-grants/go.mod +++ b/modules/mesh-grants/go.mod @@ -3,7 +3,7 @@ module mesh-grants go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-grants/go.sum b/modules/mesh-grants/go.sum index de2f4ff..fce777c 100644 --- a/modules/mesh-grants/go.sum +++ b/modules/mesh-grants/go.sum @@ -6,6 +6,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f h1:mimAGERg git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027014310-cadd7b1b2f8f/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 h1:9B7B38e3RtjbtX1uGP9dRgU9VY1/J2yAfnb5Ajoq4/s= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b h1:LuBK5dtBgm978krhj41N2MKA07Yv4zetRPOdHRTB6L8= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= From c93f0d15e4a35999e8e9662c4f18245ad191b1df Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 27 Oct 2026 21:13:41 +0100 Subject: [PATCH 3/3] Grant the served keys of the trunk's manifest too, and pin mesh-sdk 7a8e9f9 in the assigner and mesh-grants on main's bus helpers (issue 1126, review round 1) A node composing a consumer reads the served keys of the trunk's manifest of a provider elsewhere, which may serve a setting the build it runs does not. --- modules/mesh-delivery-assigner/go.mod | 2 +- modules/mesh-delivery-assigner/go.sum | 2 ++ modules/mesh-grants/go.mod | 2 +- modules/mesh-grants/go.sum | 2 ++ modules/mesh-grants/grants_test.go | 20 +++++++++++++++++++ .../mesh-grants/internal/grants/records.go | 5 +++++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/modules/mesh-delivery-assigner/go.mod b/modules/mesh-delivery-assigner/go.mod index d2b7ff8..8da7a7d 100644 --- a/modules/mesh-delivery-assigner/go.mod +++ b/modules/mesh-delivery-assigner/go.mod @@ -3,7 +3,7 @@ module mesh-delivery-assigner go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027193820-8ad9372b1952 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-delivery-assigner/go.sum b/modules/mesh-delivery-assigner/go.sum index fa4f833..f6eae7d 100644 --- a/modules/mesh-delivery-assigner/go.sum +++ b/modules/mesh-delivery-assigner/go.sum @@ -1,5 +1,7 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027193820-8ad9372b1952 h1:TmveT3Bija643RGWkilvkzP/h8UWlVvHFZZtQfJK5oU= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027193820-8ad9372b1952/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648 h1:XoMsgg9kSgjQWa86NZM8h8OpxJ2kovxcMS2C0i6WSVU= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-grants/go.mod b/modules/mesh-grants/go.mod index a6741ec..99a6624 100644 --- a/modules/mesh-grants/go.mod +++ b/modules/mesh-grants/go.mod @@ -3,7 +3,7 @@ module mesh-grants go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-grants/go.sum b/modules/mesh-grants/go.sum index fce777c..7e80983 100644 --- a/modules/mesh-grants/go.sum +++ b/modules/mesh-grants/go.sum @@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0 h1:9B7B38e3 git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027195758-cebc6519d5b0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b h1:LuBK5dtBgm978krhj41N2MKA07Yv4zetRPOdHRTB6L8= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027200317-538ffbaa085b/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648 h1:XoMsgg9kSgjQWa86NZM8h8OpxJ2kovxcMS2C0i6WSVU= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261027201213-7a8e9f970648/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index 8203289..815f4e0 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -619,6 +619,26 @@ func TestGrants(t *testing.T) { t.Errorf("%s is granted b's mod-s domain: %v (node a alone)", u.User, slices.Contains(u.Publish, served)) } } + // The provider not yet moved: it runs a build whose manifest serves no setting, and the trunk's adds one, which a + // node composing a consumer reads (frombus reads the trunk's manifest of another node's module): granted too. + bt := fixture() + const oldS = `{"module":"mod-s","version":"1","own-secrets":{"broker":"/var/lib/s/broker"},` + + `"provides":[{"name":"smtp","scope":"mesh"}],"serves":{"smtp":{"port":587}}}` + bt.manifestOf("mod-s", oldS) + oldDigest := delivery.ManifestDigest([]byte(oldS)) + bt.manifestOf("mod-s", `{"module":"mod-s","version":"1","own-secrets":{"broker":"/var/lib/s/broker"},`+ + `"config":{"domain":{"type":"string","description":"The mail domain.","required":true}},`+ + `"provides":[{"name":"smtp","scope":"mesh"}],"serves":{"smtp":{"port":587,"domain":"${config:domain}"}}}`) + bt.assign("b", "mod-s") + runsFP := "src2:" + strings.Repeat("cd", 32) + bt.put(grants.ReadWants, "want.b.mod-s", delivery.Want{V: delivery.Version, FP: runsFP, Composed: "sha256:" + strings.Repeat("ef", 32)}) + runsKey, _ := delivery.BuilderBuildKey("mod-s", runsFP) + bt.put(grants.ReadBuilds, runsKey, map[string]any{"v": delivery.Version, "state": "done", "manifest": oldDigest}) + for _, u := range shadowOf(t, bt) { + if u.User == "node.a" && !slices.Contains(u.Publish, served) { + t.Errorf("node a is not granted the domain the trunk's mod-s serves, while b runs one that serves none") + } + } // The pass, the tool listing held memberships, and the log each say the refusal. part := partOn(b) res := part.Pass() diff --git a/modules/mesh-grants/internal/grants/records.go b/modules/mesh-grants/internal/grants/records.go index 2e6696b..7ee2563 100644 --- a/modules/mesh-grants/internal/grants/records.go +++ b/modules/mesh-grants/internal/grants/records.go @@ -60,6 +60,11 @@ func Records(in Inputs) (buscompose.Records, []Gap) { continue } d := declaredFor(m, seats, declarers) + // What a node composing a consumer reads of it is the trunk manifest's served keys (frombus reads the indexer's + // manifest of another node's module), and what runs may still be another build: both are granted (issue 1126). + if trunk, ok := in.Manifests[module]; ok { + d.Served = slices.Compact(slices.Sorted(slices.Values(append(slices.Clone(d.Served), catalogue.ServedSettings(trunk)...)))) + } if len(in.Placed) > 0 { d.Holds = heldWherePlaced(d.Holds, in.Placed[node], m.Module) }