The enrolment request is a struct in each repository, and this node now reports a third key — the one its secrets are sealed to. That wiring had tests on each side and had never been run across the join, where a renamed field fails silently: enrolment succeeds, the key is absent, and the node looks joined until the first thing sealed to it cannot be opened. So this writes a real one — keys generated the way enrolment generates them, not typed as literals — and the private half of the sealing key beside it, so the other side can prove what it sealed is openable rather than merely present. The mirror of the declaration check that already runs the other way.
63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
package link
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-host/internal/identity"
|
|
)
|
|
|
|
// What this node says when it joins, written out so the mesh's own suite can accept it.
|
|
//
|
|
// The two ends are separate structs in separate repositories. Every field here is one somebody
|
|
// could rename on one side, and the failure would be silent: enrolment succeeds, a key is simply
|
|
// absent, and the node looks joined until the first thing sealed to it cannot be opened. That is
|
|
// exactly the shape of fault this project keeps finding late.
|
|
//
|
|
// Skipped unless MESH_ENROL_OUT names a file, so this is a check somebody runs deliberately
|
|
// rather than a dependency between two repositories.
|
|
func TestWhatThisNodeSaysWhenItJoins(t *testing.T) {
|
|
path := os.Getenv("MESH_ENROL_OUT")
|
|
if path == "" {
|
|
t.Skip("set MESH_ENROL_OUT to write the enrolment request the mesh's suite reads")
|
|
}
|
|
|
|
// A real one. Generated the way enrolment generates them rather than typed as literals, so a
|
|
// key that stopped being a key would be caught here rather than travelling.
|
|
mine, err := identity.Generate("workstation")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
overlay, err := identity.GenerateOverlayKey()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sealing, err := identity.GenerateSealingKey()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
request := EnrolRequest{
|
|
Node: "workstation",
|
|
Secret: "a-one-time-secret",
|
|
PublicKey: mine.Public,
|
|
OverlayKey: overlay.Public,
|
|
SealingKey: sealing.Public,
|
|
Profile: map[string]any{"seat": true},
|
|
}
|
|
body, err := json.MarshalIndent(request, "", " ")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(path, append(body, '\n'), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The private half of the sealing key goes beside it, so the mesh's suite can prove what it
|
|
// sealed is openable rather than merely present.
|
|
if err := os.WriteFile(path+".sealing-private", []byte(sealing.Private), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Logf("wrote %s", path)
|
|
}
|