package broker import ( "strings" "testing" ) // The move of the secrets into the vault (design 57's V3, issue 676): each machine's node-engine may ask the // vault's move-in in its own name — the subject that names it, and no other machine's — once the vault's holder // serves it; it hears the controller's ask to move a value on its own subject; and the controller may copy its // record of asks with the vault's move-asks. Composed from the records: a vault that serves neither grants nothing. func TestANodeEngineMayMoveItsSecretsIntoTheVaultInItsOwnName(t *testing.T) { vault := Declared{Module: "mesh-vault", Holds: []Seat{{Name: "mesh-vault", Serves: []string{"get", "accept", "secret-ask", "issued", "rotate", "move-in", "move-asks"}}}} users, err := Users(Records{Nodes: []string{"anchor", "shanks"}, Assigned: map[string][]Declared{"anchor": {vault}}}) if err != nil { t.Fatal(err) } var anchor, controller Principal for _, u := range users { switch { case u.Kind == KindNode && u.Node == "anchor": anchor = u case u.Kind == KindController: controller = u } } p, err := PermissionsFor(anchor) if err != nil { t.Fatal(err) } if !MayPublish(p, CalledSubject("mesh.seat.mesh-vault.tool.move-in", "node.anchor")) { t.Error("anchor's node-engine may not ask the vault's move-in in its own name") } for _, s := range []string{CalledSubject("mesh.seat.mesh-vault.tool.move-in", "node.shanks"), CalledSubject("mesh.seat.mesh-vault.tool.move-in", ControllerName), CalledSubject("mesh.seat.mesh-vault.tool.get", "node.anchor"), CalledSubject("mesh.seat.mesh-vault.tool.accept", "node.anchor"), "mesh.seat.mesh-vault.tool.move-in"} { if MayPublish(p, s) { t.Errorf("anchor's node-engine may publish %s", s) } } if !MaySubscribe(p, AskMoveSecretSubject("anchor")) || MaySubscribe(p, AskMoveSecretSubject("shanks")) { t.Error("anchor's node-engine does not hear its own move asks alone") } // The vault's holder hears the call naming the node-engine. held := false for _, u := range users { if u.Kind == KindModule && u.Module == "mesh-vault" { held = true h, err := PermissionsFor(u) if err != nil { t.Fatal(err) } if !MaySubscribe(h, CalledSubject("mesh.seat.mesh-vault.tool.move-in", "node.anchor")) { t.Error("the vault's holder does not hear move-in asked by a node-engine") } } } if !held { t.Fatal("no principal holds the vault's seat") } c, err := PermissionsFor(controller) if err != nil { t.Fatal(err) } if !MayPublish(c, CalledSubject("mesh.seat.mesh-vault.tool.move-asks", ControllerName)) { t.Error("the controller may not copy its record of asks into the vault") } if MayPublish(c, CalledSubject("mesh.seat.mesh-vault.tool.move-in", ControllerName)) { t.Error("the controller may move a value in itself: it opens none") } if !MayPublish(c, AskMoveSecretSubject("anchor")) { t.Error("the controller may not ask a machine's node-engine to move a value") } // A vault that serves neither, the running one: no grant for either. older := Declared{Module: "mesh-vault", Holds: []Seat{{Name: "mesh-vault", Serves: []string{"get"}}}} users, _ = Users(Records{Nodes: []string{"anchor"}, Assigned: map[string][]Declared{"anchor": {older}}}) for _, u := range users { p, _ := PermissionsFor(u) for _, s := range p.Publish { if strings.Contains(s, "move-in") || strings.Contains(s, "move-asks") { t.Errorf("%s may publish %s while the vault serves neither", u.Username(), s) } } } }