From 2d95c0eb59f0fbd04e0a4e5ae27d3e2d04044786 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 06:02:18 +0100 Subject: [PATCH] AM-D3 path: the tool runner states its own fingerprint beside its capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A capability reading must be tied to the runner that made it, so the grants part can tell an older runner's reading from the running one's. Builds: design 46 7 §6 (the announcement carries the runner's fingerprint), lead answer A-203 (key `fingerprint`) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- node-tools/internal/announce/announce.go | 5 +++++ node-tools/internal/runtime/announce_test.go | 5 +++++ node-tools/internal/runtime/runtime.go | 5 ++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/node-tools/internal/announce/announce.go b/node-tools/internal/announce/announce.go index 8771120..c8d79d8 100644 --- a/node-tools/internal/announce/announce.go +++ b/node-tools/internal/announce/announce.go @@ -48,6 +48,11 @@ const Digest = "digest" // module needing one is placed only where the runtime states it. const Capabilities = "capabilities" +// Fingerprint is the service metadata key the tool runner states its own fingerprint under, beside Capabilities: the build +// its composed environment names (MESH_FINGERPRINT, design 47 G §424), so the node-engine ties the capabilities it takes +// into the node's record to the runner that stated them (design 46 approval mark §6, lead answer A-203). +const Fingerprint = "fingerprint" + // Shortened is the service metadata key a runtime sets when its announcement was cut to fit the bus. const Shortened = "shortened" diff --git a/node-tools/internal/runtime/announce_test.go b/node-tools/internal/runtime/announce_test.go index dd58ba0..54b4a34 100644 --- a/node-tools/internal/runtime/announce_test.go +++ b/node-tools/internal/runtime/announce_test.go @@ -121,6 +121,7 @@ func TestTheRuntimeAnnouncesWhatItServesInTheServicesProtocol(t *testing.T) { // issue 1966 TLS-3 (ENG-2): the runner states the capabilities of the calls it answers in its PING, on its own instance, which // is what its machine's node-engine asks and takes into the node's record; no bundle is needed for it. func TestTheRunnerStatesTheCapabilitiesOfItsCallsInItsPing(t *testing.T) { + t.Setenv(FingerprintWord, "sha256:runner") mesh := mt.New(t) mesh.Issue(t, mt.MembershipOf("alpha", "anchor", false, nil)) nodeTools := connect(t, "node-tools", "anchor") @@ -142,4 +143,8 @@ func TestTheRunnerStatesTheCapabilitiesOfItsCallsInItsPing(t *testing.T) { if err := json.Unmarshal(msg.Data, &ping); err != nil || ping.Metadata[announce.Capabilities] != "approval-mark/1,bus-state-calls,ledger-calls,put-sessions,seat-settle-delay" { t.Errorf("the runner states %q (%v), want its bus-state and ledger calls", ping.Metadata[announce.Capabilities], err) } + // Its own fingerprint beside them (design 46 approval mark §6). + if ping.Metadata[announce.Fingerprint] != "sha256:runner" { + t.Errorf("the runner states its fingerprint as %q", ping.Metadata[announce.Fingerprint]) + } } diff --git a/node-tools/internal/runtime/runtime.go b/node-tools/internal/runtime/runtime.go index 15bfdc2..04c3f9a 100644 --- a/node-tools/internal/runtime/runtime.go +++ b/node-tools/internal/runtime/runtime.go @@ -316,7 +316,10 @@ func Run(conn *bus.Conn, served []Served, envs map[string]map[string]string, log announced, err := announce.Serve(conn, announce.Service{ Name: conn.Module(), ID: instanceOf(conn), Description: "the mesh's tool runtime on " + node + ": every assigned module's tools and the seats they hold", - Metadata: map[string]string{"node": node, announce.Capabilities: strings.Join(CallCapabilities(), ",")}, + // Its own fingerprint beside the capabilities, so a reading is tied to the runner that made it (design 46 approval + // mark §6, lead answer A-203). + Metadata: map[string]string{"node": node, announce.Capabilities: strings.Join(CallCapabilities(), ","), + announce.Fingerprint: os.Getenv(FingerprintWord)}, }, func() []announce.Endpoint { return endpointsOf(conn, r.own(), r.registrations(), r.modules) }) if err != nil { logf("[mesh-tools] cannot announce what it serves: %v", err)