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)

This commit is contained in:
2026-10-26 11:33:28 +01:00
parent 75d0eb32be
commit 9a569bfb8d
2 changed files with 55 additions and 5 deletions
+22
View File
@@ -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" })]
+33 -5
View File
@@ -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 {