From faaa6d3df23ab7c35ceb07ad85441f067a8d864a Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 19:27:03 +0100 Subject: [PATCH 1/2] Judge every manifest as the nodes read it in the catalogue's own check, so a manifest they refuse never reaches main (issue 774) ca8d6f33 gave power's bar item attributes its bar places by none of; ParseManifest refuses that, and at 19:13 on 2026-10-30 every node-engine refused to compose. No check of #565 parsed the manifest: that judgement was mesh-controller's `module check`, run over every manifest by the old merge gate, and since the checker moved to mesh-delivery it runs this repository's Go tests and the composition, where no test parsed a manifest whole. Quick fix: a row refusing node-bar block attributes other than bar, place and order. Thorough fix: checks/manifests parses every modules/*/module.json with mesh-sdk's ParseManifestWith against predefined.json and its templates beside it, then CatalogueProblems, IdentityProblems and DataProblems over the shelf, the functions the nodes and registration use. Chose thorough: it refuses every kind of manifest the nodes refuse, not this attribute alone. It fails at 7e905a66 naming power's item 2 and passes at 0695ae25. --- checks/manifests/go.mod | 5 +++ checks/manifests/go.sum | 2 ++ checks/manifests/main.go | 61 ++++++++++++++++++++++++++++++++++ checks/manifests/main_test.go | 51 ++++++++++++++++++++++++++++ checks/manifests/reads-outside | 4 +++ 5 files changed, 123 insertions(+) create mode 100644 checks/manifests/go.mod create mode 100644 checks/manifests/go.sum create mode 100644 checks/manifests/main.go create mode 100644 checks/manifests/main_test.go create mode 100644 checks/manifests/reads-outside diff --git a/checks/manifests/go.mod b/checks/manifests/go.mod new file mode 100644 index 00000000..6fbb4f39 --- /dev/null +++ b/checks/manifests/go.mod @@ -0,0 +1,5 @@ +module checks/manifests + +go 1.26.0 + +require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030181247-4c1384faefa0 diff --git a/checks/manifests/go.sum b/checks/manifests/go.sum new file mode 100644 index 00000000..fc5109a2 --- /dev/null +++ b/checks/manifests/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030181247-4c1384faefa0 h1:t04baH2Xz/NUsOEV3ctKY59XjiY5WmEuststvH+XeOs= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030181247-4c1384faefa0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= diff --git a/checks/manifests/main.go b/checks/manifests/main.go new file mode 100644 index 00000000..9658b260 --- /dev/null +++ b/checks/manifests/main.go @@ -0,0 +1,61 @@ +// Package manifests judges every module's manifest as the node-engine reads it, and the catalogue as one shelf: each +// modules/*/module.json through mesh-sdk's ParseManifestWith against the predefined.json at the root, with its templates +// read from the tree beside it (WithTemplatesFrom), then the rules between manifests (CatalogueProblems, +// IdentityProblems, DataProblems). +// +// Why it is here (issue 774): on 2026-10-30 mesh-catalog ca8d6f33 gave power's bar item two attributes its bar places +// by none of. ParseManifest refuses that, and every node-engine refused to compose at 19:13; no check of the pull +// request had parsed the manifest. That judgement was mesh-controller's `module check`, which the merge gate ran over +// every manifest before the checker moved to mesh-delivery; the checker runs this repository's Go tests and the +// composition, and no test parsed a manifest whole. This one does, in the same functions the nodes use. +package manifests + +import ( + "fmt" + "os" + "path/filepath" + "sort" + + "git.novox.be/novox/mesh-sdk/go/catalogue" +) + +// Problems is what is wrong with the manifests under root/modules, one line each: a manifest the mesh refuses, named by +// its path, then the rules between the manifests that parse. +func Problems(root string) ([]string, error) { + files, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json")) + if err != nil { + return nil, err + } + sort.Strings(files) + list, err := catalogue.ReadPredefined(root) + if err != nil { + return nil, err + } + var out []string + shelf := catalogue.Shelf{} + for _, f := range files { + raw, err := os.ReadFile(f) + if err != nil { + return nil, err + } + rel, _ := filepath.Rel(root, f) + m, err := catalogue.ParseManifestWith(raw, list) + if err == nil { + m, err = catalogue.WithTemplatesFrom(m, filepath.Dir(f)) + } + if err != nil { + out = append(out, fmt.Sprintf("%s: %v", rel, err)) + continue + } + if _, twice := shelf[m.Module]; twice { + out = append(out, fmt.Sprintf("%s: %s was already given; two manifests name one module", rel, m.Module)) + continue + } + shelf[m.Module] = m + } + between := catalogue.CatalogueProblems(shelf) + between = append(between, catalogue.IdentityProblems(shelf, catalogue.DefaultLongestMachine)...) + between = append(between, catalogue.DataProblems(shelf)...) + sort.Strings(between) + return append(out, between...), nil +} diff --git a/checks/manifests/main_test.go b/checks/manifests/main_test.go new file mode 100644 index 00000000..49ba2ff6 --- /dev/null +++ b/checks/manifests/main_test.go @@ -0,0 +1,51 @@ +package manifests + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +// Every manifest of the catalogue is one the nodes can use, and the catalogue holds together as one shelf. A row is a +// manifest written into a catalogue of its own: power's bar item as mesh-catalog ca8d6f33 gave it (issue 774) is +// refused naming the attribute, and the same item without it passes. +func TestEveryManifestIsOneTheNodesCanUse(t *testing.T) { + for _, row := range []struct { + name, attributes, refused string + }{ + {name: "the bar places by bar and place", attributes: `"bar":"bottom","place":"status","order":"45"`}, + {name: "an attribute the bar places by none of (ca8d6f33)", + attributes: `"bar":"bottom","place":"status","order":"45","shows":"state","state":"power.draw"`, + refused: `"shows" is none of them`}, + } { + root := t.TempDir() + dir := filepath.Join(root, "modules", "bar-user") + if err := os.MkdirAll(filepath.Join(dir, "files"), 0o755); err != nil { + t.Fatal(err) + } + manifest := `{"module":"bar-user","version":"1","moved":true,` + + `"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]},` + + `"items":[{"collection":"contribution:node-bar:block","attributes":{` + row.attributes + `},"template":"files/bar"}]}` + for path, body := range map[string]string{"module.json": manifest, "files/bar": "{\"shows\":\"command\"}\n"} { + if err := os.WriteFile(filepath.Join(dir, path), []byte(body), 0o644); err != nil { + t.Fatal(err) + } + } + got, err := Problems(root) + if err != nil { + t.Fatal(err) + } + joined := strings.Join(got, "\n") + if (row.refused == "") != (len(got) == 0) || !strings.Contains(joined, row.refused) { + t.Errorf("%s: refused %q, want %q", row.name, joined, row.refused) + } + } + real, err := Problems(filepath.Join("..", "..")) + if err != nil { + t.Fatal(err) + } + if len(real) != 0 { + t.Fatalf("the catalogue holds manifests the nodes cannot use:\n%s", strings.Join(real, "\n")) + } +} diff --git a/checks/manifests/reads-outside b/checks/manifests/reads-outside new file mode 100644 index 00000000..e0af3e80 --- /dev/null +++ b/checks/manifests/reads-outside @@ -0,0 +1,4 @@ +# What these tests read outside their package, as paths from the repository's root (issue 1936). +# every module's directory (its manifest and the templates beside it), and the list of predefined keys. +modules +predefined.json From b4b22aac20609f897813f7cc396cf93c58074a92 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 19:27:56 +0100 Subject: [PATCH 2/2] Pin mesh-provisioner to mesh-sdk 754edfae, so a manifest the mesh refuses holds that module alone in its plans (issue 774) PlansHeld reads the same frombus input that refused every node on 2026-10-30 at 19:13; at 754edfae it holds the module whose manifest the mesh refuses, with why, and composes every other module's plan. Quick and thorough fix are the SDK's (one rule in frombus input); this is the pin. --- modules/mesh-provisioner/go.mod | 2 +- modules/mesh-provisioner/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mesh-provisioner/go.mod b/modules/mesh-provisioner/go.mod index 27360793..cd62bdbe 100644 --- a/modules/mesh-provisioner/go.mod +++ b/modules/mesh-provisioner/go.mod @@ -3,7 +3,7 @@ module mesh-provisioner go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030174137-a37181261c24 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030182415-754edfae6924 github.com/nats-io/nats.go v1.54.0 ) diff --git a/modules/mesh-provisioner/go.sum b/modules/mesh-provisioner/go.sum index 61230834..11d9d45e 100644 --- a/modules/mesh-provisioner/go.sum +++ b/modules/mesh-provisioner/go.sum @@ -1,5 +1,5 @@ -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030174137-a37181261c24 h1:s0XXZtR7CFPBbnaDygWnE4/Q827iEFt0YfEzujk4Q9g= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030174137-a37181261c24/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030182415-754edfae6924 h1:aIiKj066gYFEDokUOq0i2n4vsygu5g0XMKJRRaMI4fM= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030182415-754edfae6924/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=