Files
mesh-catalog/modules/mesh-cli/cmd/mesh-cli/enrol_test.go
T
jschoubben 9249ca7b57 mesh-cli: nox enrol open opens a sealed enrolment token locally with the operator's private key
The seat mesh-enrolment's tokens answers the token sealed to the operator key; the operator opens it at their own
terminal. The subcommand reads the sealed token on standard input and the private key from a file, prints the token text
a joining machine takes, asks nothing of the node-engine's socket, and says the token is not sealed to a wrong key
(ADR 0587 §6, §8). New: one table-style test function; mesh-cli had 6, so none was merged or deleted.

(issue 774, 774/S51)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 01:42:19 +01:00

81 lines
3.5 KiB
Go

package main
import (
"bytes"
"context"
"crypto/rand"
"encoding/base64"
"encoding/json"
"io"
"os"
"path/filepath"
"strings"
"testing"
"golang.org/x/crypto/nacl/box"
)
// 774/S51/AC1, AC2 (novox/hq ADR 0587 §6, §8): a token sealed to a test operator key (as mesh-vault seals it: the text
// of the token, anonymous box, base64) is opened with the private half and printed as a token the engine's parser reads
// (base64url of version 1 JSON with node, broker, fingerprint, signer and secret), and nothing is asked of the engine's
// socket, which here is a path nobody listens on; the wrong key prints nothing and says the token is not sealed to it.
func TestEnrolOpenOpensASealedTokenLocallyAndOnlyWithItsKey(t *testing.T) {
t.Setenv("MESH_VERB", "")
token := base64.RawURLEncoding.EncodeToString([]byte(`{"v":1,"node":"new1","broker":"tls://10.77.0.1:4222",` +
`"fingerprint":"sha256:bus","signer":"` + base64.StdEncoding.EncodeToString(make([]byte, 32)) + `","secret":"one-time"}`))
pub, priv, _ := box.GenerateKey(rand.Reader)
_, otherPriv, _ := box.GenerateKey(rand.Reader)
sealed, err := box.SealAnonymous(nil, []byte(token), pub, rand.Reader)
if err != nil {
t.Fatal(err)
}
dir := t.TempDir()
keyFile := func(name string, k *[32]byte) string {
p := filepath.Join(dir, name)
if err := os.WriteFile(p, []byte(base64.StdEncoding.EncodeToString(k[:])+"\n"), 0o600); err != nil {
t.Fatal(err)
}
return p
}
before, beforeIn := socket, standardInput
socket = filepath.Join(dir, "nobody-listens.sock")
t.Cleanup(func() { socket, standardInput = before, beforeIn })
for _, c := range []struct {
name string
args []string
stdin string
code int
out string
err string
}{
{"the right key", []string{"enrol", "open", "--key", keyFile("op", priv)}, base64.StdEncoding.EncodeToString(sealed) + "\n", 0, token + "\n", ""},
{"the key as --key=", []string{"enrol", "open", "--key=" + keyFile("op2", priv)}, base64.StdEncoding.EncodeToString(sealed), 0, token + "\n", ""},
{"the wrong key", []string{"enrol", "open", "--key", keyFile("other", otherPriv)}, base64.StdEncoding.EncodeToString(sealed), 1, "", "not sealed to that key"},
{"no key", []string{"enrol", "open"}, base64.StdEncoding.EncodeToString(sealed), 2, "", "nox enrol open --key"},
{"not a sealed token", []string{"enrol", "open", "--key", keyFile("op3", priv)}, "@@@", 1, "", "not a sealed token"},
} {
standardInput = func() (io.Reader, bool) { return strings.NewReader(c.stdin), false }
var out, errOut bytes.Buffer
code := run(context.Background(), c.args, &out, &errOut)
if code != c.code || out.String() != c.out || !strings.Contains(errOut.String(), c.err) {
t.Errorf("%s: exit %d, stdout %q, stderr %q", c.name, code, out.String(), errOut.String())
}
}
// What it prints is a token the engine's parser reads.
var parsed struct {
V int `json:"v"`
Node string `json:"node"`
Secret string `json:"secret"`
}
raw, _ := base64.RawURLEncoding.DecodeString(token)
if json.Unmarshal(raw, &parsed) != nil || parsed.V != 1 || parsed.Node != "new1" || parsed.Secret != "one-time" {
t.Errorf("the token is %+v", parsed)
}
// Standard input a terminal is never read.
standardInput = func() (io.Reader, bool) { return strings.NewReader("x"), true }
var out, errOut bytes.Buffer
if code := run(context.Background(), []string{"enrol", "open", "--key", keyFile("op4", priv)}, &out, &errOut); code != 2 || out.Len() != 0 {
t.Errorf("a terminal on standard input: exit %d, stdout %q", code, out.String())
}
}