The controller ended by its unassignment (ADR 0590): its user, its lease's cut and reads, the operator's hand path to its compositions and its writers' rows go; an enrolling node enrols through mesh-enrolment alone; the desk's prompt stays the vault's alone (DeskOnly). The golden lists are now this composer's own, taken first from the controller's with its user removed. The bus module's tools may remove the controller's leftovers by name, consumers, CONTROL, ASSIGNMENTS, its 17 buckets and each node's declaration files' bucket, under the word controller-leftovers (clause 6). The provisioner client reads placement in place of the assignments mirror. Issue 1126 B3a, B5. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
83 lines
4.5 KiB
Go
83 lines
4.5 KiB
Go
package buscompose
|
|
|
|
import (
|
|
"git.novox.be/novox/mesh-sdk/go/asks"
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
"git.novox.be/novox/mesh-sdk/go/provisions"
|
|
)
|
|
|
|
// 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 = catalogue.EngineSeat
|
|
|
|
// 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
|
|
// `<node>.act.<id>`, `<node>.open.<act>.<digest>` and `<node>.ask.<id>`, each written by that node's engine alone.
|
|
const (
|
|
EngineModule = "mesh-host"
|
|
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, delivery.EnginePackagesState)
|
|
|
|
// EngineDataBucket is the engine's state of its node's placed modules' data items (novox/hq ADR 0577 clause 1): one
|
|
// key `<node>.<module>` per module, written by that node's engine alone.
|
|
var EngineDataBucket = delivery.EngineDataBucket
|
|
|
|
// 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 asks.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.<module>.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)
|
|
pub = append(pub, "mesh.seat."+EngineSeat+".event.*."+p.Node)
|
|
sub = append(sub, announcing(EngineSeat)...)
|
|
pub = append(pub, discovering()...)
|
|
tp, ts := seatTrafficGrants(SeatTrafficOf(asks.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(provisions.ProvisionsBucket, p.Node+".>")...)
|
|
}
|
|
// And its node's own health report, its key `<node>` 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." + delivery.NodeHealthBucket + "." + p.Node},
|
|
readGrants(delivery.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)...)
|
|
}
|
|
return append(pub, tp...), append(sub, ts...)
|
|
}
|