Files
mesh-host/internal/bootstrap/control_test.go
T
jschoubben f534cf8b42 bootstrap: the rest of the pivot — enrol, registry, publish, reinstall, retire
Steps 6 to 10, which turn a substrate into a mesh that can maintain itself
(novox/hq ADR 0067).

 6 enrol      a node record, a token, `mesh-host enrol`, and the host agent
              running. Proved by the mesh having HEARD from the node, not by a
              process existing: a host that cannot reach the broker looks exactly
              like a successful install until the first push applies nothing.
 7 registry   the module that gives this mesh an image store, registered from a
              --catalog checkout, assigned and pushed. Its image is upstream and
              never built (04-ISSUES/029) — a placeholder digest there is refused.
              Verified by asking `/v2/`, because a container that is up is not a
              registry that serves.
 8 publish    the carried image pushed into that registry, which assigns it the
              first manifest digest it has ever had. This is the hinge: without
              it the mesh works and can never upgrade itself.
 9 control    the control plane registered as an ordinary module pinned to that
              digest, with the substrate's own store connections delivered
              through `secret accept` — read out of the bundle that made them,
              because the mesh cannot invent a credential that predates it.
10 retire     the temporary control plane dropped from the bundle and removed by
              the host's ordinary removal pass.

Every step asks before it acts and reports "already done". No step leaves the
machine without a control plane: steps 9 and 10 overlap deliberately, and two
stateless control planes are untidy rather than broken.

mesh-control's `internal/builder`.PublishImage is mirrored rather than imported —
tier 0 depends on nothing that must be installed first — with one correction: the
digest is chosen from RepoDigests by repository instead of taken as element zero,
so an image pushed to two registries cannot silently pin this mesh to the wrong
one.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-10 23:59:57 +02:00

214 lines
9.2 KiB
Go

