From f85dbb0713ddbc6a456dde3638e83e3ae379b65c Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 1 Sep 2026 21:17:59 +0200 Subject: [PATCH] The registry is added, not built MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A mesh that has just bootstrapped cannot build the module that gives it an artifact store: building publishes to the store, and the builder will not start without one (novox/hq 04-ISSUES/029). This test built it and passed, because the scenario's registry was already standing to receive the push — which is precisely why a real first mesh would have hit this and the lab never did. A stand-in for Docker Hub was quietly also standing in for the thing under test. So the module now names its image by digest, the way the bundle names the three a first node starts from, and is added as a manifest rather than built. That is the only path open to a real first mesh, so it is the path this walks. Its skip on MESH_LAB_BUILDER goes with it. Nothing in the test needs a builder any more, and a skip that names a thing the test does not use sends the next person to look in the wrong place. --- test/integration/mesh.test.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/integration/mesh.test.ts b/test/integration/mesh.test.ts index 82539a9..a593edb 100644 --- a/test/integration/mesh.test.ts +++ b/test/integration/mesh.test.ts @@ -586,30 +586,34 @@ test("a machine that fell behind catches up without being named", { skip, timeou assert.match(await mesh("push --behind"), /every machine is doing what it was told/); }); -test("the mesh runs its own artifact store", { - skip: skip || (!builder ? "set MESH_LAB_BUILDER to a built mesh-builder" : false), - timeout: 900_000, -}, async () => { +test("the mesh runs its own artifact store", { skip, timeout: 900_000 }, async () => { // Artifacts go to a registry, and the only registries that existed were raised by the lab or by // the bootstrap bundle. A mesh had no way to run its own. // - // Chicken and egg, resolved the way the bootstrap's is: the scenario's registry serves the image - // the module mirrors, and the module then runs a registry of the mesh's own. + // **Named, not mirrored** (novox/hq 04-ISSUES/029). Mirroring publishes to the artifact store, + // and the builder will not start without one — so a module that provides the store and builds + // its own image asks the mesh to put an artifact into the thing that artifact is needed to + // create. It worked here only because the scenario's registry was already standing to receive + // the push, which is exactly why a real first mesh would have found this and the lab did not. + // + // So the image is named by digest, the way the bundle names the three a first node starts from. + // A registry is the one module that cannot be delivered by the mesh's own delivery. await must("anchor", `mkdir -p /root/registry && printf %s '{"module":"registry","version":"1",` + `"provides":[{"name":"artifact-store","scope":"mesh"}],` + `"capabilities":["container-runtime"],` + `"claims":[{"name":"the-artifact-store","scope":"node"}],` + `"serves":{"artifact-store":{"port":5000}},` + - `"build":{"artifacts":[{"name":"registry","kind":"upstream","from":"${pinned("registry")}"}]},` + `"resources":[` + `{"id":"state","type":"directory","path":"/var/lib/mesh/registry","mode":"0700"},` + - `{"id":"store","type":"container","name":"mesh-registry","artifact":"registry",` + + `{"id":"store","type":"container","name":"mesh-registry","image":"${pinned("registry")}",` + `"ports":["5000:5000"],"volumes":["mesh-registry-data:/var/lib/registry"]}]}' ` + `> /root/registry/module.json`); - await must("anchor", `cd /root/registry && git init -q . && git add -A && ` + - `git -c user.email=lab -c user.name=lab commit -qm registry`); - - await mesh("build /root/registry --wait 300s", 420_000); + // **Added, not built** — and this is the half that proves the fix. Building needs a builder, + // and a builder will not start without an artifact store to publish to, so a mesh that has just + // bootstrapped cannot build the module that gives it one. Adding the manifest directly is the + // path a real first mesh has to take, so it is the path this walks. + await must("anchor", `docker cp /root/registry/module.json mesh-control:/registry.json`); + await mesh("module add /registry.json"); await mesh("assign anchor registry"); await mesh("push anchor"); await new Promise((r) => setTimeout(r, 12_000));