Watch the have bucket only where the node's grant allows, so a node composing itself is not refused by the bus (issue 1126)

The fold's watch of every have key ('>') was refused (permissions violation on
CONSUMER.CREATE KV_node-engine_have), and every self-composing agent stopped
after the seed. The composer now watches '*.node' (records) and '<node>.>' (its
own haves), as buscompose grants a node; the shadow watches '<node>.>' too. The
selfcompose tests check every watch and get against PermissionsFor(KindNode),
and the agent's integration tests run the agent as the node under that grant.
This commit is contained in:
2026-10-27 09:27:54 +01:00
parent 50c229f905
commit 0184e2a5b8
4 changed files with 144 additions and 40 deletions
+9 -10
View File
@@ -117,8 +117,11 @@ func (c *Composer) inputs() []input {
return []input{
{delivery.AssignerWantsBucket, "want." + node + ".>", (*Composer).takeWant, nil},
{delivery.PlacementBucket, ">", (*Composer).takePlacement, nil},
// Every node's record, and this node's haves: what it runs inside its own composition.
{delivery.HaveBucket, ">", nil, (*Composer).takeHave},
// Every node's record, and this node's own haves (what it runs inside its own composition): two watches, each
// within the node's grant (buscompose: readGrants of the have bucket at `*.node`, NodeKeysGrants at `<node>.>`).
// A watch of every key is refused by the bus (issue 1126, 2026-10-27 09:21: the fold's `>` stopped every agent).
{delivery.HaveBucket, "*." + delivery.HaveNodeWord, nil, (*Composer).takeRecordChanged},
{delivery.HaveBucket, node + ".>", nil, (*Composer).takeModuleHave},
{delivery.ModulesBucket, ">", (*Composer).takeModule, nil},
{ResolvedBucket, node + ".>", (*Composer).takeValue, nil},
}
@@ -310,14 +313,10 @@ func (c *Composer) takeRecord(u agent.Update) {
c.records[node] = *h.Record
}
// takeHave takes a have key: a node's record (always composed again), or one of this node's modules' haves, which
// changes what is composed only when whether it runs inside the node's own composition changes.
func (c *Composer) takeHave(u agent.Update) bool {
if isNodeKey(u.Key) {
c.takeRecord(u)
return true
}
return c.takeModuleHave(u)
// takeRecordChanged takes a node's record, which is always composed again.
func (c *Composer) takeRecordChanged(u agent.Update) bool {
c.takeRecord(u)
return true
}
// takeModuleHave takes one of this node's modules' haves, and says whether it changed which it runs inside its own