Merge pull request 'A catalogue check parses every manifest as the nodes do; mesh-provisioner holds a refused manifest alone (issue 774)' (#567) from fix/one-bad-item-holds-one-module into main
Reviewed-on: #567
This commit was merged in pull request #567.
This commit is contained in:
@@ -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
|
||||||
@@ -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=
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -3,7 +3,7 @@ module mesh-provisioner
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
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
|
github.com/nats-io/nats.go v1.54.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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.20261030182415-754edfae6924 h1:aIiKj066gYFEDokUOq0i2n4vsygu5g0XMKJRRaMI4fM=
|
||||||
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/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 h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
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=
|
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||||
|
|||||||
Reference in New Issue
Block a user