Grant the bus's own module the snapshot API and nothing else (hq ADR 0235)
The night's backup of the bus takes each stream through JetStream's snapshot API, run by the nats module under its own account. The module holding mesh-broker is composed that account: stream names and info, the snapshot request, its flow-control acks, its own inbox — no write, which the writers table checks. A bus module declaring anything else to say on the bus is refused by module check rather than silently granted nothing. The genesis user list is unchanged: the controller's grants are.
This commit is contained in:
@@ -141,6 +141,9 @@ func declaredFor(m catalogue.Manifest, seats map[string]catalogue.SeatDeclaratio
|
||||
if _, reads := m.OwnSecrets["broker"]; !reads {
|
||||
d.NoAccount = true
|
||||
}
|
||||
// The bus's own module — the one holding mesh-broker — copies the bus's streams for the night's
|
||||
// backup, and its account is granted that and nothing else (novox/hq ADR 0235).
|
||||
d.SnapshotsTheBus = m.ClaimsSeat(catalogue.BrokerSeat)
|
||||
for _, c := range m.Claims {
|
||||
// Every seat with a protocol, the mesh's own included. One that says only who does a job is
|
||||
// not here and grants nothing, which is most of them.
|
||||
|
||||
@@ -241,3 +241,58 @@ func TestIssuingATokenRecordsTheAccountItIsThePasswordOf(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The module holding mesh-broker is the bus, and its user is the bus's own: granted the snapshot API
|
||||
// for the night's backup and nothing else, whatever tools it declares (novox/hq ADR 0235). Another
|
||||
// module on the same machine is granted none of it.
|
||||
func TestTheBussOwnModuleBecomesTheSnapshotUser(t *testing.T) {
|
||||
bus := catalogue.Manifest{
|
||||
Module: "nats", Version: "1",
|
||||
Provides: []catalogue.Offer{{Name: "mesh-bus", Scope: catalogue.ScopeMesh}},
|
||||
Claims: []catalogue.Claim{{Name: catalogue.BrokerSeat, Scope: catalogue.ScopeMesh}},
|
||||
Tools: []string{"nats_streams"},
|
||||
OwnSecrets: catalogue.OwnSecrets{"broker": {Path: "/run/broker"}},
|
||||
}
|
||||
shop := catalogue.Manifest{Module: "shop", Version: "1", Emits: []string{"order.placed"},
|
||||
OwnSecrets: catalogue.OwnSecrets{"broker": {Path: "/run/broker"}}}
|
||||
inv, ctx := aMeshWith(t, bus, shop)
|
||||
if _, err := inv.AddNode(ctx, "one"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, module := range []string{"nats", "shop"} {
|
||||
if _, err := inv.Assign(ctx, "one", module); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
records, err := inv.BusRecords(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
users, err := broker.Users(records)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, u := range users {
|
||||
perms, err := broker.PermissionsFor(u)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
snapshots := granted(perms.Publish, "$JS.API.STREAM.SNAPSHOT.*")
|
||||
switch u.Username() {
|
||||
case "one.nats":
|
||||
seen[u.Username()] = true
|
||||
if !snapshots || len(perms.Publish) != len(broker.BusSnapshotGrants.Publish) {
|
||||
t.Fatalf("the bus's own user is granted %v, not the snapshot API alone", perms.Publish)
|
||||
}
|
||||
case "one.shop":
|
||||
seen[u.Username()] = true
|
||||
if snapshots {
|
||||
t.Fatal("a module that is not the bus may snapshot it")
|
||||
}
|
||||
}
|
||||
}
|
||||
if !seen["one.nats"] || !seen["one.shop"] {
|
||||
t.Fatalf("users derived: %v", seen)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user