The vault takes a value only from the controller, which it knows from the subject that names its caller. The grant is composed from the records, as the issued tools' is, so the installer's first user list is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
4.1 KiB
Go
100 lines
4.1 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"},
|
|
"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)
|
|
}
|
|
}
|
|
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)
|
|
}
|
|
}
|