package buscompose import ( nodeengineseat "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" "git.novox.be/novox/mesh-delivery/modules/mesh-grants/busgrants" ) // The node seat node-engine (novox/hq ADR 0563 §1): every node's engine holds it on its own bus account, and no module // claims it. Its verbs and events are the catalogue's (catalogue.EngineVerbs), read here rather than copied. // EngineSeat is the seat. const EngineSeat = nodeengineseat.Seat // EngineModule is the node-engine's manifest's module name, and EngineActsState its state the acts asked through the // node seat and its own asks are kept in (ADR 0563 §2, §3: "the engine's own state"): the bucket mesh-host_acts, keys // `.act.`, `.open..` and `.ask.`, each written by that node's engine alone. const ( EngineModule = busgrants.EngineModule EngineActsState = "acts" ) // EngineActsBucket is that state's bucket. var EngineActsBucket = BucketName(EngineModule, EngineActsState) // EnginePackagesBucket is the engine's state of its node's declared packages (novox/hq ADR 0565 clause 6): one key, the // node's name, written by that node's engine alone. var EnginePackagesBucket = BucketName(EngineModule, EnginePackagesState) // EngineFindingsBucket is the engine's state of the findings it raises about its own node (novox/hq ADR 0564 §2, ADR 0636 §1): // keys `machine..`, written by that node's engine alone and cleared by it; the condition keeper raises each as a // condition. var EngineFindingsBucket = BucketName(EngineModule, "findings") // EngineFindingsGrants is what a node's engine publishes to write and clear its node's findings: its own node's keys alone, // and their read. Without it the finding that the node waits for the seat list is refused on the bus and never raised. func EngineFindingsGrants(node string) []string { return append([]string{"$KV." + EngineFindingsBucket + ".machine." + node + ".>"}, readGrants(EngineFindingsBucket, "machine."+node+".>")...) } // EnginePackagesGrants is what a node's engine publishes to keep its node's key of the packages bucket: the key alone, // and its read. func EnginePackagesGrants(node string) []string { return append([]string{"$KV." + EnginePackagesBucket + "." + node}, readGrants(EnginePackagesBucket, node)...) } // engineGrants is what a node's engine is granted to hold its node seat and to ask the operator (ADR 0563 §1, §3): it // answers its own node's verbs (the caller-named subjects are added beside them with every principal's), says the // seat's events about its node, answers discovery for the seat, asks who answers what (the login shell's execute, ADR // 0563 §6), and asks the operator under occ.EngineAsker(node) on the router's seat as its holder declares it, as any // user of that seat is granted. // // Its verbs and events are granted as any verb and any event of the seat on its own node, not as the contract's list: // the list is compiled into whichever mesh-sdk the grants part pins, so a verb the engine gained before the grants part // was released was refused on every node and the engine reopened its link every few minutes (2026-10-31, the optional // verb composition of mesh-host #184). As a module answers `mesh.mod..tool.>`, nothing is given away: no other // principal may subscribe this seat's subjects of this node, and a caller is still granted each verb by name. func engineGrants(p Principal) (pub, sub []string) { sub = append(sub, "mesh.seat."+EngineSeat+".tool.*."+p.Node) // Any event of the seat about its own node, by the one rule a watcher of it is composed by (machineEvent). every, _ := machineEvent(Seat{Name: EngineSeat, Scope: "node", HeldByTheEngine: true}, "*") pub = append(pub, seatSubject(Seat{Name: EngineSeat}, "event", onMachine(every, p.Node))) sub = append(sub, announcing(EngineSeat)...) pub = append(pub, discovering()...) tp, ts := seatTrafficGrants(SeatTrafficOf(occ.EngineAsker(p.Node), nil, p.Uses, nil)) // And its acts and asks, under its own node's keys alone; never the bucket's creation, which is the grants part's. if own, err := NodeKeysGrants(EngineActsBucket, p.Node); err == nil { pub = append(pub, own...) } // And the provisions its node's modules consume, its own node's keys alone, read (novox/hq ADR 0570 clause 6: the // consuming engine checks the vault's name and generation of what it is handed). if safeSubject.MatchString(p.Node) { pub = append(pub, readGrants(ProvisionerProvisionsBucket, p.Node+".>")...) } // And its node's own health report, its key `` alone (issue 774, the operator's alert table): what the watchman // reads for the machine's alerts. if safeSubject.MatchString(p.Node) { pub = append(pub, append([]string{"$KV." + NodeHealthBucket + "." + p.Node}, readGrants(NodeHealthBucket, p.Node)...)...) } // And its node's placed modules' data items, its own node's keys alone (ADR 0577 clause 1). if own, err := NodeKeysGrants(EngineDataBucket, p.Node); err == nil { pub = append(pub, own...) } // And its node's declared packages, its own key alone (ADR 0565 clause 6). if safeSubject.MatchString(p.Node) { pub = append(pub, EnginePackagesGrants(p.Node)...) } // And the findings it raises about its own node, its own node's keys alone (ADR 0564 §2, ADR 0636 §1). if safeSubject.MatchString(p.Node) { pub = append(pub, EngineFindingsGrants(p.Node)...) } return append(pub, tp...), append(sub, ts...) }