Require node-tools in the three build modules, so the delivery plan puts the tool runner they pull asks through before them on every node (issue 1911)

This commit is contained in:
2026-10-23 16:50:03 +02:00
parent a1febd3ad8
commit a493c90c0d
9 changed files with 43 additions and 9 deletions
@@ -144,8 +144,9 @@ func TestForgeFilesRenderFromTheBoundValuesInTheModulesOwnHome(t *testing.T) {
func TestManifestRequiresForgeAccountKeepsKeysAndTakesFilesFromTemplates(t *testing.T) {
m := readForgeManifest(t)
// artifact-store: the module pushes a done build's archive itself (ADR 0498 §2).
if len(m.Requires) != 3 || m.Requires[0] != "forge-account" || m.Requires[1] != "go-toolchain" || m.Requires[2] != "artifact-store" {
t.Errorf("requires = %v, want [forge-account go-toolchain artifact-store]", m.Requires)
// node-tools: the module pulls its asks through the tool runner's seat pull (1911).
if len(m.Requires) != 4 || m.Requires[0] != "forge-account" || m.Requires[1] != "go-toolchain" || m.Requires[2] != "artifact-store" || m.Requires[3] != "node-tools" {
t.Errorf("requires = %v, want [forge-account go-toolchain artifact-store node-tools]", m.Requires)
}
keeps := false
for _, s := range m.State {
@@ -176,3 +176,12 @@ func TestTheModuleRequiresTheArtifactStoreAndIsToldItsAddress(t *testing.T) {
t.Errorf("files/registry is %q (%v), want the store seat's reach", raw, err)
}
}
// 1911: the module pulls its asks through node-tools' seat pull (mesh-tools, R4g), so it requires node-tools on its node
// and the delivery plan puts node-tools first: a node's build module never pulls through a tool runner that cannot.
func TestTheModuleRequiresNodeToolsItPullsThrough(t *testing.T) {
m := readManifest(t)
if !slices.Contains(m.Requires, "node-tools") {
t.Errorf("requires %v lack node-tools", m.Requires)
}
}
+2 -1
View File
@@ -51,7 +51,8 @@
"requires": [
"forge-account",
"go-toolchain",
"artifact-store"
"artifact-store",
"node-tools"
],
"own-secrets": {
"broker": "${dir:state}/broker"
@@ -50,10 +50,11 @@ func TestTheModuleComposesWhereItsFilesAreHandedToTheProvisionersClient(t *testi
"buildah": read("buildah"),
"forge": {Module: "forge", Version: "1", Provides: []catalogue.Offer{{Name: "forge-account"}}},
"store": {Module: "store", Version: "1", Provides: []catalogue.Offer{{Name: "artifact-store"}}},
"runner": {Module: "runner", Version: "1", Provides: []catalogue.Offer{{Name: "node-tools"}}}, // node-tools, which the module pulls its asks through (1911)
}
node := catalogue.Node{Name: "builder", Site: "house",
Capabilities: map[string]bool{"package-manager": true, "user-namespaces": true}}
r, err := catalogue.Resolve(shelf, []string{"forge", "store", "buildah", "mesh-build-image"}, node, catalogue.World{})
r, err := catalogue.Resolve(shelf, []string{"forge", "store", "runner", "buildah", "mesh-build-image"}, node, catalogue.World{})
if err != nil {
t.Fatal(err)
}
@@ -144,7 +144,7 @@ func TestForgeFilesRenderFromTheBoundValuesInTheModulesOwnHome(t *testing.T) {
// template in the files/ archive (novox/hq ADR 0349 §2).
func TestManifestRequiresForgeAccountKeepsKeysAndTakesFilesFromTemplates(t *testing.T) {
m := readForgeManifest(t)
if want := []any{"forge-account", "rootless-image-build", "artifact-store"}; !reflect.DeepEqual(m.Requires, want) {
if want := []any{"forge-account", "rootless-image-build", "artifact-store", "node-tools"}; !reflect.DeepEqual(m.Requires, want) {
t.Errorf("requires = %v, want %v", m.Requires, want)
}
keeps := false
@@ -163,6 +163,8 @@ func TestACompositionWithoutBuildahIsRefusedNamingItAndWithBuildahComposes(t *te
shelf := map[string]catalogue.Manifest{
"forge": {Module: "forge", Version: "1", Provides: []catalogue.Offer{{Name: "forge-account"}}},
"store": {Module: "store", Version: "1", Provides: []catalogue.Offer{{Name: "artifact-store"}}},
// node-tools, the tool runner the module pulls its asks through (1911), stood in for as the others are.
"runner": {Module: "runner", Version: "1", Provides: []catalogue.Offer{{Name: "node-tools"}}},
}
for _, name := range []string{"mesh-build-image", "buildah", "docker"} {
m, err := catalogue.ReadTreeManifest(catalogueRoot, filepath.Join(catalogueRoot, "modules", name))
@@ -173,7 +175,7 @@ func TestACompositionWithoutBuildahIsRefusedNamingItAndWithBuildahComposes(t *te
}
node := catalogue.Node{Name: "builder", Site: "house",
Capabilities: map[string]bool{"package-manager": true, "user-namespaces": true}}
_, err := catalogue.Resolve(shelf, []string{"forge", "store", "docker", "mesh-build-image"}, node, catalogue.World{})
_, err := catalogue.Resolve(shelf, []string{"forge", "store", "runner", "docker", "mesh-build-image"}, node, catalogue.World{})
if err == nil {
t.Fatal("mesh-build-image composed on a machine without buildah (docker does not stand in for it)")
}
@@ -182,7 +184,16 @@ func TestACompositionWithoutBuildahIsRefusedNamingItAndWithBuildahComposes(t *te
t.Errorf("the refusal does not say %q:\n%v", want, err)
}
}
if _, err := catalogue.Resolve(shelf, []string{"forge", "store", "buildah", "mesh-build-image"}, node, catalogue.World{}); err != nil {
if _, err := catalogue.Resolve(shelf, []string{"forge", "store", "runner", "buildah", "mesh-build-image"}, node, catalogue.World{}); err != nil {
t.Errorf("with buildah assigned the composition is refused: %v", err)
}
}
// 1911: the module pulls its asks through node-tools' seat pull (mesh-tools, R4g), so it requires node-tools on its node
// and the delivery plan puts node-tools first: a node's build module never pulls through a tool runner that cannot.
func TestTheModuleRequiresNodeToolsItPullsThrough(t *testing.T) {
m := readManifest(t)
if !slices.Contains(m.Requires, "node-tools") {
t.Errorf("requires %v lack node-tools", m.Requires)
}
}
+2 -1
View File
@@ -39,7 +39,8 @@
"requires": [
"forge-account",
"rootless-image-build",
"artifact-store"
"artifact-store",
"node-tools"
],
"own-secrets": {
"broker": "${dir:state}/broker"
@@ -239,3 +239,12 @@ func TestTheModuleContributesWriteAccessToThePackageRegistry(t *testing.T) {
t.Errorf("npm-package-registry access = %v, want write", got)
}
}
// 1911: the module pulls its asks through node-tools' seat pull (mesh-tools, R4g), so it requires node-tools on its node
// and the delivery plan puts node-tools first: a node's build module never pulls through a tool runner that cannot.
func TestTheModuleRequiresNodeToolsItPullsThrough(t *testing.T) {
m := readManifest(t)
if !slices.Contains(m.Requires, "node-tools") {
t.Errorf("requires %v lack node-tools", m.Requires)
}
}
+2 -1
View File
@@ -50,7 +50,8 @@
"forge-account",
"npm-package-registry",
"node-toolchain",
"artifact-store"
"artifact-store",
"node-tools"
],
"contributes": {
"npm-package-registry": {