From c7e892ca63b367d066facede2c02776e2b15f824 Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Tue, 20 Oct 2026 22:59:36 +0000 Subject: [PATCH] Mark the build modules moved, so a machine assigned them composes before the forge serves their entry (issue 1537) --- modules/mesh-build-go/README.md | 5 +++++ modules/mesh-build-go/cmd/mesh-build-go/forge_test.go | 11 +++++++++++ modules/mesh-build-go/module.json | 1 + modules/mesh-build-node/README.md | 3 ++- .../mesh-build-node/cmd/mesh-build-node/forge_test.go | 11 +++++++++++ modules/mesh-build-node/module.json | 1 + 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/modules/mesh-build-go/README.md b/modules/mesh-build-go/README.md index 61433b7e..f523a1e5 100644 --- a/modules/mesh-build-go/README.md +++ b/modules/mesh-build-go/README.md @@ -35,6 +35,11 @@ with `GOTOOLCHAIN=local`, `GOFLAGS=-mod=mod` and the module's cache directory. E environment built from scratch (`StepRunner`): `PATH`, `HOME` and what the step passes. Workspaces older than a day are removed. +The account's ssh files (`files/forge`, `files/known_hosts`, `files/gitconfig`) are filled on the node by the +provisioner's client from the module's entry of `forge-account` (the manifest says `moved`, ADR 0466 §4, ADR 0400 §5). +The forge writes that entry only once the module has run and reported its key (ADR 0400 §2), so until then the client +says it waits and the files are not written: a fetch cannot reach the forge before them (issue 1537). + ## Test `build_go_test {workspace, level, packages?}` runs the tests of a fetched workspace by Go's convention, one level at a diff --git a/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go b/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go index b4e1d4b1..27a0cc76 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/forge_test.go @@ -23,6 +23,7 @@ const ( ) type forgeManifest struct { + Moved bool `json:"moved"` Requires []any `json:"requires"` State []any `json:"state"` Resources []map[string]any `json:"resources"` @@ -44,6 +45,16 @@ func readForgeManifest(t *testing.T) forgeManifest { return m } +// The forge files are filled on the node by the provisioner's client, never by the controller (ADR 0466 §4, ADR 0400 +// §5, issue 1537): the forge serves a module's entry only after the module has run and reported its key (ADR 0400 +// §2), so a controller filling them would refuse the machine until then, and the module could never run. +func TestTheForgeFilesAreFilledOnTheNodeSoTheModuleCanRunBeforeItsEntry(t *testing.T) { + if !readForgeManifest(t).Moved { + t.Errorf("%s's manifest does not say \"moved\": true, so the controller fills its forge files and refuses "+ + "every machine it is assigned to until the forge serves an entry it makes only after the module ran", forgeModule) + } +} + func forgeTemplate(t *testing.T, r map[string]any) string { t.Helper() name, _ := r["template"].(string) diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index 85944415..bb7f65de 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -1,6 +1,7 @@ { "module": "mesh-build-go", "version": "1", + "moved": true, "runs-as": "mesh-build-go", "capabilities": [ "package-manager", diff --git a/modules/mesh-build-node/README.md b/modules/mesh-build-node/README.md index 19c16e8e..9442105b 100644 --- a/modules/mesh-build-node/README.md +++ b/modules/mesh-build-node/README.md @@ -4,7 +4,8 @@ Design 47, release R4c-3 (novox/hq ADR 0405, ADR 0466 §1, ADR 0469 §1 and §4) TypeScript code on a build machine, as an account of its own (`runs-as`, no login shell, home at mode 0700), with the packages it declares (`nodejs`, `npm`, `git`, `openssh`) and the capability `user-namespaces`. The bundle is Go (`cmd/mesh-build-node`). It claims no seat: it is assigned to the build machines (ADR 0469 §6) and runs dark until the -builder uses it. Its forge key and ssh files are the same as mesh-build-go's (issue 1484). +builder uses it. Its forge key and ssh files are the same as mesh-build-go's (issue 1484), filled on the node by the +provisioner's client (issue 1537). ## The recipe diff --git a/modules/mesh-build-node/cmd/mesh-build-node/forge_test.go b/modules/mesh-build-node/cmd/mesh-build-node/forge_test.go index 55d0a83f..030e223d 100644 --- a/modules/mesh-build-node/cmd/mesh-build-node/forge_test.go +++ b/modules/mesh-build-node/cmd/mesh-build-node/forge_test.go @@ -24,6 +24,7 @@ const ( ) type forgeManifest struct { + Moved bool `json:"moved"` Requires []any `json:"requires"` State []any `json:"state"` Resources []map[string]any `json:"resources"` @@ -45,6 +46,16 @@ func readForgeManifest(t *testing.T) forgeManifest { return m } +// The forge files are filled on the node by the provisioner's client, never by the controller (ADR 0466 §4, ADR 0400 +// §5, issue 1537): the forge serves a module's entry only after the module has run and reported its key (ADR 0400 +// §2), so a controller filling them would refuse the machine until then, and the module could never run. +func TestTheForgeFilesAreFilledOnTheNodeSoTheModuleCanRunBeforeItsEntry(t *testing.T) { + if !readForgeManifest(t).Moved { + t.Errorf("%s's manifest does not say \"moved\": true, so the controller fills its forge files and refuses "+ + "every machine it is assigned to until the forge serves an entry it makes only after the module ran", forgeModule) + } +} + func forgeTemplate(t *testing.T, r map[string]any) string { t.Helper() name, _ := r["template"].(string) diff --git a/modules/mesh-build-node/module.json b/modules/mesh-build-node/module.json index 812f7a0e..6c06d5e2 100644 --- a/modules/mesh-build-node/module.json +++ b/modules/mesh-build-node/module.json @@ -1,6 +1,7 @@ { "module": "mesh-build-node", "version": "1", + "moved": true, "runs-as": "mesh-build-node", "capabilities": [ "package-manager",