From 9a569bfb8dad355249fd4ab9543f927dcd7357d9 Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 26 Oct 2026 11:26:20 +0100 Subject: [PATCH] mesh-grants: derive that a bundle loads from build.artifacts, as the indexer's manifest has no derived bundles, so route-proxy's helper is carried (issue 1945) --- modules/mesh-grants/grants_test.go | 22 +++++++++++ .../mesh-grants/internal/grants/records.go | 38 ++++++++++++++++--- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index 0f0fa18..a4c2805 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -426,6 +426,28 @@ func TestGrants(t *testing.T) { } }) } + // A module whose only runtime-loaded part is a helper bundle (route-proxy's route-provider) says `loads` in + // the repository manifest's build.artifacts; the indexer's manifest has no derived Bundles (issue 1945). + for _, row := range []struct { + name, build string + carried bool + }{ + {"a bundle that says loads is carried by node-tools", `,"build":{"artifacts":[{"name":"helper","kind":"bundle","language":"go","system":"arch","from":"cmd/h","binary":"h","loads":["h"]}]}`, true}, + {"a module with no loading bundle is left to its own account", ``, false}, + } { + t.Run(row.name, func(t *testing.T) { + b := fixture() + b.manifestOf("mod-z", `{"module":"mod-z","version":"1","own-secrets":{"broker":"/var/lib/z/broker"}`+row.build+`}`) + b.assign("a", "mod-z") + b.manifestOf("node-tools", `{"module":"node-tools","version":"1","own-secrets":{"broker":"/var/lib/nt/broker"}}`) + b.assign("a", "node-tools") + users := shadowOf(t, b) + tools := users[slices.IndexFunc(users, func(u grants.User) bool { return u.User == "a.node-tools" })] + if got := slices.Contains(tools.Subscribe, "mesh.mod.mod-z.tool.>"); got != row.carried { + t.Errorf("a.node-tools subscribes to mod-z's tools = %v, want %v: %v", got, row.carried, tools.Subscribe) + } + }) + } b := fixture() users := shadowOf(t, b) y := users[slices.IndexFunc(users, func(u grants.User) bool { return u.User == "b.mod-y" })] diff --git a/modules/mesh-grants/internal/grants/records.go b/modules/mesh-grants/internal/grants/records.go index 94beb82..e53beab 100644 --- a/modules/mesh-grants/internal/grants/records.go +++ b/modules/mesh-grants/internal/grants/records.go @@ -101,11 +101,7 @@ func declaredFor(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaratio Streams: streamsOf(m), Queues: queueOwnersOf(m), Processes: processesOf(m), Checks: catalogue.HealthChecks(m), RunsAs: m.RunsAs, Issued: issuedTools(m), } - for _, b := range m.Bundles { - if len(b.Loads) > 0 { - d.Loads = true - } - } + d.Loads = loadsABundle(m) if _, reads := m.OwnSecrets["broker"]; !reads { d.NoAccount = true } @@ -129,6 +125,38 @@ func declaredFor(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaratio return d } +// loadsABundle says the node's tool runtime loads a bundle of the module. The controller reads it from the resolved +// manifest's Bundles, which a build derives and the indexer's manifest does not carry (the builder's build record names +// the repository's manifest digest), so the same answer is derived here from `build.artifacts` by mesh-sdk's rule +// (the build's own rule for what a bundle loads): a bundle that says `loads`, else every bundle of a module that declares tools and that no +// resource of the module runs. Without it a module whose only runtime-loaded part is a helper (route-proxy's +// route-provider) was left out of node-tools' grants (issue 1945). +func loadsABundle(m catalogue.Manifest) bool { + for _, b := range m.Bundles { + if len(b.Loads) > 0 { + return true + } + } + if m.Build == nil { + return false + } + run := map[string]bool{} + for _, r := range m.Resources { + if a, ok := r["artifact"].(string); ok && a != "" { + run[a] = true + } + } + for _, a := range m.Build.Artifacts { + if a.Kind != catalogue.ArtifactBundle { + continue + } + if len(a.Loads) > 0 || (a.Loads == nil && len(m.Tools) > 0 && !run[a.Name]) { + return true + } + } + return false +} + func waitsOf(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaration) []buscompose.Wait { var out []buscompose.Wait for _, w := range m.Waits {