Say which bus accounts the grants part wants, in a state only the vault reads, and what the vault says when it mints one, so the vault can mint from the grants part's word (issue 774, ADR 0561 §2)

This commit is contained in:
2026-10-28 21:54:04 +01:00
parent af08be36a2
commit da506bb3b8
3 changed files with 201 additions and 2 deletions
+51
View File
@@ -293,4 +293,55 @@ func TestTheCopiedComposerComposesAsTheControllers(t *testing.T) {
}
grantsAsTheControllers(t, got, string(want))
})
// 774/AC2 (novox/hq ADR 0561 §2): a wanted account round-trips through the grants part's state `accounts`, keyed by
// its user, at the subject `$KV.mesh-grants_accounts.<user>`, read by the vault alone; and the vault's account-issued
// names the account, never a value.
t.Run("a wanted account is kept by its user and read by the vault alone", func(t *testing.T) {
for _, w := range []WantedAccount{
{User: "ace.mesh-build-go", Kind: KindModule, Node: "ace", Module: "mesh-build-go", URL: "nats://novox.mesh:4222",
Fingerprint: "ab", Claims: []ClaimedSeat{{Seat: "node-build-go", Scope: "node", Serves: []string{"build"}}}},
{User: "novox.mesh-mail.send", Kind: KindProcess, Node: "novox", Module: "mesh-mail", Process: "send",
URL: "nats://novox.mesh:4222"},
{User: "provisioner.g14", Kind: KindProvisioner, Node: "g14", Module: "mesh-provisioner-client",
URL: "nats://novox.mesh:4222", Fingerprint: "ab"},
} {
if err := w.Valid(); err != nil {
t.Fatalf("%s: %v", w.User, err)
}
raw, err := json.Marshal(w)
if err != nil {
t.Fatal(err)
}
back, err := ReadWantedAccount(w.User, raw)
if err != nil || !back.Same(w) {
t.Errorf("%s does not round-trip: %+v, %v", w.User, back, err)
}
if got := AccountsSubject(w.User); got != "$KV.mesh-grants_accounts."+w.User {
t.Errorf("%s is kept at %s", w.User, got)
}
if _, err := ReadWantedAccount("someone.else", raw); err == nil {
t.Errorf("%s was read under another user's key", w.User)
}
}
for _, bad := range []WantedAccount{
{User: "ace.x", Kind: KindModule, Node: "ace", Module: "y", URL: "nats://a:1"},
{User: "ace.x.p", Kind: KindProcess, Node: "ace", Module: "x", URL: "nats://a:1"},
{User: "node.ace", Kind: KindNode, Node: "ace", URL: "nats://a:1"},
{User: "controller", Kind: KindController, URL: "nats://a:1"},
{User: "ace.x", Kind: KindModule, Node: "ace", Module: "x"},
} {
if bad.Valid() == nil {
t.Errorf("%+v is taken as a wanted account", bad)
}
}
if ReaderMay("mesh-delivery-assigner", GrantsAccounts) || !ReaderMay(VaultSeat, GrantsAccounts) {
t.Errorf("%s is read by %v alone, want the vault's", GrantsAccounts, NamedReaders[GrantsAccounts])
}
e := AccountIssued{User: "ace.x", Kind: KindModule, Node: "ace", Module: "x", Generation: 1}
raw, _ := json.Marshal(e)
if strings.Contains(string(raw), "password") || strings.Contains(string(raw), "hash") ||
AccountIssuedSubject != "mesh.mod.mesh-vault.event.account-issued" {
t.Errorf("account-issued says %s at %s", raw, AccountIssuedSubject)
}
})
}