package bootstrap
import (
"context"
"strings"
"testing"
"time"
)
// Step 9 is where the control plane stops being a special case. These tests defend the two things
// that could go wrong quietly: pinning it to the wrong image, and delivering it store connections
// the mesh invented rather than the ones the substrate actually made.
// theControlPlaneModule is the shape this installer codes against: one container using the
// catalogue's placeholder-digest convention, with each store connection delivered as a sealed
// secret written into a file and MESH_STORE_<CONTEXT>_FILE pointing at it.
const theControlPlaneModule = `{
"module": "mesh-control",
"version": "1",
"capabilities": ["container-runtime"],
"own-secrets": {
"inventory-store": "/var/lib/mesh/control/inventory",
"identity-store": "/var/lib/mesh/control/identity",
"licences-store": "/var/lib/mesh/control/licences"
},
"resources": [
{"id": "state", "type": "directory", "path": "/var/lib/mesh/control", "mode": "0700"},
{"id": "container", "type": "container", "name": "mesh-control",
"image": "mesh-control@` + placeholderDigest + `",
"network": "host", "args": ["serve"],
"env": {
"MESH_STORE_INVENTORY_FILE": "/var/lib/mesh/control/inventory",
"MESH_STORE_IDENTITY_FILE": "/var/lib/mesh/control/identity",
"MESH_STORE_LICENCES_FILE": "/var/lib/mesh/control/licences"
}}
]
}`
const pushedReference = "127.0.0.1:5000/mesh-control@sha256:" +
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
// **The whole reference moves, not only the digest.** The manifest's placeholder names a
// repository too, and replacing sixty-four zeros inside it would leave `mesh-control@sha256:…`
// with no registry in front — which a runtime would go to the internet for, and this mesh's
// control plane exists in no public registry by design.
func TestTheControlPlaneIsPinnedToWhatThisMeshsRegistryAssigned(t *testing.T) {
pinned, places, err := pinImage([]byte(theControlPlaneModule), pushedReference)
if err != nil {
t.Fatal(err)
}
if places != 1 {
t.Errorf("the placeholder was found in %d place(s)", places)
}
if !strings.Contains(string(pinned), `"image": "`+pushedReference+`"`) {
t.Errorf("the manifest does not name the pushed image:\n%s", pinned)
}
if strings.Contains(string(pinned), `"mesh-control@sha256:`) {
t.Errorf("the digest was replaced and the manifest's own repository name was left in "+
"front of it, so nothing says which registry serves it:\n%s", pinned)
}
}
// A manifest already naming a real digest was pinned by somebody else, to some other build.
// Registering it would install a control plane that is not the image this machine just published,
// which is the one thing this step exists to guarantee.
func TestAManifestAlreadyPinnedByHandIsRefused(t *testing.T) {
already := strings.Replace(theControlPlaneModule, placeholderDigest,
"sha256:"+strings.Repeat("9", 64), 1)
if _, _, err := pinImage([]byte(already), pushedReference); err == nil {
t.Fatal("a manifest already pinned to some other image was accepted")
}
}
// Every placeholder moves. A manifest naming its image in a second resource — a runtime container
// beside the application's, which the catalogue's converted modules routinely carry — would
// otherwise be left half pinned, and fail inside an apply rather than here.
func TestEveryPlaceTheManifestNamesTheImageIsPinned(t *testing.T) {
twice := strings.Replace(theControlPlaneModule,
`{"id": "state", "type": "directory", "path": "/var/lib/mesh/control", "mode": "0700"},`,
`{"id": "state", "type": "directory", "path": "/var/lib/mesh/control", "mode": "0700"},
{"id": "migrate", "type": "container", "name": "mesh-control-migrate", "run-once": true,
"image": "mesh-control@`+placeholderDigest+`", "args": ["migrate"]},`, 1)
pinned, places, err := pinImage([]byte(twice), pushedReference)
if err != nil {
t.Fatal(err)
}
if places != 2 {
t.Errorf("the placeholder was found in %d place(s), and the manifest names it twice", places)
}
if strings.Contains(string(pinned), placeholderDigest) {
t.Error("a placeholder survived the pinning")
}
}
// **The connections are the substrate's, and they are read out of the bundle that made them.**
// The mesh cannot invent them: they are the credentials the substrate created the databases with,
// and thirty-two random bytes in their place would leave the control plane unable to open a single
// context. The pairing is read from the manifest so that whatever the catalogue calls these
// secrets is what is delivered.
func TestTheStoreConnectionsComeFromTheBundleThatMadeThem(t *testing.T) {
wanted, err := storeSecretsIn([]byte(theControlPlaneModule))
if err != nil {
t.Fatal(err)
}
for context, secret := range map[string]string{
"INVENTORY": "inventory-store",
"IDENTITY": "identity-store",
"LICENCES": "licences-store",
} {
if wanted[context] != secret {
t.Errorf("the %s store's connection would be accepted as %q, want %q",
context, wanted[context], secret)
}
}
// And the values are the substrate's own, taken from the produced bundle rather than composed.
rewritten, err := Rewrite(theRealBundle(t), held)
if err != nil {
t.Fatal(err)
}
runtime := &asked{answer: aMeshThatAgrees(nil)}
control := controlPlane{container: "temp-mesh-control", run: runtime.run, timeout: time.Second}
delivered, err := deliverStores(context.Background(), Options{Node: "anchor"}, control,
[]byte(theControlPlaneModule), rewritten.Declaration, func(string) {})
if err != nil {
t.Fatal(err)
}
if len(delivered) != 3 {
t.Fatalf("%d connections were delivered, and the mesh holds three contexts: %v",
len(delivered), delivered)
}
for _, secret := range delivered {
if !runtime.ran("secret accept anchor mesh-control " + secret + " --from") {
t.Errorf("%s was not accepted through `secret accept`: %v", secret, runtime.commands)
}
}
}
// A manifest whose container reads a file no own-secret writes is refused. The mesh would seal
// nothing there and the control plane would find an empty file where a connection string has to
// be — which presents as a control plane that will not start, three steps from the cause.
func TestAConnectionFileNothingWritesIsRefused(t *testing.T) {
mismatched := strings.Replace(theControlPlaneModule,
`"inventory-store": "/var/lib/mesh/control/inventory"`,
`"inventory-store": "/var/lib/mesh/control/somewhere-else"`, 1)
_, err := storeSecretsIn([]byte(mismatched))
if err == nil {
t.Fatal("a manifest whose two ends do not meet was accepted")
}
if !strings.Contains(err.Error(), "own-secret") {
t.Errorf("the refusal does not say which half is missing: %v", err)
}
}
// A manifest asking for no store connections at all describes a control plane that can open
// nothing, and the refusal says what shape the installer delivers into — because the manifest is
// written in another repository and this is where the two have to agree.
func TestAManifestWantingNoStoresIsRefusedWithTheShapeItShouldHave(t *testing.T) {
rewritten, err := Rewrite(theRealBundle(t), held)
if err != nil {
t.Fatal(err)
}
runtime := &asked{answer: aMeshThatAgrees(nil)}
control := controlPlane{container: "temp-mesh-control", run: runtime.run, timeout: time.Second}
bare := `{"module":"mesh-control","version":"1","resources":[
{"id":"container","type":"container","name":"mesh-control",
"image":"mesh-control@` + placeholderDigest + `"}]}`
_, err = deliverStores(context.Background(), Options{Node: "anchor"}, control,
[]byte(bare), rewritten.Declaration, func(string) {})
if err == nil {
t.Fatal("a control plane that can open nothing was accepted")
}
if !strings.Contains(err.Error(), storeVariablePrefix+"<CONTEXT>"+storeFileSuffix) {
t.Errorf("the refusal does not say what shape is expected: %v", err)
}
}
// The permanent control plane is asked a question, not merely looked at — the same question the
// temporary one was asked at step 5, and for the same reason: `status` opens all three stores, so
// a reply proves the sealed connections it was given are the ones the substrate made.
func TestThePermanentControlPlaneIsAskedTheSameQuestion(t *testing.T) {
runtime := &asked{answer: aMeshThatAgrees(map[string]string{
"module list": "",
"exec mesh-control /mesh-control": "1 node, 0 waiting\n",
})}
control := controlPlane{container: "temp-mesh-control", run: runtime.run, timeout: time.Second}
rewritten, err := Rewrite(theRealBundle(t), held)
if err != nil {
t.Fatal(err)
}
out, err := InstallControlPlane(context.Background(),
installing(t, catalogueWith(t, ControlPlaneModule, theControlPlaneModule)),
Deps{Run: runtime.run}, control, rewritten.Declaration, pushedReference, func(string) {})
if err != nil {
t.Fatal(err)
}
if out.Answered != "1 node, 0 waiting" {
t.Errorf("the permanent control plane's reply is reported as %q", out.Answered)
}
if !runtime.ran("docker exec mesh-control " + controlPlaneBinary + " status") {
t.Errorf("the permanent control plane was never asked anything: %v", runtime.commands)
}
// And the module was registered with the digest, not with the placeholder.
if !runtime.ran("module add /mesh-control-module.json") {
t.Errorf("the module was never registered: %v", runtime.commands)
}
}