Grant the bus keeper its account's information, which every bucket create asks first
mesh/delivery merged: source.main moved to novox/mesh-delivery@3f96301177b1
mesh/check checking 66f31c8e97a6 on f9cadbfdbb93

The keeper on novox (nats fea2c02b) has been refused $JS.API.INFO every 30 s since
21:58 UTC: the client library's CreateKeyValue asks the account's information before
it creates a bucket, so each create of KV_distribution_* and KV_gitea_* timed out and
the keeper never finished a fill pass (health failed). Read-only: the account's limits
and usage, never a stream's data.

Claude-Session: https://claude.ai/code/session_01NcbgfFfQ4Z9UE5jK32PmE5
This commit is contained in:
2026-11-08 23:07:00 +01:00
parent f9cadbfdbb
commit 66f31c8e97
2 changed files with 9 additions and 2 deletions
@@ -1141,6 +1141,10 @@ func theBusModulesProcessKeepsBusState(t *testing.T) {
perms[u.Username()] = p
}
keeper := perms["a.nats.keeper"]
// A key-value bucket's create asks the account's information first (the client library's CreateKeyValue).
if !MayPublish(keeper, "$JS.API.INFO") {
t.Errorf("the bus module's process may not read its account's information, which every bucket create asks first")
}
for _, u := range []string{"a.nats.keeper", "a.nats.other", "a.mod-x.sneak", "a.node-tools", "a.nats.nats-tools", "a.admin-ish"} {
if _, ok := perms[u]; !ok {
t.Fatalf("no user %s composed: %v", u, slices.Collect(maps.Keys(perms)))
@@ -168,9 +168,12 @@ func BusStateNames(asked map[string][]catalogue.BusStateEntry, bound map[string]
// update, information, deletion and snapshot with the acknowledgement of the snapshot's chunks (ADR 0626 §1; the server
// waits on `$JS.SNAPSHOT.ACK.<stream>.…` past its window), and the stream list it finds orphans in. Never a consumer of
// one, nor any stream's own subjects: a snapshot carries an entry's data to the keeper's inbox alone, and the keeper
// hears no message of it (ADR 0626 §1, restricted streams included).
// hears no message of it (ADR 0626 §1, restricted streams included). And the account's own information
// ($JS.API.INFO): the client library asks it before every key-value bucket it creates, so without it each create times
// out on a refused publish (the keeper's KV_distribution_* and KV_gitea_*, 2026-11-08); it reads the account's limits and
// usage, never a stream's data.
func busStateKeeperGrants(names []string) []string {
out := []string{"$JS.API.STREAM.NAMES", "$JS.API.STREAM.LIST"}
out := []string{"$JS.API.INFO", "$JS.API.STREAM.NAMES", "$JS.API.STREAM.LIST"}
for _, n := range names {
for _, op := range []string{"CREATE", "UPDATE", "INFO", "DELETE", "SNAPSHOT"} {
out = append(out, "$JS.API.STREAM."+op+"."+n)