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).
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/broker"
|
||||
"github.com/novox/mesh-controller/internal/testbus"
|
||||
)
|
||||
|
||||
// The move's ask and answer keep the engine's field names (mesh-host internal/link,
|
||||
// TestTheMovesAskKeepsItsFieldNamesAndContext): the row's fields beside a hand-over's, under a context of its own.
|
||||
func TestTheMovesAskAndAnswerKeepTheirFieldNames(t *testing.T) {
|
||||
keys := func(v any) string {
|
||||
raw, _ := json.Marshal(v)
|
||||
var m map[string]any
|
||||
_ = json.Unmarshal(raw, &m)
|
||||
var out []string
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return strings.Join(out, " ")
|
||||
}
|
||||
ask := MoveSecretAsk{Module: "m", Name: "n", Provider: "p", Provision: "q", Consumer: "c", ConsumerModule: "cm",
|
||||
Local: "l", Origin: "made", Generation: "g", MadeAt: time.Unix(1, 0).UTC(), Sealed: "s", SealedTo: "k"}
|
||||
if got := keys(ask); got != "consumer consumer_module generation local made_at module name origin provider "+
|
||||
"provision sealed sealed_to" {
|
||||
t.Fatalf("the ask's fields are %q", got)
|
||||
}
|
||||
answer := MoveSecretAnswer{Said: "s", Refused: "r", Secret: "own/a/b/c", Generation: 1, Unchanged: true}
|
||||
if got := keys(answer); got != "generation refused said secret unchanged" {
|
||||
t.Fatalf("the answer's fields are %q", got)
|
||||
}
|
||||
if broker.AskMoveSecretSubject("laptop") != "mesh.node.laptop.ask.move-secret" ||
|
||||
MoveSecretContext != "novox-mesh move-secret v1\n" {
|
||||
t.Fatalf("the subject %q, the context %q", broker.AskMoveSecretSubject("laptop"), MoveSecretContext)
|
||||
}
|
||||
}
|
||||
|
||||
// A move is asked of the machine on its own subject, signed under its own context — never a hand-over's — naming
|
||||
// no path and carrying the row beside the hand-over's fields; the engine's answer comes back whole.
|
||||
func TestAMoveIsAskedOfTheMachineSignedUnderItsOwnContext(t *testing.T) {
|
||||
conn, err := nats.Connect(testbus.URL(t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(conn.Close)
|
||||
signer, public := testSigner(t)
|
||||
var heard HandOverAsk
|
||||
var row MoveSecretAsk
|
||||
engine, err := conn.Subscribe(broker.AskMoveSecretSubject("laptop"), func(msg *nats.Msg) {
|
||||
var signed SignedHandOver
|
||||
_ = json.Unmarshal(msg.Data, &signed)
|
||||
if ed25519.Verify(public, append([]byte(HandOverContext), signed.Ask...), signed.Signature) ||
|
||||
!ed25519.Verify(public, append([]byte(MoveSecretContext), signed.Ask...), signed.Signature) {
|
||||
_ = msg.Respond([]byte(`{"refused":"not signed as a move"}`))
|
||||
return
|
||||
}
|
||||
_ = json.Unmarshal(signed.Ask, &heard)
|
||||
_ = json.Unmarshal(signed.Ask, &row)
|
||||
body, _ := json.Marshal(MoveSecretAnswer{Said: "moved", Secret: "own/laptop/" + row.Module + "/" + row.Name,
|
||||
Generation: 1})
|
||||
_ = msg.Respond(body)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = engine.Unsubscribe() })
|
||||
a, err := AskMoveSecret(context.Background(), conn, signer, "laptop", "the move",
|
||||
MoveSecretAsk{Module: "postgres", Name: "superuser-password", Origin: "made", Sealed: "c2Vh"}, 5*time.Second)
|
||||
if err != nil || a.Secret != "own/laptop/postgres/superuser-password" || a.Generation != 1 {
|
||||
t.Fatalf("answered %+v, %v", a, err)
|
||||
}
|
||||
if heard.Node != "laptop" || heard.Path != "" || heard.Nonce == "" || heard.Expires.IsZero() || heard.By != "the move" ||
|
||||
row.Sealed != "c2Vh" || row.Origin != "made" {
|
||||
t.Fatalf("the engine heard %+v %+v", heard, row)
|
||||
}
|
||||
if _, err := AskMoveSecret(context.Background(), conn, signer, "anchor", "the move", MoveSecretAsk{}, 2*time.Second); err == nil ||
|
||||
!strings.Contains(err.Error(), "nothing was moved") {
|
||||
t.Fatalf("a machine with no engine listening: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user