From 611fafb58ea63f458d96342205d1f2848c5815d9 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 06:20:21 +0100 Subject: [PATCH] AM-D4: the real bus delivers no marked call to a runtime denied the marks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A deny composed into the user list must hold on the server itself: the runtime keeps its allow of the module's tools, and neither the tool's subject nor the caller-named subject process.Call sends on first reaches it. Builds: design 46 7 §6 (integration, the grants part's real-bus test) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- .../mesh-grants/composed_integration_test.go | 55 +++++++++++++++++++ .../cmd/mesh-grants/integration_test.go | 1 + 2 files changed, 56 insertions(+) diff --git a/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go b/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go index fb8fe2e7..fb847a1f 100644 --- a/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go +++ b/modules/mesh-grants/cmd/mesh-grants/composed_integration_test.go @@ -623,3 +623,58 @@ func theToolRunnerHearsEveryEventOnTheBus(t *testing.T) { } hears(ledger, "the restricted stream after its grant value changed") } + +// aRuntimeDeniedTheMarksHearsNoMarkedCall, run by TestTheGrantsPartWhole, defends design 46 approval mark §6 on a real +// server (AM-D4): a runtime account composed with the deny, its node's tool runner stating no approval-mark/1, holds +// `mesh.mod..tool.>` and is delivered no call on a marked tool's subject nor on the caller-named subject +// process.Call sends on first; a call of an unmarked tool still reaches it. +func aRuntimeDeniedTheMarksHearsNoMarkedCall(t *testing.T) { + records := buscompose.Records{Nodes: []string{"a"}, Assigned: map[string][]buscompose.Declared{"a": { + {Module: "node-tools", ToolRunner: true}, + {Module: "shell", Serves: []string{"execute", "read"}, Marked: []string{"execute"}}, + {Module: "asker", Invokes: []string{"shell.execute", "shell.read"}}, + }}, Readings: map[string]buscompose.RunnerReading{"a": {Capabilities: []string{"bus-state-calls"}, Fingerprint: "sha256:runner"}}, + Running: map[string]string{"a.node-tools": "sha256:runner"}} + bus := startComposedBus(t, records) + runner, _ := bus.dial("a.node-tools") + heard := make(chan *nats.Msg, 16) + for _, s := range []string{"mesh.mod.shell.tool.>", "mesh.mod.shell.call.>"} { + if _, err := runner.ChanSubscribe(s, heard); err != nil { + t.Fatal(err) + } + } + if err := runner.Flush(); err != nil { + t.Fatal(err) + } + asker, askerRefused := bus.dial("a.asker") + // The caller-named subject is process.Call's first: mesh.mod..call... + for _, subject := range []string{"mesh.mod.shell.tool.execute", "mesh.mod.shell.call.execute.asker~a", "mesh.mod.shell.tool.read"} { + if err := asker.Publish(subject, []byte(`{}`)); err != nil { + t.Fatal(err) + } + } + if err := asker.Flush(); err != nil { + t.Fatal(err) + } + select { + case e := <-askerRefused: + t.Fatalf("the asker may not call: %s", e) + default: + } + select { + case m := <-heard: + if m.Subject != "mesh.mod.shell.tool.read" { + t.Errorf("the runtime denied the marks was delivered %s", m.Subject) + } + case <-time.After(5 * time.Second): + t.Fatal("the unmarked call did not reach the runtime") + } + if err := runner.Flush(); err != nil { + t.Fatal(err) + } + select { + case m := <-heard: + t.Errorf("the runtime denied the marks was delivered %s", m.Subject) + default: + } +} diff --git a/modules/mesh-grants/cmd/mesh-grants/integration_test.go b/modules/mesh-grants/cmd/mesh-grants/integration_test.go index 4b5fc605..4f910327 100644 --- a/modules/mesh-grants/cmd/mesh-grants/integration_test.go +++ b/modules/mesh-grants/cmd/mesh-grants/integration_test.go @@ -628,6 +628,7 @@ func TestTheGrantsPartWhole(t *testing.T) { // And what the part composes holds on a server that loads it (one integration test per module, the test budget). t.Run("the composed grants hold on a server that loads them", theBusNodeFollowsTheSealedListUnderTheComposedGrants) t.Run("the tool runner hears every event on a server that loads its grants", theToolRunnerHearsEveryEventOnTheBus) + t.Run("a runtime denied the marks is delivered no call on a marked subject", aRuntimeDeniedTheMarksHearsNoMarkedCall) } // lockedLog is the part's log, read by the test while the part writes it.