From b1bf1659d97286a4cfb8723192ca8d4bde6f0b6e Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 4 Sep 2026 21:56:05 +0200 Subject: [PATCH] broker: a module account scopes its tool serve queues and mesh.rpc (ADR 0052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CreateModuleAccount now also grants serve..* (declare, bind, consume its own tool queues) and mesh.rpc (bind them on, publish replies) — so a module can serve its tools and reply, scoped to exactly its own, and no other module's. The broker tests still hold a module out of another's queue. --- internal/broker/management.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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) }