The operator's one more grant in the frozen controller's composer (2026-10-26 08:54), beside the memberships grant of 22:31 (ADR 0547 clause 1 and 5): mesh-grants' principal may publish $JS.API.STREAM.CREATE.<stream> and $JS.API.STREAM.INFO.<stream> for each bucket (KV_<module>_<state>), log (LOG_<module>_<log>) and module stream a placed module's manifest declares, each by its own name, and nothing wider. The writers table lets it create, never update or delete. Byte-equal with mesh-sdk's buscompose (fix/1790-grants-create-buckets), whose expected lists this code wrote; the same test file holds both copies. Nothing else changes, and the mesh-sdk pin stays. Research 072: moves the grants piece (the grants part split out of the controller) one step, the creation of a module's declared bus objects; the controller's raise at start stays until it loses its lease. Issue: 1790
78 lines
3.5 KiB
Go
78 lines
3.5 KiB
Go
package broker
|
|
|
|
import "testing"
|
|
|
|
// Defends issue 1790 and novox/hq ADR 0547 §5 (the operator, 2026-10-26 08:54): the grants part may create the stream
|
|
// of each bucket, log and stream a placed module's manifest declares, by its own name, and read it back; nothing
|
|
// wider, nothing updated or deleted, and no other principal so. Held byte-equal in the controller's copy.
|
|
func TestTheGrantsPartCreatesOnlyDeclaredStreams(t *testing.T) {
|
|
records := Records{
|
|
Nodes: []string{"novox"},
|
|
Assigned: map[string][]Declared{"novox": {
|
|
{Module: "mesh-delivery-builder",
|
|
State: []Bucket{{Module: "mesh-delivery-builder", Name: "steps", History: 5}},
|
|
Logs: []Log{{Module: "mesh-delivery-builder", Name: "builds"}},
|
|
Streams: []ModuleStream{{Module: "mesh-delivery-builder", Name: "BUILDASKS", Events: []string{"ask"}}}},
|
|
{Module: GrantsModule, State: []Bucket{{Module: GrantsModule, Name: "assertions"}}},
|
|
}},
|
|
}
|
|
users, err := Users(records)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
perms := map[string]Permissions{}
|
|
for _, u := range users {
|
|
if u.Kind != KindModule {
|
|
continue
|
|
}
|
|
p, err := PermissionsFor(u)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", u.Username(), err)
|
|
}
|
|
perms[u.Module] = p
|
|
}
|
|
for _, row := range []struct {
|
|
who, subject string
|
|
may bool
|
|
}{
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.KV_mesh-delivery-builder_steps", true},
|
|
{GrantsModule, "$JS.API.STREAM.INFO.KV_mesh-delivery-builder_steps", true},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.LOG_mesh-delivery-builder_builds", true},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.BUILDASKS", true},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.KV_mesh-grants_assertions", true},
|
|
{GrantsModule, "$JS.API.STREAM.UPDATE.KV_mesh-delivery-builder_steps", false},
|
|
{GrantsModule, "$JS.API.STREAM.DELETE.KV_mesh-delivery-builder_steps", false},
|
|
{GrantsModule, "$JS.API.STREAM.PURGE.KV_mesh-delivery-builder_steps", false},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.KV_mesh-delivery-builder_undeclared", false},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.EVENTS", false},
|
|
{GrantsModule, "$JS.API.STREAM.CREATE.ASSIGNMENTS", false},
|
|
{GrantsModule, "$JS.API.STREAM.INFO.EVENTS", false},
|
|
{"mesh-delivery-builder", "$JS.API.STREAM.CREATE.KV_mesh-delivery-builder_steps", false},
|
|
} {
|
|
if got := MayPublish(perms[row.who], row.subject); got != row.may {
|
|
t.Errorf("%s may publish %s: %v, want %v", row.who, row.subject, got, row.may)
|
|
}
|
|
}
|
|
// A name that is no plain token is never granted, and a module other than the grants part is never granted one.
|
|
if got := CreateStreamGrants([]string{"*", ">", "KV_a.b", "KV_a_b"}); len(got) != 2 {
|
|
t.Errorf("grants for wildcard names: %v", got)
|
|
}
|
|
other, err := PermissionsFor(Principal{Kind: KindModule, Node: "novox", Module: "shop", CreatesStreams: []string{"KV_shop_x"}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if MayPublish(other, "$JS.API.STREAM.CREATE.KV_shop_x") {
|
|
t.Error("a module other than the grants part was granted a create")
|
|
}
|
|
// The writers table refuses the grants part an update, and a create of a stream it was not given.
|
|
g := Principal{Kind: KindModule, Node: "novox", Module: GrantsModule, CreatesStreams: []string{"KV_a_b"}}
|
|
if err := CheckWriters(g, []string{"$JS.API.STREAM.CREATE.KV_a_b"}); err != nil {
|
|
t.Errorf("the declared create refused: %v", err)
|
|
}
|
|
for _, refused := range []string{"$JS.API.STREAM.UPDATE.KV_a_b", "$JS.API.STREAM.CREATE.KV_a_c", "$JS.API.STREAM.CREATE.*"} {
|
|
if CheckWriters(g, []string{refused}) == nil {
|
|
t.Errorf("%s was not refused", refused)
|
|
}
|
|
}
|
|
}
|