mesh/merge-gate head bff1ac14a198 merged into trunk 49c9002c04d3 beside mesh-controller#355@8c381172 — pass: builds mesh-host → ace, g14, novox, shanks; no…
mesh/repo-check head bff1ac14a198 merged into trunk 49c9002c04d3 beside mesh-controller#355@8c381172 — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group release/57-config-and-provisioning delivered: every member is delivered
135 lines
4.8 KiB
Go
135 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/crypto/nacl/box"
|
|
|
|
"github.com/novox/mesh-host/internal/identity"
|
|
"github.com/novox/mesh-host/internal/link"
|
|
)
|
|
|
|
// standInVault answers move-in's two steps as the vault does: a key made for the call, the value opened with it,
|
|
// and the value kept read back sealed to the key the second step sent. lie makes its read-back another value.
|
|
type standInVault struct {
|
|
t *testing.T
|
|
pub *[32]byte
|
|
priv *[32]byte
|
|
opened map[string]any
|
|
kept string
|
|
lie string
|
|
refuse string
|
|
carried []string
|
|
}
|
|
|
|
func (v *standInVault) ask(verb string, args any) (json.RawMessage, error) {
|
|
raw, _ := json.Marshal(args)
|
|
v.carried = append(v.carried, string(raw))
|
|
if verb != "move-in" {
|
|
v.t.Fatalf("asked %s", verb)
|
|
}
|
|
if v.refuse != "" {
|
|
return nil, errors.New(v.refuse)
|
|
}
|
|
var a map[string]any
|
|
_ = json.Unmarshal(raw, &a)
|
|
if a["call"] == nil {
|
|
v.opened = a
|
|
pub, priv, _ := box.GenerateKey(rand.Reader)
|
|
v.pub, v.priv = pub, priv
|
|
return json.Marshal(map[string]string{"call": "c1", "seal_to": base64.StdEncoding.EncodeToString(pub[:]),
|
|
"secret": "own/anchor/postgres/superuser-password"})
|
|
}
|
|
blob, _ := base64.StdEncoding.DecodeString(a["sealed"].(string))
|
|
value, ok := box.OpenAnonymous(nil, blob, v.pub, v.priv)
|
|
if !ok {
|
|
v.t.Fatal("what the engine sealed does not open with the call's key")
|
|
}
|
|
v.kept = string(value)
|
|
back := v.kept
|
|
if v.lie != "" {
|
|
back = v.lie
|
|
}
|
|
key, _ := base64.StdEncoding.DecodeString(a["read_back_to"].(string))
|
|
var to [32]byte
|
|
copy(to[:], key)
|
|
boxed, _ := box.SealAnonymous(nil, []byte(back), &to, rand.Reader)
|
|
return json.Marshal(map[string]any{"name": "own/anchor/postgres/superuser-password", "generation": 1,
|
|
"read_back": base64.StdEncoding.EncodeToString(boxed)})
|
|
}
|
|
|
|
const theValue = "the-superusers-password"
|
|
|
|
func aMoveOf(t *testing.T, key identity.SealingKey) link.MoveSecret {
|
|
t.Helper()
|
|
sealed, err := identity.Seal(key.Public, []byte(theValue))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return link.MoveSecret{Node: "anchor", By: "the move", MoveSecretAsk: link.MoveSecretAsk{Module: "postgres",
|
|
Name: "superuser-password", Origin: "made", Generation: "g-1", Sealed: sealed, SealedTo: key.Public}}
|
|
}
|
|
|
|
// The engine opens what was sealed to its machine, hands it to the vault sealed to the call's key — never in the
|
|
// clear — and answers what the vault kept only once the read-back opens to the same value.
|
|
func TestTheEngineMovesAValueSealedToItAndChecksTheReadBack(t *testing.T) {
|
|
key, err := identity.GenerateSealingKey()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
vault := &standInVault{t: t}
|
|
moved, err := moveIntoTheVault(vault.ask, key, aMoveOf(t, key))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if moved.Secret != "own/anchor/postgres/superuser-password" || moved.Generation != 1 || vault.kept != theValue {
|
|
t.Fatalf("moved %+v, the vault kept %q", moved, vault.kept)
|
|
}
|
|
if vault.opened["module"] != "postgres" || vault.opened["name"] != "superuser-password" || vault.opened["node"] != "anchor" ||
|
|
vault.opened["origin"] != "made" || vault.opened["generation"] != "g-1" ||
|
|
vault.opened["sealing_key"] != key.Public {
|
|
t.Errorf("the first step named %v", vault.opened)
|
|
}
|
|
if strings.Contains(strings.Join(vault.carried, " "), theValue) {
|
|
t.Fatal("the value crossed the bus in the clear")
|
|
}
|
|
}
|
|
|
|
// A read-back that is not the value handed in is a failed move, said; so is a value this machine cannot open, and
|
|
// the vault's refusal.
|
|
func TestTheEngineSaysAMoveThatDidNotHold(t *testing.T) {
|
|
key, _ := identity.GenerateSealingKey()
|
|
vault := &standInVault{t: t, lie: "something-else"}
|
|
if _, err := moveIntoTheVault(vault.ask, key, aMoveOf(t, key)); err == nil ||
|
|
!strings.Contains(err.Error(), "read back") {
|
|
t.Fatalf("a read-back of another value: %v", err)
|
|
}
|
|
other, _ := identity.GenerateSealingKey()
|
|
if _, err := moveIntoTheVault((&standInVault{t: t}).ask, key, aMoveOf(t, other)); err == nil ||
|
|
!strings.Contains(err.Error(), "sealing key") {
|
|
t.Fatalf("a value sealed to another key: %v", err)
|
|
}
|
|
refusing := &standInVault{t: t, refuse: "the move never replaces a value the vault holds"}
|
|
if _, err := moveIntoTheVault(refusing.ask, key, aMoveOf(t, key)); err == nil ||
|
|
!strings.Contains(err.Error(), "never replaces") {
|
|
t.Fatalf("the vault's refusal: %v", err)
|
|
}
|
|
// A pair credential names both its ends.
|
|
pair := aMoveOf(t, key)
|
|
pair.Module, pair.Name = "", ""
|
|
pair.Provider, pair.Provision, pair.Consumer, pair.ConsumerModule = "anchor", "database", "shanks", "gitea"
|
|
ends := &standInVault{t: t}
|
|
if _, err := moveIntoTheVault(ends.ask, key, pair); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ends.opened["provider"] != "anchor" || ends.opened["consumer"] != "shanks" || ends.opened["consumer_module"] != "gitea" ||
|
|
ends.opened["node"] != nil {
|
|
t.Errorf("the pair's first step named %v", ends.opened)
|
|
}
|
|
}
|