diff --git a/internal/broker/management.go b/internal/broker/management.go index 3270826..3ec9277 100644 --- a/internal/broker/management.go +++ b/internal/broker/management.go @@ -92,20 +92,27 @@ func ModuleQueueFor(node, module string) string { return node + "." + module + " func modulePermissions(node, module string, emits, consumes []string) (configure, write, read string) { queue := regexp.QuoteMeta(ModuleQueueFor(node, module)) events := regexp.QuoteMeta(EventsExchangeName) + rpc := regexp.QuoteMeta(RPCExchangeName) + // A module serves each of its tools on its own queue, namespaced by the module (novox/hq + // ADR 0052) — serve.. — so the account may declare, bind and read exactly its own, + // and no other module's. + serve := "serve\\." + regexp.QuoteMeta(module) + "\\..*" - // Declare only its own queue. - configure = "^" + queue + "$" + // Declare its own events queue and its own tool serve queues. + configure = "^(" + queue + "|" + serve + ")$" - // Write to its own queue — binding a queue to an exchange is a write on the queue — and to the - // events exchange only if it emits. - writes := []string{queue} + // Write to bind its queue and serve queues (binding is a write on the queue), and to the RPC + // exchange to publish replies (ADR 0052: replies ride mesh.rpc, never the default exchange, which + // would let it publish into any queue). To the events exchange only if it emits. + writes := []string{queue, serve, rpc} if len(emits) > 0 { writes = append(writes, events) } write = "^(" + strings.Join(writes, "|") + ")$" - // Read its own queue to consume it, and the events exchange to bind onto, only if it consumes. - reads := []string{queue} + // Read its own queue and serve queues to consume them, and the RPC exchange to bind its serve + // queues onto. The events exchange to bind onto only if it consumes. + reads := []string{queue, serve, rpc} if len(consumes) > 0 { reads = append(reads, events) }