Files
mesh-controller/internal/catalogue/vault_seat_test.go
T
mesh-tools 97a2d841c7 Land feature 57's controller work on its release branch
The controller plans config, templates and moved providers' provisions,
hands bus accounts to the vault and judges the new manifest words, on the
feature's SDK and node-engine validator (feature 57, config and provisioning).
2026-10-15 21:27:33 +00:00

172 lines
6.8 KiB
Go

package catalogue
import "testing"
// The vault's provision is one the controller itself dereferences — every minted credential is
// sealed with it — so it is delivered by a seat of the mesh's own, and a second provider is a second
// claimant refused by name rather than a candidate for a pin (novox/hq ADR 0161, issue 106).
func TestTheVaultsSeatDeliversSecret(t *testing.T) {
seat, known := SeatNamed("mesh-vault")
if !known {
t.Fatal("mesh-vault is not in the mesh's own set")
}
if seat.Scope != ScopeMesh || seat.Delivers != "secret" {
t.Fatalf("mesh-vault is %s-scoped and delivers %q; one per mesh, delivering secret", seat.Scope, seat.Delivers)
}
vault := Manifest{Module: "mesh-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-vault", Scope: ScopeMesh}}}
if err := CanHold(vault, seat); err != nil {
t.Fatalf("the vault, claiming its seat and providing secret, was refused: %v", err)
}
another := Manifest{Module: "other-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}}}
if err := CanHold(another, seat); err == nil {
t.Fatal("a provider of secret that does not claim the seat was allowed to hold it")
}
}
// The vault answers `get` on request and reply (novox/hq ADR 0349 §11, issue 674): the seat promises the
// verb, so a holder serving it is accepted — and, optional while the vault that runs is the TypeScript one,
// so is a holder that does not yet.
func TestTheVaultsSeatPromisesGet(t *testing.T) {
seat, _ := SeatNamed("mesh-vault")
var get *Verb
for i := range seat.Serves {
if seat.Serves[i].Name == "get" {
get = &seat.Serves[i]
}
}
if get == nil {
t.Fatal("the vault's seat does not promise get")
}
for _, arg := range []string{"name", "public_key"} {
if props, _ := get.Input["properties"].(map[string]any); props[arg] == nil {
t.Errorf("get takes no %s", arg)
}
}
serving := Manifest{Module: "mesh-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-vault", Scope: ScopeMesh, Serves: []string{"get"}}}}
if err := CanHold(serving, seat); err != nil {
t.Fatalf("the vault serving get was refused: %v", err)
}
notYet := Manifest{Module: "mesh-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-vault", Scope: ScopeMesh}}}
if err := CanHold(notYet, seat); err != nil {
t.Fatalf("the vault that does not serve get yet was refused: %v", err)
}
}
// The vault takes values in and rotates them (novox/hq ADR 0349 clauses 8 to 10, issue 675): the seat promises
// accept, secret-ask, issued and rotate, each with the arguments of its steps; a holder serving them is accepted,
// and, optional while the vault that runs does not, so is one that does not yet.
func TestTheVaultsSeatPromisesItsIntakeVerbs(t *testing.T) {
seat, _ := SeatNamed("mesh-vault")
want := map[string][]string{
"accept": {"node", "module", "name", "provider", "provision", "by", "call", "sealed"},
"secret-ask": {"node", "module", "name", "desk", "asked_by", "outcome", "call", "sealed"},
"issued": {"provision", "provider", "module", "call", "sealed", "holders"},
"rotate": {"node", "module", "name", "provider", "provision", "by"},
}
for name, args := range want {
var verb *Verb
for i := range seat.Serves {
if seat.Serves[i].Name == name {
verb = &seat.Serves[i]
}
}
if verb == nil {
t.Errorf("the vault's seat does not promise %s", name)
continue
}
if !verb.Optional {
t.Errorf("%s is not optional while the vault that runs does not serve it", name)
}
props, _ := verb.Input["properties"].(map[string]any)
for _, arg := range args {
if props[arg] == nil {
t.Errorf("%s takes no %s", name, arg)
}
}
if props["value"] != nil {
t.Errorf("%s takes a value in the clear", name)
}
}
// The holders `issued` names (issue 749) are a list of {node, module}.
for _, verb := range seat.Serves {
if verb.Name != "issued" {
continue
}
props, _ := verb.Input["properties"].(map[string]any)
holders, _ := props["holders"].(map[string]any)
items, _ := holders["items"].(map[string]any)
each, _ := items["properties"].(map[string]any)
if holders["type"] != "array" || each["node"] == nil || each["module"] == nil {
t.Errorf("issued's holders are %v", holders)
}
}
serving := Manifest{Module: "mesh-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-vault", Scope: ScopeMesh,
Serves: []string{"get", "accept", "secret-ask", "issued", "rotate"}}}}
if err := CanHold(serving, seat); err != nil {
t.Fatalf("the vault serving its verbs was refused: %v", err)
}
}
// The move of the controller's secrets into the vault (design 57's V3, issue 676): the seat promises move-in, which a
// machine's node-engine asks in two steps with the row, its origin and generation, then the value sealed to the
// call's key and a key to read back to; and move-asks, the controller's record of asks copied as it is. Optional
// while the vault that runs does not serve them; never a value in the clear.
func TestTheVaultsSeatPromisesTheMove(t *testing.T) {
seat, _ := SeatNamed("mesh-vault")
want := map[string][]string{
"move-in": {"node", "module", "name", "provider", "provision", "consumer", "consumer_module", "local", "origin",
"generation", "made_at", "call", "sealed", "read_back_to"},
"move-asks": {"asks"},
}
for name, args := range want {
var verb *Verb
for i := range seat.Serves {
if seat.Serves[i].Name == name {
verb = &seat.Serves[i]
}
}
if verb == nil {
t.Errorf("the vault's seat does not promise %s", name)
continue
}
if !verb.Optional {
t.Errorf("%s is not optional while the vault that runs does not serve it", name)
}
props, _ := verb.Input["properties"].(map[string]any)
for _, arg := range args {
if props[arg] == nil {
t.Errorf("%s takes no %s", name, arg)
}
}
if props["value"] != nil {
t.Errorf("%s takes a value in the clear", name)
}
}
serving := Manifest{Module: "mesh-vault", Provides: []Offer{{Name: "secret", Scope: ScopeMesh}},
Claims: []Claim{{Name: "mesh-vault", Scope: ScopeMesh,
Serves: []string{"get", "accept", "secret-ask", "issued", "rotate", "move-in", "move-asks"}}}}
if err := CanHold(serving, seat); err != nil {
t.Fatalf("the vault serving the move was refused: %v", err)
}
}
// Issue 786: the vault's seat promises node-key, optional while the vault that runs does not serve it.
func TestTheVaultsSeatPromisesNodeKey(t *testing.T) {
seat, _ := SeatNamed("mesh-vault")
for _, v := range seat.Serves {
if v.Name != "node-key" {
continue
}
props, _ := v.Input["properties"].(map[string]any)
if !v.Optional || props["key"] == nil {
t.Errorf("node-key: optional %v, key %v", v.Optional, props["key"])
}
return
}
t.Error("the vault's seat does not promise node-key")
}