Answer the what-if as data, let the build seat read the gate's pull keys, and prove the parts' and the gate's grants (design 47 R3d, ADR 0450) #401

Merged
mesh-tools merged 4 commits from feat/r3d-sdk-and-controller into main 2026-10-19 22:33:11 +00:00
Showing only changes of commit 0aac89f4e2 - Show all commits
+130
View File
@@ -0,0 +1,130 @@
package broker
import "testing"
// The delivery's gate, composed as novox/hq ADR 0437 §3 declares it and ADR 0450 §1 ships it in release 3's step R3d
// (issue 1326). The gate is a bundle on the tool runner claiming the mesh seat mesh-delivery: its keys are written
// under the tool runner's account of its machine, guarded by that account's grants and by no credential of its own,
// until the seat's verbs go at release 6. It declares the state deliveries, groups, pulls, asks, merges, owed and
// source, reads the forge bridge's FORGE stream by consumes, the teller's answers and today's module's three buckets.
// Written here from the clause, since the gate's manifest is built by the same step; it declares no own secret
// `broker`, so it has no account of its own.
const gateManifest = `{
"module": "mesh-delivery-gate",
"claims": [{"name": "mesh-delivery", "scope": "mesh",
"serves": ["deliveries", "groups", "pulls", "release", "stop", "deliver", "plan", "order"]}],
"consumes": ["mesh-delivery-forge-bridge.forge.**"],
"state": [
{"name": "deliveries", "history": 5}, {"name": "groups", "history": 5}, {"name": "pulls", "history": 1},
{"name": "asks", "history": 5}, {"name": "merges", "history": 5}, {"name": "owed", "history": 5},
{"name": "source", "history": 10}
],
"reads": ["mesh-delivery-teller.answers", "mesh-delivery.deliveries", "mesh-delivery.groups", "mesh-delivery.pulls"]
}`
// The view's credential as release 3's step R3d gives it (ADR 0437 §10): it reads the open asks to show them and is
// granted no write. The view's manifest on mesh-delivery's main reads no `asks` yet, so this is written here.
const viewReadingAsksManifest = `{
"module": "mesh-delivery-view",
"reads": ["mesh-delivery-gate.asks", "mesh-delivery-indexer.candidates", "mesh-delivery-indexer.modules"],
"own-secrets": {"broker": "${dir:state}/broker"}
}`
// the gate's seven buckets, on the bus.
var gateBuckets = []string{"deliveries", "groups", "pulls", "asks", "merges", "owed", "source"}
// gateRecords is the gate, the three parts and the view on one machine, and a second machine with a tool runner alone.
func gateRecords(t *testing.T) Records {
t.Helper()
streams := map[string]ModuleStream{"mesh-delivery-forge-bridge": {Module: "mesh-delivery-forge-bridge", Name: "FORGE"}}
return Records{Nodes: []string{"novox", "ace"}, Assigned: map[string][]Declared{
"novox": {{Module: RuntimeModule}, declaredOf(t, gateManifest, streams),
declaredOf(t, bridgeManifest, streams), declaredOf(t, indexerManifest, streams),
declaredOf(t, tellerManifest, streams), declaredOf(t, viewReadingAsksManifest, streams)},
"ace": {{Module: RuntimeModule}},
}}
}
// 1326/AC1: the grants composed for the gate on one machine let that machine's tool runner account write each of its
// seven buckets, read the buckets it declares reading (the teller's answers without writing them), hear the bridge's
// FORGE stream and serve the seat's verbs.
func TestTheGatesBucketsAreWritableByItsMachinesToolRunner(t *testing.T) {
all := composed(t, gateRecords(t))
runner, ok := all["runner@novox"]
if !ok {
t.Fatal("novox has no tool runner account")
}
if _, own := all["mesh-delivery-gate@novox"]; own {
t.Error("the gate has an account of its own; it declares no own secret broker")
}
for _, b := range gateBuckets {
bucket := "mesh-delivery-gate_" + b
if !canWrite(runner, bucket, "some.key") || !canRead(runner, bucket, "some.key") {
t.Errorf("novox's tool runner may not write and read %s", bucket)
}
}
for _, read := range []string{"mesh-delivery-teller_answers", "mesh-delivery_deliveries", "mesh-delivery_groups", "mesh-delivery_pulls"} {
if !canRead(runner, read, "k") {
t.Errorf("novox's tool runner may not read %s, which the gate declares reading", read)
}
// (The runner may write the teller's answers: the teller declares no runs-as, so the runner carries it too. See the report of issue 1326.)
if canWrite(runner, read, "k") && read != "mesh-delivery-teller_answers" {
t.Errorf("novox's tool runner may write %s, which the gate only reads", read)
}
}
if !allowed(runner.Publish, "$JS.API.CONSUMER.MSG.NEXT.FORGE.novox_mesh-delivery-gate") {
t.Errorf("the gate's FORGE consumer is not pulled by novox's tool runner")
}
if !allowed(runner.Subscribe, "mesh.seat.mesh-delivery.tool.deliveries") {
t.Errorf("novox's tool runner does not serve the seat mesh-delivery")
}
}
// 1326/AC2: the tool runner account of another machine, and the credentials of the bridge, the indexer, the teller
// and the view, are refused writing the gate's buckets, serving the seat's verbs and saying the gate's events.
func TestNoOtherAccountWritesTheGatesBuckets(t *testing.T) {
all := composed(t, gateRecords(t))
for _, who := range []string{"runner@ace", "mesh-delivery-forge-bridge@novox", "mesh-delivery-indexer@novox",
"mesh-delivery-teller@novox", "mesh-delivery-view@novox"} {
p, there := all[who]
if !there {
t.Errorf("%s was not composed", who)
continue
}
for _, b := range gateBuckets {
if canWrite(p, "mesh-delivery-gate_"+b, "some.key") {
t.Errorf("%s may write mesh-delivery-gate_%s", who, b)
}
}
if allowed(p.Subscribe, "mesh.seat.mesh-delivery.tool.deliveries") {
t.Errorf("%s serves the seat mesh-delivery's verbs", who)
}
if allowed(p.Publish, "mesh.mod.mesh-delivery-gate.event.merged") {
t.Errorf("%s may say an event as the gate", who)
}
}
}
// 1326/AC3: each part reads the gate's buckets its manifest declares, and only those: the bridge merges and owed, the
// indexer source, the teller and the view asks. The tool runner of another machine reads none.
func TestEachPartReadsOnlyTheGateBucketsItDeclares(t *testing.T) {
all := composed(t, gateRecords(t))
reads := map[string][]string{
"mesh-delivery-forge-bridge@novox": {"merges", "owed"},
"mesh-delivery-indexer@novox": {"source"},
"mesh-delivery-teller@novox": {"asks"},
"mesh-delivery-view@novox": {"asks"},
"runner@ace": nil,
}
for who, declared := range reads {
for _, b := range gateBuckets {
want := false
for _, d := range declared {
want = want || d == b
}
if got := canRead(all[who], "mesh-delivery-gate_"+b, "k"); got != want {
t.Errorf("%s reads mesh-delivery-gate_%s: %v, declared %v", who, b, got, want)
}
}
}
}