Files
mesh-delivery/modules/mesh-grants/internal/buscompose/recovery_engine_test.go
T
jschoubben f0c4d564d2 GR16 §554: the recovery module's account is granted the bus names of kept data
The account of the module claiming the seat mesh-recovery is granted the stream snapshot and
restore subjects with their chunk subjects, a stream's deletion and a durable consumer's
creation, only for the bus names of every kept data of every manifest the part holds and of
every restore point or aside kept-points names; never a stream of the mesh's own (CONTROL,
NODES, EVENTS, DEAD_LETTER*, PROV_APPLIED, CHECKS_*, SEAT_*, a seat's KV_). The writers table
names the account as a deleter of kept data's streams (ADR 0672 §4).

Builds: design 47 G §554, §565, A-230

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 09:17:07 +01:00

87 lines
3.9 KiB
Go

package buscompose
import (
"testing"
)
// Design 47 G §406, §554, A-108: the node-engine of a node is granted to hear the seat mesh-recovery's kept events ended and
// restored through an ordered consumer, to ask the verbs snapshot-kept, restore-kept and kept-points of the seat, and to call
// the catch-up tool of a module placed on its node, on its own node's tool subject and no other module's tool.
func TestTheNodeEngineIsGrantedWhatItNeedsOfTheRecoverySeat(t *testing.T) {
kept := []KeptEvent{
{Seat: "mesh-recovery", Event: "ended", Stream: "SEAT_mesh-recovery_ended", Filter: "mesh.seat.mesh-recovery.event.ended.*.*"},
{Seat: "mesh-recovery", Event: "restored", Stream: "SEAT_mesh-recovery_restored", Filter: "mesh.seat.mesh-recovery.event.restored.*.*"},
}
records := Records{Nodes: []string{"one"}, Kept: kept,
Engine: &Declared{Module: EngineModule, Consumes: []string{"mesh-recovery.ended", "mesh-recovery.restored"},
Invokes: []string{"seat:mesh-recovery.snapshot-kept", "seat:mesh-recovery.restore-kept", "seat:mesh-recovery.kept-points"}},
Assigned: map[string][]Declared{"one": {{Module: "keeper", CatchUps: []string{"catch_up"}}, {Module: "plain"}}}}
users, err := Users(records)
if err != nil {
t.Fatal(err)
}
var node Principal
for _, u := range users {
if u.Kind == KindNode {
node = u
}
}
perms, err := PermissionsFor(node)
if err != nil {
t.Fatal(err)
}
for _, want := range []string{
"$JS.API.CONSUMER.CREATE.SEAT_mesh-recovery_ended", "$JS.API.CONSUMER.CREATE.SEAT_mesh-recovery_ended.>",
"$JS.API.CONSUMER.MSG.NEXT.SEAT_mesh-recovery_ended.*", "$JS.API.CONSUMER.DELETE.SEAT_mesh-recovery_restored.*",
"$JS.API.STREAM.INFO.SEAT_mesh-recovery_restored",
"mesh.seat.mesh-recovery.tool.snapshot-kept", "mesh.seat.mesh-recovery.tool.restore-kept", "mesh.seat.mesh-recovery.tool.kept-points",
"mesh.mod.keeper.tool.catch_up.one",
} {
if !MayPublish(perms, want) {
t.Errorf("the node-engine of one may not publish %s", want)
}
}
for _, bad := range []string{"mesh.mod.plain.tool.catch_up.one", "mesh.mod.keeper.tool.other.one", "$JS.API.CONSUMER.CREATE.SEAT_mesh-recovery_set-aside"} {
if MayPublish(perms, bad) {
t.Errorf("the node-engine of one may publish %s", bad)
}
}
}
// Design 47 G §554: the account of the module holding the seat mesh-recovery is granted the snapshot, the restore with its
// chunks, the deletion and a durable consumer's creation for the bus names of kept data, and no stream of the mesh's own; no other
// module is granted them.
func TestTheRecoveryAccountIsGrantedTheBusNamesOfKeptDataAlone(t *testing.T) {
names := []string{"KV_a_x", "OBJ_b_y", "EVENTS", "SEAT_node-build-go", "KV_SEAT_x", "CONTROL", "bad.name"}
records := Records{Nodes: []string{"one"}, RecoveryNames: names,
Assigned: map[string][]Declared{"one": {{Module: "recovery", HoldsRecovery: true}, {Module: "plain"}}}}
users, err := Users(records)
if err != nil {
t.Fatal(err)
}
perms := map[string]Permissions{}
for _, u := range users {
if u.Kind == KindModule {
if perms[u.Module], err = PermissionsFor(u); err != nil {
t.Fatal(err)
}
}
}
for _, n := range []string{"KV_a_x", "OBJ_b_y"} {
for _, want := range []string{"$JS.API.STREAM.SNAPSHOT." + n, "$JS.SNAPSHOT.ACK." + n + ".abc", "$JS.API.STREAM.RESTORE." + n,
"$JS.SNAPSHOT.RESTORE." + n + ".abc", "$JS.API.STREAM.DELETE." + n, "$JS.API.CONSUMER.DURABLE.CREATE." + n + ".keeper"} {
if !MayPublish(perms["recovery"], want) {
t.Errorf("the recovery account may not publish %s", want)
}
if MayPublish(perms["plain"], want) {
t.Errorf("a module that holds no recovery seat may publish %s", want)
}
}
}
for _, n := range []string{"EVENTS", "SEAT_node-build-go", "KV_SEAT_x", "CONTROL"} {
if MayPublish(perms["recovery"], "$JS.API.STREAM.DELETE."+n) || MayPublish(perms["recovery"], "$JS.API.STREAM.SNAPSHOT."+n) {
t.Errorf("the recovery account may touch %s, a stream of the mesh's own", n)
}
}
}