131 lines
6.2 KiB
Go
131 lines
6.2 KiB
Go
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)
|
|
}
|
|
// 1329/AC3: the runner no longer carries the teller, so it may not write the teller's answers either.
|
|
if canWrite(runner, read, "k") {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|