From 0697b2994efedf6528fc6f08f372ec3829898c6a Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 2 Nov 2026 19:23:26 +0100 Subject: [PATCH] =?UTF-8?q?Tests=20of=20the=20build=20module=20follow=20th?= =?UTF-8?q?e=20composition's=20move:=20mesh-build-image=20tests=20its=20ow?= =?UTF-8?q?n=20files,=20and=20sdkjudge=20lists=20what=20mesh-sdk=20still?= =?UTF-8?q?=20holds=20(ADR=200593=20=C2=A77)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mesh-build-image's two tests that composed with catalogue.Resolve (gone with the composition) now hold the module's own facts: its registry file is the placement and no file binds the store; it requires rootless-image-build, which buildah provides and docker does not. What only proved composition is listed in .work/sdk1/proofs-for-node-engine.md. sdkjudge's composition list drops the six refusals that left mesh-sdk. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- checks/sdkjudge/main.go | 8 +- .../cmd/mesh-build-image/compose_test.go | 82 ++++++------------- .../cmd/mesh-build-image/manifest_test.go | 37 +++------ 3 files changed, 39 insertions(+), 88 deletions(-) diff --git a/checks/sdkjudge/main.go b/checks/sdkjudge/main.go index ac7bc0c9..eea7e734 100644 --- a/checks/sdkjudge/main.go +++ b/checks/sdkjudge/main.go @@ -36,13 +36,7 @@ import ( // composition is every function or table the check lets stay in mesh-sdk, as "path-from-go/:name", and why. It names no // manifest judgement: each is the composer's refusal of composition itself (ADR 0578 clause 5). var composition = map[string]string{ - "catalogue/consumers.go:consumersPlaceholderProblems": "composition: rendering a consumer's template", - "catalogue/collections.go:collectedPlaceholderProblems": "composition: placeholders a contribution renders", - "catalogue/environment_into.go:placeholderProblems": "composition: placeholders a contribution renders", - "catalogue/seat_contributions.go:seatPlaceholderProblems": "composition: placeholders a contribution renders", - "catalogue/collections.go:itemTemplateProblem": "composition: filling an item's template", - "catalogue/setting_takes.go:takenSettingsProblems": "composition: whether stored settings still compose", - "catalogue/template.go:HeldTemplateProblem": "composition: the take-in refusal of a resolved build", + "catalogue/collections.go:itemTemplateProblem": "composition: filling an item's template", } // Problems is what mesh-sdk's Go tree under root (its go/ directory) holds of a manifest judge, one line each, but for diff --git a/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go b/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go index 984a7231..7acb4454 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/compose_test.go @@ -5,69 +5,37 @@ import ( "path/filepath" "strings" "testing" - - "git.novox.be/novox/mesh-sdk/go/catalogue" ) // Issue 1703 (the live failure of the first assignment): the module is moved, so the provisioner's client on the node -// fills its templates, and it fills only config, secrets, collections, placement and what a moved provider told it. -// The registry's address therefore cannot be a ${bound:artifact-store:...} (the artifact store has not moved): it is the -// placement ${seat:mesh-artifact-store:reach}, the form the container runtime's daemon.json uses. This composes the -// module on a machine with buildah and the artifact store reachable, handing its files to the client as a node does. -func TestTheModuleComposesWhereItsFilesAreHandedToTheProvisionersClient(t *testing.T) { - built := func(m catalogue.Manifest) []catalogue.Built { - texts := map[string]string{} - entries, err := os.ReadDir(filepath.Join(moduleDir, "files")) +// fills its templates, and it fills only config, secrets, collections, placement and what a moved provider told it. The +// registry's address therefore cannot be a ${bound:artifact-store:...} (the artifact store has not moved): it is the +// placement ${seat:mesh-artifact-store:reach}, the form the container runtime's daemon.json uses. The module's own part +// of that is what this holds: its registry file is that placement and none of its files or its manifest binds the store. +// That a node composes it is the node-engine's composition test (.work/sdk1/proofs-for-node-engine.md). +func TestTheRegistryIsThePlacementAndNoFileBindsTheStore(t *testing.T) { + raw, err := os.ReadFile(filepath.Join(moduleDir, "files", "registry")) + if err != nil { + t.Fatal(err) + } + if got := strings.TrimSpace(string(raw)); got != "${seat:mesh-artifact-store:reach}" { + t.Errorf("the registry file is %q, want the placement ${seat:mesh-artifact-store:reach}", got) + } + files := []string{filepath.Join(moduleDir, "module.json")} + entries, err := os.ReadDir(filepath.Join(moduleDir, "files")) + if err != nil { + t.Fatal(err) + } + for _, e := range entries { + files = append(files, filepath.Join(moduleDir, "files", e.Name())) + } + for _, f := range files { + body, err := os.ReadFile(f) if err != nil { t.Fatal(err) } - for _, e := range entries { - raw, err := os.ReadFile(filepath.Join(moduleDir, "files", e.Name())) - if err != nil { - t.Fatal(err) - } - texts[e.Name()] = string(raw) + if strings.Contains(string(body), "${bound:artifact-store") { + t.Errorf("%s binds the artifact store, which has not moved: a moved module's client cannot fill it", f) } - return []catalogue.Built{ - {Name: "tools", Kind: "bundle", Reference: catalogue.ArtifactStoreScheme + "mesh-build-image/tools/blobs/sha256:" + strings.Repeat("a", 64), Digest: "sha256:" + strings.Repeat("a", 64)}, - {Name: "files", Kind: "archive", Reference: catalogue.ArtifactStoreScheme + "mesh-build-image/files/blobs/sha256:" + strings.Repeat("b", 64), Digest: "sha256:" + strings.Repeat("b", 64), Texts: texts}, - } - } - read := func(name string) catalogue.Manifest { - return decodeTree(t, filepath.Join(catalogueRoot, "modules", name)) - } - image := read("mesh-build-image") - resolved, err := image.Resolve(built(image)) - if err != nil { - t.Fatal(err) - } - shelf := map[string]catalogue.Manifest{ - "mesh-build-image": resolved, - "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", "runner", "buildah", "mesh-build-image"}, node, catalogue.World{}) - if err != nil { - t.Fatal(err) - } - r.Account = "op" - // What the resolution states for the node: the forge's provider has moved, the artifact store's has not. - r.Needs = []catalogue.Needed{ - {Name: "forge-account", For: "mesh-build-image", Module: "forge", From: "novox", At: "10.7.0.1", ProviderMoved: true, - Serves: map[string]any{"known_host": "[novox.internal]:222 ssh-ed25519 AAAA", "host_key": "ssh-ed25519 AAAA", "ssh_host": "novox.internal", "ssh_alias": "mesh-forge", "ssh_port": "222", "ssh_base": "ssh://git@novox.internal:222/", "https_base": "https://git.novox.be/"}}, - {Name: "artifact-store", For: "mesh-build-image", Module: "store", From: "novox", At: "10.7.0.1", Serves: map[string]any{"port": "5000"}}, - } - with := catalogue.Rendering{Hands: true, Provisioner: "mesh-provisioner-client", ArtifactStore: "store:5000", - Needed: map[string]map[string]string{"mesh-build-image": {"broker": "sealed-to-the-node"}}} - c, err := r.Compose(with) - if err != nil { - t.Fatalf("the module does not compose on a machine with buildah and the artifact store: %v", err) - } - if _, asked := c.Plans["mesh-build-image"].Placement["seat:mesh-artifact-store:reach"]; !asked { - t.Errorf("the plan's placement %v does not ask where the registry is reached", c.Plans["mesh-build-image"].Placement) } } diff --git a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go index fa6ce173..f826d2b9 100644 --- a/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go +++ b/modules/mesh-build-image/cmd/mesh-build-image/manifest_test.go @@ -183,33 +183,22 @@ func TestGiteaReadsTheImageBuildModulesKeys(t *testing.T) { } } -// 1704b: over the real manifests, mesh-build-image where no module provides rootless-image-build is refused, the error -// naming the provision, the module that wants it and the module to assign (buildah); with buildah it composes. The -// forge and the registry, which other modules provide for the whole mesh, are stood in for. -func TestACompositionWithoutBuildahIsRefusedNamingItAndWithBuildahComposes(t *testing.T) { - 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"}}}, +// 1704b: the module requires rootless-image-build, which buildah provides and docker does not. That a composition without +// buildah is refused naming both is the node-engine's composition test (.work/sdk1/proofs-for-node-engine.md). +func TestTheModuleRequiresRootlessImageBuildAndBuildahProvidesIt(t *testing.T) { + if m := readManifest(t); !slices.Contains(m.Requires, "rootless-image-build") { + t.Errorf("requires %v lack rootless-image-build", m.Requires) } - for _, name := range []string{"mesh-build-image", "buildah", "docker"} { - m := decodeTree(t, filepath.Join(catalogueRoot, "modules", name)) - shelf[m.Module] = m - } - node := catalogue.Node{Name: "builder", Site: "house", - Capabilities: map[string]bool{"package-manager": true, "user-namespaces": true}} - _, 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)") - } - for _, want := range []string{`"rootless-image-build" is wanted by mesh-build-image`, "buildah"} { - if !strings.Contains(err.Error(), want) { - t.Errorf("the refusal does not say %q:\n%v", want, err) + provides := func(name string) bool { + for _, o := range decodeTree(t, filepath.Join(catalogueRoot, "modules", name)).Provides { + if o.Name == "rootless-image-build" { + return true + } } + return false } - 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) + if !provides("buildah") || provides("docker") { + t.Errorf("buildah provides it: %v, docker provides it: %v; want true and false", provides("buildah"), provides("docker")) } }