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") }