From ae6f7d5b5445eb18ac965cbd7eec28031d80af10 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 03:43:49 +0200 Subject: [PATCH 01/12] Make a missing trunk copy a failure again, now the checker places it (issue 1295) --- checks/paths/main.go | 3 ++- checks/trunk/trunk.go | 32 ++++++++++++++------------------ checks/trunk/trunk_test.go | 28 ++++++++++++++-------------- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/checks/paths/main.go b/checks/paths/main.go index 122b7aa2..8c4c9b3d 100644 --- a/checks/paths/main.go +++ b/checks/paths/main.go @@ -251,7 +251,8 @@ func main() { } var grown []string if baseDir == "" { - fmt.Println("NOT COMPARED: no base branch's lists were given, so additions to them were not judged") + fmt.Fprintln(os.Stderr, "NOT COMPARED: no base branch's lists were given (-base ), so additions to them were not judged; that is a failure, not a pass (issue 1295)") + os.Exit(2) } else { baseShared, _, err1 := list(filepath.Join(baseDir, "shared")) baseKnown, _, err2 := list(filepath.Join(baseDir, "known")) diff --git a/checks/trunk/trunk.go b/checks/trunk/trunk.go index e3bc86f3..1c4b0da4 100644 --- a/checks/trunk/trunk.go +++ b/checks/trunk/trunk.go @@ -3,14 +3,14 @@ // // The checker fetches the change's own repository at its base commit beside the change, as it fetches a sibling, and says where // in MESH_CHECK_BESIDE; the copy is under the repository's name (the same convention the other repositories' tests use). With -// MESH_CHECK_BESIDE unset, or set without the catalogue's copy in it, the comparison is skipped and the test says NOT COMPARED -// WITH THE TRUNK, naming why: the checker that runs before R4g's delivery places siblings but not the change's own repository, -// so R4g's own check cannot hold the copy (issue 1295 notes that a missing copy becomes a failure once that checker is gone). A trunk that holds no such file had +// MESH_CHECK_BESIDE unset, or set without the catalogue's copy in it, the test fails saying NOT COMPARED WITH THE TRUNK and +// why: the checker places the change's own repository since R4g (issue 1295), so a missing copy is a fault, never a pass. A trunk that holds no such file had // none: the list's first copy, which nothing was added to. package trunk import ( "errors" + "fmt" "os" "path/filepath" "testing" @@ -23,13 +23,11 @@ const Repository = "mesh-catalog" const BesideEnv = "MESH_CHECK_BESIDE" // Copy is the trunk's copy of the file at rel (a path from the catalogue's root), written to a file of the test's own: its path, -// and whether the trunk holds one (false: its first copy). It skips the test, saying so, when no copy of the catalogue is beside. +// and whether the trunk holds one (false: its first copy). It fails the test when no copy of the catalogue is beside. func Copy(t testing.TB, rel string) (string, bool) { t.Helper() - raw, found, skip, err := Read(rel) + raw, found, err := Read(rel) switch { - case skip != "": - t.Skip(skip) case err != nil: t.Fatal(err) case !found: @@ -43,27 +41,25 @@ func Copy(t testing.TB, rel string) (string, bool) { return path, true } -// Read is the trunk's copy of rel and whether the trunk holds one. skip is the words to skip the comparison with, when no trunk is -// named; err is a trunk named and not there, or unreadable. -func Read(rel string) (content []byte, found bool, skip string, err error) { +// Read is the trunk's copy of rel and whether the trunk holds one. err is a trunk not beside the check (MESH_CHECK_BESIDE unset, +// or without the catalogue's directory), or a copy unreadable: a comparison that cannot be made is never a pass. +func Read(rel string) (content []byte, found bool, err error) { beside := os.Getenv(BesideEnv) if beside == "" { - return nil, false, "NOT COMPARED WITH THE TRUNK: " + BesideEnv + " is not set, so the trunk's copy of " + rel + - " is not beside this run; the checker places it", nil + return nil, false, fmt.Errorf("NOT COMPARED WITH THE TRUNK: %s is not set, so the trunk's copy of %s is not beside this run; the checker places the change's own repository there (issue 1295)", BesideEnv, rel) } dir := filepath.Join(beside, Repository) if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { - return nil, false, "NOT COMPARED WITH THE TRUNK: " + Repository + " is not beside this check in " + BesideEnv + "=" + beside + - ", so " + rel + " is not judged against the trunk's copy (the checker before R4g places no copy of the change's own repository)", nil + return nil, false, fmt.Errorf("NOT COMPARED WITH THE TRUNK: %s is not beside this check in %s=%s, so %s is not judged against the trunk's copy; the checker places the change's own repository there at its trunk (issue 1295)", Repository, BesideEnv, beside, rel) } else if err != nil { - return nil, false, "", err + return nil, false, err } raw, err := os.ReadFile(filepath.Join(dir, rel)) if errors.Is(err, os.ErrNotExist) { - return nil, false, "", nil + return nil, false, nil } if err != nil { - return nil, false, "", err + return nil, false, err } - return raw, true, "", nil + return raw, true, nil } diff --git a/checks/trunk/trunk_test.go b/checks/trunk/trunk_test.go index d8283f4d..aa0ace00 100644 --- a/checks/trunk/trunk_test.go +++ b/checks/trunk/trunk_test.go @@ -17,27 +17,27 @@ func TestTheCloneBesideTheCheckIsTheTrunk(t *testing.T) { t.Fatal(err) } t.Setenv(BesideEnv, beside) - raw, found, skip, err := Read("checks/x/known") - if err != nil || skip != "" || !found || string(raw) != "a\nb\n" { - t.Fatalf("read %q found %v skip %q err %v", raw, found, skip, err) + raw, found, err := Read("checks/x/known") + if err != nil || !found || string(raw) != "a\nb\n" { + t.Fatalf("read %q found %v err %v", raw, found, err) } - if _, found, skip, err := Read("checks/x/absent"); err != nil || skip != "" || found { - t.Fatalf("a file the trunk does not hold: found %v skip %q err %v; wanted its first copy", found, skip, err) + if _, found, err := Read("checks/x/absent"); err != nil || found { + t.Fatalf("a file the trunk does not hold: found %v err %v; wanted its first copy", found, err) } } -func TestWithNothingBesideTheComparisonIsSkippedAndSaidNotMade(t *testing.T) { +func TestWithNothingBesideTheComparisonFailsAndSaysNotMade(t *testing.T) { t.Setenv(BesideEnv, "") - _, found, skip, err := Read("checks/x/known") - if found || err != nil || len(skip) < 12 || skip[:12] != "NOT COMPARED" { - t.Fatalf("found %v, skip %q, err %v; wanted NOT COMPARED", found, skip, err) + _, found, err := Read("checks/x/known") + if found || err == nil || !strings.Contains(err.Error(), "NOT COMPARED") { + t.Fatalf("found %v, err %v; wanted a failure saying NOT COMPARED", found, err) } } -func TestACloneBesideWithoutTheCatalogueIsSkippedAndSaidNotMade(t *testing.T) { - t.Setenv(BesideEnv, t.TempDir()) // the siblings are there, the catalogue's own base is not (the checker before R4g) - _, found, skip, err := Read("checks/x/known") - if found || err != nil || len(skip) < 12 || skip[:12] != "NOT COMPARED" || !strings.Contains(skip, "not beside") { - t.Fatalf("found %v, skip %q, err %v; wanted NOT COMPARED naming the missing copy", found, skip, err) +func TestACloneBesideWithoutTheCatalogueFailsAndSaysNotMade(t *testing.T) { + t.Setenv(BesideEnv, t.TempDir()) // the siblings are there, the catalogue's own base is not + _, found, err := Read("checks/x/known") + if found || err == nil || !strings.Contains(err.Error(), "NOT COMPARED") || !strings.Contains(err.Error(), "not beside") { + t.Fatalf("found %v, err %v; wanted a failure naming the missing copy", found, err) } } From b6ed8599c8e210cb17781490081396fb762b2bf4 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 03:46:45 +0200 Subject: [PATCH 02/12] mesh-build-go: a package marked reads-outside is never kept, so tests that read files outside their directory run on every check (issue 1935) --- modules/mesh-build-go/README.md | 6 +++- .../mesh-build-go/cmd/mesh-build-go/digest.go | 28 +++++++++++++++++++ .../cmd/mesh-build-go/digest_test.go | 25 +++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/modules/mesh-build-go/README.md b/modules/mesh-build-go/README.md index f2493e35..e466c36b 100644 --- a/modules/mesh-build-go/README.md +++ b/modules/mesh-build-go/README.md @@ -102,7 +102,11 @@ integration level, the postgres major and the nats-server version; and, when the workspace (`beside`), each one's repository and commit, which the answer echoes as `beside` (the checker keeps a verdict only for the siblings it was judged with). The text's form is `DigestVersion` 3. The Go version is not in it: the toolchain enters a fingerprint once, as the version the build nodes agree on (ADR 0477 §3), and the standard library's packages are that -version's. A package with no tests at the level has no digest and is named in `without_tests`. A directory that vendors +version's. A package with no tests at the level has no digest and is named in `without_tests`. A package whose directory holds a file named `reads-outside` (any content; say what the tests read) is never kept (issue 1935): its tests read +files outside it, which a digest from `go list` cannot name, so its digest is a fresh random one on every call, the ask finds no kept +verdict for it and runs it, and the answer names it in `reads_outside` and the module's log says why. The checker still writes a +verdict under that digest, which nothing ever reads again. The marker is the plain way to say it until each verdict keeps the files +its tests opened (Go's test log). A directory that vendors is listed and tested from its vendor directory (`-mod=vendor`). ## A change to this module is judged by its candidate diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest.go b/modules/mesh-build-go/cmd/mesh-build-go/digest.go index 1c92d318..1525f119 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest.go @@ -7,6 +7,7 @@ package main import ( "bytes" "context" + "crypto/rand" "crypto/sha256" "encoding/hex" "encoding/json" @@ -30,6 +31,13 @@ const DigestVersion = "4" // depends on the siblings' commits. const besideVariable = "MESH_CHECK_BESIDE" +// ReadsOutsideMarker is the name of a file in a package's directory that says its tests read files outside it (a +// repository's documents, a sibling directory): such a package is never kept (issue 1935). The digest hashes only what +// the Go toolchain lists, so it cannot name what a test opens elsewhere; a marker file, beside the Go files where a +// reader of the package sees it, is the plain way to say so until the checker keeps the files a test opened (the Go +// test log) with each verdict. +const ReadsOutsideMarker = "reads-outside" + // integrationTags are the build tags of the integration level, its run and its digest alike: integration, and isolation // for the bubblewrap proofs (mesh-sdk's and the build modules'), which a build node can run. var integrationTags = []string{"integration", "isolation"} @@ -89,6 +97,9 @@ type DigestResult struct { // only when they are the siblings it gave the fetch. Beside []string `json:"beside,omitempty"` WithoutTests []string `json:"without_tests,omitempty"` + // ReadsOutside names the packages that carry the marker: each has a digest that no kept verdict can have (a fresh + // random one), so the check runs it every time. + ReadsOutside []string `json:"reads_outside,omitempty"` // JudgedBy is the program that ran the digest (ADR 0535 §5): "installed", or "candidate " under the // runner workspace. JudgedBy string `json:"judged_by,omitempty"` @@ -199,6 +210,12 @@ func (m *Module) digestHere(ctx context.Context, workspace, level string) (Diges } } sort.Strings(res.WithoutTests) + sort.Strings(res.ReadsOutside) + for _, p := range res.ReadsOutside { + if m.Say != nil { + m.Say("the %s level of %s always runs: its directory carries %s, so its tests read files outside it that no digest names", level, p, ReadsOutsideMarker) + } + } return res, nil } @@ -256,6 +273,17 @@ func digestModule(res *DigestResult, pkgs map[string]*goPackage, tree string, he if testMain == nil { return fmt.Errorf("go list gave no test binary for %s", path) } + if _, err := os.Stat(filepath.Join(root.Dir, ReadsOutsideMarker)); err == nil { + // The digest of a package that reads outside itself is one nothing can have kept: the key is a fresh random + // hex, so the ask finds no kept verdict and runs it, and what the checker writes under it is never read again. + var nonce [32]byte + if _, err := rand.Read(nonce[:]); err != nil { + return err + } + res.Packages[path] = hex.EncodeToString(nonce[:]) + res.ReadsOutside = append(res.ReadsOutside, path) + continue + } d, err := packageDigest(root, testMain, pkgs, tree, header, beside) if err != nil { return fmt.Errorf("%s: %w", path, err) diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go index 5e2d81d0..2cee4acc 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go @@ -189,3 +189,28 @@ func TestAModuleOutsideTheTreeCountsByVersionAndChecksum(t *testing.T) { t.Errorf("a new version left the digest as it was") } } + +// Issue 1935: a package whose directory carries the reads-outside marker is never kept: its digest is one no kept verdict +// can have (it differs on every call, though nothing changed), and the answer names it. A package without the marker +// keeps its digest. +func TestAPackageWithTheReadsOutsideMarkerIsNeverKept(t *testing.T) { + t.Parallel() + m, tree := digestFixture(t) + plain := digests(t, m, "unit") + if len(plain.ReadsOutside) != 0 { + t.Fatalf("a package carries the marker in the fixture: %v", plain.ReadsOutside) + } + edit(t, tree, "c/"+ReadsOutsideMarker, "the tests read ../docs\n") + first, second := digests(t, m, "unit"), digests(t, m, "unit") + c := "fixture/digest/c" + if len(first.Packages[c]) != 64 || first.Packages[c] == second.Packages[c] || first.Packages[c] == plain.Packages[c] { + t.Errorf("c carries the marker and its digest is stable: %s, %s, before %s", first.Packages[c], second.Packages[c], plain.Packages[c]) + } + if strings.Join(first.ReadsOutside, ",") != c { + t.Errorf("the answer does not name the package that reads outside: %v", first.ReadsOutside) + } + a := "fixture/digest/a" + if first.Packages[a] != plain.Packages[a] || first.Packages[a] != second.Packages[a] { + t.Errorf("a has no marker and its digest moved: %s, %s, before %s", first.Packages[a], second.Packages[a], plain.Packages[a]) + } +} From a715c8821fbcdacfb9b0da5b5a4f0d360dd0e35e Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 03:59:08 +0200 Subject: [PATCH 03/12] mesh-build-go: a catalogue module's non-Go files enter its packages' digests; markers where tests read other modules (issue 1935) --- modules/mesh-build-go/README.md | 2 +- .../cmd/mesh-build-go/beside_digest_test.go | 2 +- .../mesh-build-go/cmd/mesh-build-go/digest.go | 47 ++++++++++++++++++- .../cmd/mesh-build-go/digest_test.go | 43 +++++++++++++++++ .../cmd/mesh-build-go/reads-outside | 1 + .../cmd/mesh-build-image/reads-outside | 1 + .../cmd/mesh-build-node/reads-outside | 1 + .../cmd/mesh-provisioner-client/reads-outside | 1 + modules/minio/cmd/object-store/reads-outside | 1 + .../cmd/postgres-provider/reads-outside | 1 + 10 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 modules/mesh-build-go/cmd/mesh-build-go/reads-outside create mode 100644 modules/mesh-build-image/cmd/mesh-build-image/reads-outside create mode 100644 modules/mesh-build-node/cmd/mesh-build-node/reads-outside create mode 100644 modules/mesh-provisioner-client/cmd/mesh-provisioner-client/reads-outside create mode 100644 modules/minio/cmd/object-store/reads-outside create mode 100644 modules/postgres/cmd/postgres-provider/reads-outside diff --git a/modules/mesh-build-go/README.md b/modules/mesh-build-go/README.md index e466c36b..7b2c14f3 100644 --- a/modules/mesh-build-go/README.md +++ b/modules/mesh-build-go/README.md @@ -102,7 +102,7 @@ integration level, the postgres major and the nats-server version; and, when the workspace (`beside`), each one's repository and commit, which the answer echoes as `beside` (the checker keeps a verdict only for the siblings it was judged with). The text's form is `DigestVersion` 3. The Go version is not in it: the toolchain enters a fingerprint once, as the version the build nodes agree on (ADR 0477 §3), and the standard library's packages are that -version's. A package with no tests at the level has no digest and is named in `without_tests`. A package whose directory holds a file named `reads-outside` (any content; say what the tests read) is never kept (issue 1935): its tests read +version's. A package with no tests at the level has no digest and is named in `without_tests`. A catalogue module's packages also hash the module's non-Go files (the nearest ancestor directory holding `module.json`: its manifest, README, `files/` and the rest, so `../../module.json` is covered; digest form 5). A package whose directory holds a file named `reads-outside` (any content; say what the tests read) is never kept (issue 1935): its tests read files outside it, which a digest from `go list` cannot name, so its digest is a fresh random one on every call, the ask finds no kept verdict for it and runs it, and the answer names it in `reads_outside` and the module's log says why. The checker still writes a verdict under that digest, which nothing ever reads again. The marker is the plain way to say it until each verdict keeps the files diff --git a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go index 3682a61b..22aebaca 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/beside_digest_test.go @@ -116,7 +116,7 @@ func TestTheIntegrationLevelDigestsUnderBothTags(t *testing.T) { t.Errorf("the integration digest listed %q", s.command) } } - if DigestVersion != "4" { + if DigestVersion != "5" { t.Errorf("the digest's form changed in kind and is still version %s", DigestVersion) } } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest.go b/modules/mesh-build-go/cmd/mesh-build-go/digest.go index 1525f119..bce625ba 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest.go @@ -25,7 +25,8 @@ import ( // 2: no Go version in the text; the toolchain enters a fingerprint as the agreed version (ADR 0477 §3). 3: the siblings' // commits (the lead's decision L5) and the integration level's tags integration,isolation (the checker's agreement). // 4: the siblings' commits enter only the digest of a package whose tests reach a file naming MESH_CHECK_BESIDE (ADR 0536 §1). -const DigestVersion = "4" +// 5: a catalogue module's non-Go files enter the digest of its packages (issue 1935). +const DigestVersion = "5" // besideVariable is the name a file bears when it reads where the siblings lie; a package whose tests reach such a file // depends on the siblings' commits. @@ -331,6 +332,15 @@ func packageDigest(root, testMain *goPackage, pkgs map[string]*goPackage, tree s } } } + // A catalogue module's tests read its manifest, its README and its files from the package's directory (../../module.json): + // every non-Go file of the module's directory is an input (issue 1935). The module is the nearest ancestor with a module.json. + if modDir := enclosingModule(tree, root.Dir); modDir != "" { + more, err := moduleFileLines(tree, root, modDir) + if err != nil { + return "", err + } + lines = append(lines, more...) + } data := filepath.Join(root.Dir, "testdata") if _, err := os.Stat(data); err == nil { err := filepath.WalkDir(data, func(path string, e fs.DirEntry, err error) error { @@ -356,6 +366,41 @@ func packageDigest(root, testMain *goPackage, pkgs map[string]*goPackage, tree s return hex.EncodeToString(h.Sum(nil)), nil } +// enclosingModule is the nearest ancestor of dir, inside tree, that holds a module.json, or "" when there is none. +func enclosingModule(tree, dir string) string { + tree = filepath.Clean(tree) + for d := filepath.Clean(dir); d != tree && strings.HasPrefix(d, tree+string(filepath.Separator)); d = filepath.Dir(d) { + if st, err := os.Stat(filepath.Join(d, "module.json")); err == nil && !st.IsDir() { + return d + } + } + return "" +} + +// moduleFileLines are the content lines of every file of a module's directory that is not Go source (Go source is the +// packages' own, listed by go list), skipping .git and node_modules. +func moduleFileLines(tree string, p *goPackage, modDir string) ([]string, error) { + var lines []string + err := filepath.WalkDir(modDir, func(path string, e fs.DirEntry, err error) error { + if err != nil { + return err + } + if e.IsDir() { + if n := e.Name(); n == ".git" || n == "node_modules" { + return filepath.SkipDir + } + return nil + } + if strings.HasSuffix(path, ".go") { + return nil + } + l, err := contentLine(tree, p, path) + lines = append(lines, l) + return err + }) + return lines, err +} + func fileLine(tree string, p *goPackage, name string) (string, error) { return contentLine(tree, p, filepath.Join(p.Dir, name)) } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go index 2cee4acc..9b6fd78c 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/digest_test.go @@ -214,3 +214,46 @@ func TestAPackageWithTheReadsOutsideMarkerIsNeverKept(t *testing.T) { t.Errorf("a has no marker and its digest moved: %s, %s, before %s", first.Packages[a], second.Packages[a], plain.Packages[a]) } } + +// Issue 1935: a catalogue module's packages read ../../module.json and the module's files: a change to them changes the +// digest of the module's package, and a change to another module's files does not. +func TestACatalogueModulesFilesChangeTheDigestOfItsPackagesOnly(t *testing.T) { + t.Parallel() + m, tree := digestFixture(t) + for _, mod := range []string{"mod1", "mod2"} { + dir := filepath.Join(tree, mod, "cmd", "p") + if err := os.MkdirAll(filepath.Join(tree, mod, "files"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + edit(t, tree, mod+"/module.json", `{"module":"`+mod+`"}`) + edit(t, tree, mod+"/README.md", "# "+mod+"\n") + edit(t, tree, mod+"/files/f.env", "A=1\n") + edit(t, tree, mod+"/cmd/p/p.go", "package p\n") + edit(t, tree, mod+"/cmd/p/p_test.go", "package p\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestReads(t *testing.T) {\n\tif _, err := os.ReadFile(\"../../module.json\"); err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n") + } + p1, p2 := "fixture/digest/mod1/cmd/p", "fixture/digest/mod2/cmd/p" + before := digests(t, m, "unit") + if len(before.Packages[p1]) != 64 || len(before.Packages[p2]) != 64 { + t.Fatalf("no digest for the module packages: %+v", before.Packages) + } + if before.Packages[p1] == before.Packages[p2] { + t.Errorf("two modules, one digest") + } + for _, file := range []string{"mod1/module.json", "mod1/README.md", "mod1/files/f.env"} { + edit(t, tree, file, "changed "+file+"\n") + after := digests(t, m, "unit") + if after.Packages[p1] == before.Packages[p1] { + t.Errorf("a change to %s did not change the module's digest", file) + } + if after.Packages[p2] != before.Packages[p2] { + t.Errorf("a change to %s changed the other module's digest", file) + } + before = after + } + if got := digests(t, m, "unit"); got.Packages["fixture/digest/c"] == "" { + t.Errorf("a package outside any module lost its digest") + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/reads-outside b/modules/mesh-build-go/cmd/mesh-build-go/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/mesh-build-go/cmd/mesh-build-go/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. diff --git a/modules/mesh-build-image/cmd/mesh-build-image/reads-outside b/modules/mesh-build-image/cmd/mesh-build-image/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/mesh-build-image/cmd/mesh-build-image/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. diff --git a/modules/mesh-build-node/cmd/mesh-build-node/reads-outside b/modules/mesh-build-node/cmd/mesh-build-node/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/mesh-build-node/cmd/mesh-build-node/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. diff --git a/modules/mesh-provisioner-client/cmd/mesh-provisioner-client/reads-outside b/modules/mesh-provisioner-client/cmd/mesh-provisioner-client/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/mesh-provisioner-client/cmd/mesh-provisioner-client/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. diff --git a/modules/minio/cmd/object-store/reads-outside b/modules/minio/cmd/object-store/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/minio/cmd/object-store/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. diff --git a/modules/postgres/cmd/postgres-provider/reads-outside b/modules/postgres/cmd/postgres-provider/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/postgres/cmd/postgres-provider/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. From 6a70735489dc5f1d72a4b4cd19f07025ce654b35 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 04:13:55 +0200 Subject: [PATCH 04/12] Run a compose ask on the Go build seat: build mesh-sdk's composer at the asked commit once, fill its manifests from the indexer and run it shut off (issue 1622) --- .../mesh-build-go/cmd/mesh-build-go/asks.go | 3 + .../cmd/mesh-build-go/compose.go | 210 ++++++++++++++++++ .../mesh-build-go/compose_integration_test.go | 156 +++++++++++++ .../cmd/mesh-build-go/compose_test.go | 125 +++++++++++ .../mesh-build-go/cmd/mesh-build-go/fetch.go | 6 +- .../mesh-build-go/cmd/mesh-build-go/main.go | 1 + .../mesh-build-go/cmd/mesh-build-go/module.go | 4 + modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 2 + modules/mesh-build-go/module.json | 3 +- 10 files changed, 509 insertions(+), 3 deletions(-) create mode 100644 modules/mesh-build-go/cmd/mesh-build-go/compose.go create mode 100644 modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go create mode 100644 modules/mesh-build-go/cmd/mesh-build-go/compose_test.go diff --git a/modules/mesh-build-go/cmd/mesh-build-go/asks.go b/modules/mesh-build-go/cmd/mesh-build-go/asks.go index dd516941..bb0713da 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/asks.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/asks.go @@ -100,6 +100,9 @@ func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep if err := m.room(); err != nil { return nil, err } + if a.Compose != nil { + return m.compose(ctx, ask.Fetch, a) + } return buildstep.RunAsk(ctx, ask, a) }} } diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose.go b/modules/mesh-build-go/cmd/mesh-build-go/compose.go new file mode 100644 index 00000000..c733a15a --- /dev/null +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose.go @@ -0,0 +1,210 @@ +package main + +// **A compose ask runs mesh-sdk's composer at a commit** (novox/hq ADR 0482 clause 4, issues 1621 and 1622): the +// assigner asks it, to compose a group with its mesh-sdk member's head, and to read the group's manifests with the +// mesh-sdk the running controller and node-engine pin (ADR 0482 clause 5, issue 1623). The module fetches the commit +// (its fetch step: the forge key and the network, none of the change's code), builds the composer package in the Go +// module the ask names, in a run step shut off with nothing fetched, and keeps the program under its key +// (delivery.ComposerKey), so each commit is built once on a node. It fills the request's manifests from the delivery +// indexer's manifests state, by digest, and runs the program shut off: no network, none of the account, the request a +// file of a workspace of its own. The answer is the composer's verdict whole (delivery.ComposeAnswer); the module +// judges nothing of it. + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + + "git.novox.be/novox/mesh-sdk/go/buildstep" + "git.novox.be/novox/mesh-sdk/go/composer" + "git.novox.be/novox/mesh-sdk/go/delivery" +) + +// ManifestsState is the delivery indexer's manifests by digest, which a compose ask's request names (the module reads +// it, module.json reads). +const ManifestsState = delivery.IndexerModule + ".manifests" + +// composerLocks hold one mutex per composer key, so a composer two asks need at once is built once. +var composerLocks sync.Map + +// composerPath is where the composer of key is kept: the cache directory, beside Go's own caches. +func (m *Module) composerPath(key string) string { + return filepath.Join(m.Cache, "composers", key, "mesh-compose") +} + +// compose runs a compose ask: the composer of its commit, built once, over its request with the manifests filled. +func (m *Module) compose(ctx context.Context, fetch buildstep.StepFunc, a delivery.StepAsk) (any, error) { + job := *a.Compose + repository, _ := job.Fetch["repository"].(string) + commit, _ := job.Fetch["commit"].(string) + installed, err := m.Probe(ctx) + if err != nil { + return nil, err + } + key := delivery.ComposerKey(repository, commit, job.Dir, job.Package, delivery.ToolchainUsed{Version: installed, Recipe: m.Recipe.Version()}) + exe, built, err := m.composerOf(ctx, fetch, job, key) + if err != nil { + return nil, err + } + req, err := composer.Decode(job.Request) + if err != nil { + return nil, buildstep.Refuse("the compose ask %s: %v", a.ID, err) + } + if err := composer.Fill(&req, m.manifestOf); err != nil { + return nil, err + } + verdict, err := m.runComposer(ctx, exe, req) + if err != nil { + return nil, err + } + return delivery.ComposeAnswer{Built: built, Key: key, Verdict: verdict}, nil +} + +// manifestOf is the manifest the indexer keeps under digest, as its repository holds it. +func (m *Module) manifestOf(digest string) ([]byte, error) { + if m.ReadManifest == nil { + return nil, errors.New("this module reads no manifests state") + } + key, err := delivery.ManifestsKey(digest) + if err != nil { + return nil, err + } + raw, err := m.ReadManifest(key) + if err != nil { + return nil, err + } + if raw == nil { + return nil, fmt.Errorf("the indexer keeps no manifest of digest %s", digest) + } + man, err := delivery.DecodeManifest(raw) + if err != nil { + return nil, err + } + return []byte(man.JSON), nil +} + +// composerOf is the composer kept under key, or, when none is, the one built now from the fetched commit (built true). +func (m *Module) composerOf(ctx context.Context, fetch buildstep.StepFunc, job delivery.ComposeJob, key string) (string, bool, error) { + exe := m.composerPath(key) + mu, _ := composerLocks.LoadOrStore(exe, &sync.Mutex{}) + mu.(*sync.Mutex).Lock() + defer mu.(*sync.Mutex).Unlock() + if st, err := os.Stat(exe); err == nil && st.Mode().IsRegular() { + return exe, false, nil + } + if fetch == nil { + return "", false, buildstep.Refuse("this build module fetches nothing") + } + out, err := fetch(ctx, job.Fetch) + if err != nil { + return "", false, err + } + raw, err := json.Marshal(out) + if err != nil { + return "", false, err + } + var f struct { + Workspace string `json:"workspace"` + } + if err := json.Unmarshal(raw, &f); err != nil || f.Workspace == "" { + return "", false, fmt.Errorf("the fetch answered no workspace: %s", raw) + } + defer m.releaseSaid(f.Workspace) + done := m.spaces().Hold(f.Workspace) + defer done() + dir := filepath.Join(m.Work, f.Workspace, "tree", job.Dir) + if _, err := os.Stat(filepath.Join(dir, "go.mod")); err != nil { + return "", false, fmt.Errorf("%s at %s holds no go.mod in %s, so no composer can be built there", job.Fetch["repository"], job.Fetch["commit"], job.Dir) + } + into := filepath.Join(m.Work, f.Workspace, "composer", "mesh-compose") + if err := os.MkdirAll(filepath.Dir(into), 0o700); err != nil { + return "", false, err + } + run, err := m.stepRunner(f.Workspace, false) + if err != nil { + return "", false, err + } + env := append(m.goEnvFor(dir), "GOPROXY=off", "GOTOOLCHAIN=local", "CGO_ENABLED=0") + r := run(ctx, env, "go", "-C", dir, "build", "-trimpath", "-o", into, job.Package) + if r.Status != 0 || r.Err != "" { + // The words Go says when the module holds no such package (a mesh-sdk from before the composer) are kept whole, + // so the asker tells that apart from a fault. + return "", false, fmt.Errorf("the composer %s does not build at %s: %s", job.Package, job.Fetch["commit"], compileError(r.Err+"\n"+r.Stderr+"\n"+r.Stdout)) + } + if err := copyExecutable(into, exe); err != nil { + return "", false, fmt.Errorf("the composer could not be kept: %w", err) + } + return exe, true, nil +} + +// copyExecutable copies a built program into place through a file beside it, so a half-written program is never kept. +func copyExecutable(from, to string) error { + if err := os.MkdirAll(filepath.Dir(to), 0o700); err != nil { + return err + } + src, err := os.Open(from) + if err != nil { + return err + } + defer src.Close() + tmp := to + ".new" + dst, err := os.OpenFile(tmp, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o700) + if err != nil { + return err + } + if _, err := io.Copy(dst, src); err != nil { + dst.Close() + return err + } + if err := dst.Close(); err != nil { + return err + } + return os.Rename(tmp, to) +} + +// releaseSaid removes a workspace once its steps ended, saying a failure: the sweep removes it later. +func (m *Module) releaseSaid(workspace string) { + if err := m.spaces().Release(workspace); err != nil && m.Say != nil { + m.Say("the compose ask's workspace %s: %v", workspace, err) + } +} + +// runComposer runs the composer over req in a workspace of its own, shut off, and answers its verdict: the last line of +// its standard output, a composer.Verdict of the version this module reads. +func (m *Module) runComposer(ctx context.Context, exe string, req composer.Request) (json.RawMessage, error) { + id := buildstep.NewID() + done := m.spaces().Hold(id) + defer m.releaseSaid(id) + defer done() + ws := filepath.Join(m.Work, id) + if err := os.MkdirAll(ws, 0o700); err != nil { + return nil, err + } + raw, err := json.Marshal(req) + if err != nil { + return nil, err + } + file := filepath.Join(ws, "request.json") + if err := os.WriteFile(file, raw, 0o600); err != nil { + return nil, err + } + run := m.Run + if !m.Inside { + iso := m.isolation(id, false) + iso.ReadOnly = append(iso.ReadOnly, exe) + run = buildstep.Isolated(m.Run, iso) + } + r := run(ctx, nil, exe, "-request", file) + line := strings.TrimSpace(lastLine(r.Stdout)) + var v composer.Verdict + if r.Status != 0 || r.Err != "" || json.Unmarshal([]byte(line), &v) != nil || v.V != composer.Version { + return nil, fmt.Errorf("the composer answered no verdict (status %d %s): %s", r.Status, r.Err, firstLine(r.Stderr+"\n"+r.Stdout)) + } + return json.RawMessage(line), nil +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go new file mode 100644 index 00000000..ad1fe4d0 --- /dev/null +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_integration_test.go @@ -0,0 +1,156 @@ +//go:build integration + +package main + +import ( + "context" + "encoding/json" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/nats-io/nats.go" + "github.com/nats-io/nats.go/jetstream" + + "git.novox.be/novox/mesh-sdk/go/buildstep" + "git.novox.be/novox/mesh-sdk/go/composer" + "git.novox.be/novox/mesh-sdk/go/delivery" + "git.novox.be/novox/mesh-sdk/go/forgekey" + "git.novox.be/novox/mesh-sdk/go/testbus" +) + +// sdkPin is the mesh-sdk version this module's go.mod requires: the composer the test builds is that version's. +func sdkPin(t *testing.T) string { + t.Helper() + raw, err := os.ReadFile("../../go.mod") + if err != nil { + t.Fatal(err) + } + for _, l := range strings.Split(string(raw), "\n") { + if f := strings.Fields(l); len(f) >= 2 && f[0] == "git.novox.be/novox/mesh-sdk/go" { + return f[1] + } + } + t.Fatal("go.mod requires no mesh-sdk") + return "" +} + +// goEnvOf is one value of this machine's go env. +func goEnvOf(t *testing.T, name string) string { + t.Helper() + out, err := exec.Command("go", "env", name).Output() + if err != nil { + t.Fatalf("go env %s: %v", name, err) + } + return strings.TrimSpace(string(out)) +} + +// 1622/AC1, AC3 against the real bus: a compose ask put on the Go build seat's check stream is pulled by the module +// started whole on that bus, which fetches the commit (here a tree of a module requiring mesh-sdk at this module's pin, +// as a reader repository is), builds mesh-sdk's composer there with nothing fetched, fills the request's manifests from +// the indexer's state and runs the composer; the step key . passes with the composer's verdict. A second +// ask of the same commit runs the kept composer: fetched and built once. +func TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus(t *testing.T) { + nc, err := nats.Connect(testbus.URL(t)) + if err != nil { + t.Fatal(err) + } + defer nc.Close() + js, err := jetstream.New(nc) + if err != nil { + t.Fatal(err) + } + ctx, stop := context.WithCancel(context.Background()) + defer stop() + if err := buildstep.DeclareAskWorkers(ctx, js, delivery.AskGo, 2*time.Minute); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = js.DeleteStream(context.Background(), "SEAT_NODE_BUILD_GO") }) + + states := newStates() + m := moduleWith(states, "go1.26.0") + m.Work, m.Cache, m.Inside = t.TempDir(), t.TempDir(), true + m.Run = StepRunner(t.TempDir()) + m.GoModCache = goEnvOf(t, "GOMODCACHE") // the module cache this module's own build filled, read and not fetched + run, gocache := m.Run, goEnvOf(t, "GOCACHE") // this machine's build cache, so the composer's packages compile once + m.Run = func(ctx context.Context, env []string, name string, args ...string) forgekey.Ran { + return run(ctx, append(env, "GOCACHE="+gocache), name, args...) + } + read, digests := indexerHolds(t, `{"module":"demo","version":"1"}`) + m.ReadManifest = read + + gosum, err := os.ReadFile("../../go.sum") + if err != nil { + t.Fatal(err) + } + fetches := 0 + steps := fakeSteps(new([]string)) + for i := range steps { + if steps[i].Name == "build_go_fetch" { + steps[i].Run = func(ctx context.Context, args map[string]any) (any, error) { + fetches++ + ws := buildstep.NewID() + tree := filepath.Join(m.Work, ws, "tree") + if err := os.MkdirAll(tree, 0o700); err != nil { + return nil, err + } + mod := "module reader\n\ngo 1.26.0\n\nrequire git.novox.be/novox/mesh-sdk/go " + sdkPin(t) + "\n" + if err := os.WriteFile(filepath.Join(tree, "go.mod"), []byte(mod), 0o600); err != nil { + return nil, err + } + return map[string]any{"workspace": ws}, os.WriteFile(filepath.Join(tree, "go.sum"), gosum, 0o600) + } + } + } + p := m.Puller(steps, &buildstep.JetStreamAsks{JS: js, Language: delivery.AskGo}) + p.PullWait = 200 * time.Millisecond + go p.Pull(ctx) + + ask := func() delivery.Step { + a := composeAskOf(t, digests[0]) + a.Compose.Fetch["repository"], a.Compose.Dir = "novox/mesh-controller", delivery.RootPath + raw, err := delivery.EncodeStepAsk(a) + if err != nil { + t.Fatal(err) + } + subject, _ := delivery.AskSubject(delivery.AskGo, delivery.AskCheck) + if _, err := js.Publish(ctx, subject, raw); err != nil { + t.Fatal(err) + } + key, _ := delivery.AskStepKey("ace", a.ID) + for deadline := time.Now().Add(90 * time.Second); time.Now().Before(deadline); time.Sleep(50 * time.Millisecond) { + states.mu.Lock() + v := states.steps[key] + states.mu.Unlock() + if len(v) > 0 && v[len(v)-1].State != delivery.StepRunning { + return v[len(v)-1] + } + } + t.Fatalf("the compose ask %s never ended", a.ID) + return delivery.Step{} + } + for n, wantBuilt := range []bool{true, false} { + step := ask() + if step.State != delivery.StepPassed { + t.Fatalf("ask %d: %s: %s", n+1, step.State, step.Reason) + } + var ans delivery.ComposeAnswer + var v composer.Verdict + if err := json.Unmarshal(step.Result, &ans); err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(ans.Verdict, &v); err != nil { + t.Fatal(err) + } + if ans.Built != wantBuilt || !strings.HasPrefix(ans.Key, "composer-") || len(v.Cases) != 1 || !v.Cases[0].Manifests["demo"].Accepted || + !strings.Contains(v.SDK, sdkPin(t)) { + t.Fatalf("ask %d: answer built %v key %s, verdict %+v; want built %v and demo accepted by mesh-sdk %s", n+1, ans.Built, ans.Key, v, wantBuilt, sdkPin(t)) + } + } + if fetches != 1 { + t.Errorf("two asks of one commit fetched %d times, want once", fetches) + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go new file mode 100644 index 00000000..14a70ea0 --- /dev/null +++ b/modules/mesh-build-go/cmd/mesh-build-go/compose_test.go @@ -0,0 +1,125 @@ +package main + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "slices" + "strings" + "testing" + "time" + + "git.novox.be/novox/mesh-sdk/go/buildstep" + "git.novox.be/novox/mesh-sdk/go/composer" + "git.novox.be/novox/mesh-sdk/go/delivery" +) + +const composeCommit = "4444444444444444444444444444444444444444" + +// indexerHolds is the delivery indexer's manifests state holding each body under its digest, as the indexer writes it. +func indexerHolds(t *testing.T, bodies ...string) (func(string) (json.RawMessage, error), []string) { + t.Helper() + kept, digests := map[string]json.RawMessage{}, []string{} + for _, b := range bodies { + d := delivery.ManifestDigest([]byte(b)) + key, _ := delivery.ManifestsKey(d) + raw, err := delivery.EncodeManifest(delivery.Manifest{Module: "demo", JSON: b}) + if err != nil { + t.Fatal(err) + } + kept[key], digests = raw, append(digests, d) + } + return func(key string) (json.RawMessage, error) { return kept[key], nil }, digests +} + +func composeAskOf(t *testing.T, digest string) delivery.StepAsk { + t.Helper() + req, _ := json.Marshal(composer.Request{V: composer.Version, Cases: []composer.Case{{Name: "change", + Manifests: map[string]composer.Manifest{"demo": {Digest: digest}}}}}) + return delivery.StepAsk{ID: buildstep.NewID(), Kind: delivery.AskCheck, Language: delivery.AskGo, Asker: "mesh-delivery-assigner", + At: time.Now(), Compose: &delivery.ComposeJob{Fetch: map[string]any{"repository": "novox/mesh-sdk", "commit": composeCommit}, + Dir: "go", Package: composer.Package, Request: req}} +} + +// composeModule is a module with work and cache directories of its own, running its commands as they are (Inside: a +// unit test has no bubblewrap to shut them off in). +func composeModule(t *testing.T) *Module { + t.Helper() + m := moduleWith(newStates(), "go1.26.0") + m.Work, m.Cache, m.Inside, m.Run = t.TempDir(), t.TempDir(), true, StepRunner(t.TempDir()) + return m +} + +// 1622/AC3: a composer kept under the ask's key is run again, nothing fetched or built: the answer says it was not +// built, names the key, and carries the composer's verdict whole; the request it read had its manifests filled from the +// indexer's state. +func TestAKeptComposerIsRunWithTheManifestsFilled(t *testing.T) { + m := composeModule(t) + read, digests := indexerHolds(t, `{"module":"demo","version":"1"}`) + m.ReadManifest = read + a := composeAskOf(t, digests[0]) + key := delivery.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, delivery.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) + exe := m.composerPath(key) + if err := os.MkdirAll(filepath.Dir(exe), 0o700); err != nil { + t.Fatal(err) + } + // A composer that answers which manifests its request held, filled or not, as a verdict. + script := "#!/bin/sh\n" + + `if grep -q '"digest"' "$2"; then echo '{"v":1,"sdk":"stand-in","cases":[{"name":"unfilled","manifests":{}}]}'; ` + + `else echo '{"v":1,"sdk":"stand-in","cases":[{"name":"change","manifests":{"demo":{"accepted":true}}}]}'; fi` + "\n" + if err := os.WriteFile(exe, []byte(script), 0o700); err != nil { + t.Fatal(err) + } + fetched := 0 + fetch := func(context.Context, map[string]any) (any, error) { fetched++; return nil, nil } + out, err := m.compose(context.Background(), fetch, a) + if err != nil { + t.Fatal(err) + } + ans := out.(delivery.ComposeAnswer) + var v composer.Verdict + if err := json.Unmarshal(ans.Verdict, &v); err != nil { + t.Fatal(err) + } + if ans.Built || ans.Key != key || fetched != 0 || len(v.Cases) != 1 || v.Cases[0].Name != "change" || !v.Cases[0].Manifests["demo"].Accepted { + t.Fatalf("answer = %+v (fetched %d), verdict %+v", ans, fetched, v) + } + if entries, _ := os.ReadDir(m.Work); len(entries) != 0 { + t.Errorf("the run's workspace was left: %v", entries) + } +} + +// 1622: a manifest the indexer does not keep fails the ask, naming its digest; a fetched commit with no go.mod where +// the ask builds fails it naming the directory, and its workspace is released. +func TestAComposeAskFailsLoudly(t *testing.T) { + m := composeModule(t) + m.ReadManifest, _ = indexerHolds(t) + a := composeAskOf(t, "feedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed") + key := delivery.ComposerKey("novox/mesh-sdk", composeCommit, "go", composer.Package, delivery.ToolchainUsed{Version: "go1.26.0", Recipe: m.Recipe.Version()}) + os.MkdirAll(filepath.Dir(m.composerPath(key)), 0o700) + os.WriteFile(m.composerPath(key), []byte("#!/bin/sh\nexit 0\n"), 0o700) + if _, err := m.compose(context.Background(), nil, a); err == nil || !strings.Contains(err.Error(), "feedfeed") { + t.Errorf("an unkept manifest: %v", err) + } + m2 := composeModule(t) + fetch := func(context.Context, map[string]any) (any, error) { + if err := os.MkdirAll(filepath.Join(m2.Work, "ws0000000000a", "tree", "go"), 0o700); err != nil { + return nil, err + } + return map[string]any{"workspace": "ws0000000000a"}, nil + } + if _, err := m2.compose(context.Background(), fetch, composeAskOf(t, "x")); err == nil || !strings.Contains(err.Error(), "no go.mod in go") { + t.Errorf("a commit with no go.mod: %v", err) + } + if entries, _ := os.ReadDir(m2.Work); len(entries) != 0 { + t.Errorf("the fetched workspace was left: %v", entries) + } +} + +// 1622: the module reads the delivery indexer's manifests, which a compose ask names by digest. +func TestTheModuleReadsTheIndexersManifests(t *testing.T) { + if m := readManifest(t); !slices.Contains(m.Reads, ManifestsState) { + t.Errorf("reads = %v, lacks %s", m.Reads, ManifestsState) + } +} diff --git a/modules/mesh-build-go/cmd/mesh-build-go/fetch.go b/modules/mesh-build-go/cmd/mesh-build-go/fetch.go index e5a1b49b..6dc0e424 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/fetch.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/fetch.go @@ -288,10 +288,14 @@ func inTestdata(path string) bool { // git, through the account's rewrite of the forge's address to ssh), and nothing that asks a question. For a directory // that vendors, see goEnvFor. func (m *Module) goEnv() []string { + modcache := filepath.Join(m.Cache, "gomod") + if m.GoModCache != "" { + modcache = m.GoModCache + } return []string{ "GOTOOLCHAIN=local", "GOFLAGS=-mod=mod", - "GOMODCACHE=" + filepath.Join(m.Cache, "gomod"), + "GOMODCACHE=" + modcache, "GOCACHE=" + filepath.Join(m.Cache, "gobuild"), "GOPRIVATE=git.novox.be", "GIT_TERMINAL_PROMPT=0", diff --git a/modules/mesh-build-go/cmd/mesh-build-go/main.go b/modules/mesh-build-go/cmd/mesh-build-go/main.go index 3becd9d0..d9e0da20 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/main.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/main.go @@ -54,6 +54,7 @@ func main() { m.RegistryFile = m.Home + "/registry" m.Settings = m.Home + "/settings.json" m.ReadKept = readOf(stdio.State(KeptState)).Get + m.ReadManifest = readOf(stdio.State(ManifestsState)).Get m.Probe = ProbeGo(m.Home, m.Cache) m.Bubblewrap = ProbeBubblewrap // Outside a launch by the runtime — a build, a check — there is no node and no state to write. diff --git a/modules/mesh-build-go/cmd/mesh-build-go/module.go b/modules/mesh-build-go/cmd/mesh-build-go/module.go index 3db6e3fb..48903962 100644 --- a/modules/mesh-build-go/cmd/mesh-build-go/module.go +++ b/modules/mesh-build-go/cmd/mesh-build-go/module.go @@ -82,6 +82,10 @@ type Module struct { Settings string Capacity func() int ReadKept func(key string) (json.RawMessage, error) + // ReadManifest reads a key of the delivery indexer's manifests state (ManifestsState), which a compose ask's request + // names its manifests by (compose.go); GoModCache, when set, is the Go module cache in place of Cache's (a test). + ReadManifest func(key string) (json.RawMessage, error) + GoModCache string spacesOnce sync.Once workspaces *buildstep.Workspaces diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 79763029..6e098605 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721 github.com/distribution/distribution/v3 v3.1.2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index 81e122b8..2e3015dc 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -1,5 +1,7 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93 h1:FAiFY2KBKEoZSH49OZTt7/zRBIQxyl5g/KhYrpggbN4= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721 h1:N//dDGmry1F3HKeBTWd+z/SfK+wb8bUUMJF0OlgR0/g= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= diff --git a/modules/mesh-build-go/module.json b/modules/mesh-build-go/module.json index 4d2b080a..600345e3 100644 --- a/modules/mesh-build-go/module.json +++ b/modules/mesh-build-go/module.json @@ -20,7 +20,8 @@ } ], "reads": [ - "mesh-delivery-checker.kept" + "mesh-delivery-checker.kept", + "mesh-delivery-indexer.manifests" ], "config": { "capacity": { From e870a7f65fa962c69bbb7485759281143140557b Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 04:28:14 +0200 Subject: [PATCH 05/12] Pin to the finish group's mesh-sdk head dd0d156b, so every member names one SDK (issue 1622) --- modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 6e098605..1f114f46 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc github.com/distribution/distribution/v3 v3.1.2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index 2e3015dc..6c96246c 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93 h1:FAiFY2KB git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721 h1:N//dDGmry1F3HKeBTWd+z/SfK+wb8bUUMJF0OlgR0/g= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc h1:MSywVviXmT3bR2pQLJLHErUGK8wCme8jEspS6x/j/Vo= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= From f04465537b7ca27390d1b68abc7f45952508cdad Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 04:37:52 +0200 Subject: [PATCH 06/12] Say in realtree_test that a missing trunk fails, not skips (issue 1295) --- checks/paths/realtree_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/paths/realtree_test.go b/checks/paths/realtree_test.go index d42f7f5a..c689267d 100644 --- a/checks/paths/realtree_test.go +++ b/checks/paths/realtree_test.go @@ -32,8 +32,8 @@ func TestNoModuleNamesAnothersState(t *testing.T) { } } -// And neither list gains a line the trunk's copies at the merge base do not hold, unless the line says why after `# allow:`. Skipped, -// and said, where no trunk is beside. +// And neither list gains a line the trunk's copies at the merge base do not hold, unless the line says why after `# allow:`. Fails, saying +// NOT COMPARED, where no trunk is beside (issue 1295). func TestTheListsOfPathsHoldNoLineTheTrunksDoNot(t *testing.T) { sharedPath, okShared := trunk.Copy(t, "checks/paths/shared") knownPath, okKnown := trunk.Copy(t, "checks/paths/known") From 16d7b1898d3808b4fc0238aa1e7045213aa04a20 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 04:38:48 +0200 Subject: [PATCH 07/12] Mark the packages whose tests read files outside their directory, found by the review (issue 1935) --- checks/agenthome/reads-outside | 1 + checks/config/reads-outside | 1 + checks/deps/reads-outside | 1 + checks/health/reads-outside | 1 + checks/imagebuild/reads-outside | 1 + checks/imageplace/reads-outside | 1 + checks/locks/reads-outside | 1 + checks/mailstore/reads-outside | 1 + checks/noscripts/reads-outside | 1 + checks/owned/reads-outside | 1 + checks/particulars/reads-outside | 1 + checks/paths/reads-outside | 1 + checks/predefined/reads-outside | 1 + checks/secrets/reads-outside | 1 + checks/sshdir/reads-outside | 1 + checks/templates/reads-outside | 1 + checks/toolchains/reads-outside | 1 + checks/trunk/reads-outside | 1 + checks/words/reads-outside | 1 + modules/adwaita/internal/desktop/reads-outside | 1 + modules/blueman/cmd/blueman-tools/reads-outside | 1 + modules/brother/cmd/brother/reads-outside | 1 + modules/forticlient/cmd/forticlient-tools/reads-outside | 1 + modules/i3/internal/desktop/reads-outside | 1 + modules/lemurs/internal/desktop/reads-outside | 1 + modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reads-outside | 1 + modules/mesh-issues/cmd/mesh-issues/reads-outside | 1 + modules/mesh-knowledge/cmd/mesh-knowledge/reads-outside | 1 + modules/mesh-mail-notifier/cmd/mesh-mail-notifier/reads-outside | 1 + modules/mesh-mail-reader/cmd/mesh-mail-reader/reads-outside | 1 + modules/mesh-mail/cmd/mesh-mail/reads-outside | 1 + modules/networkmanager/cmd/uplink-tools/reads-outside | 1 + .../nextcloud-client/cmd/nextcloud-client-tools/reads-outside | 1 + modules/nm-applet/cmd/nm-applet-tools/reads-outside | 1 + modules/openrazer/cmd/openrazer-tools/reads-outside | 1 + modules/polychromatic/cmd/polychromatic-tools/reads-outside | 1 + modules/slack/cmd/slack-tools/reads-outside | 1 + modules/systemd-networkd/cmd/uplink-tools/reads-outside | 1 + modules/xorg/internal/desktop/reads-outside | 1 + modules/xterm/internal/desktop/reads-outside | 1 + 40 files changed, 40 insertions(+) create mode 100644 checks/agenthome/reads-outside create mode 100644 checks/config/reads-outside create mode 100644 checks/deps/reads-outside create mode 100644 checks/health/reads-outside create mode 100644 checks/imagebuild/reads-outside create mode 100644 checks/imageplace/reads-outside create mode 100644 checks/locks/reads-outside create mode 100644 checks/mailstore/reads-outside create mode 100644 checks/noscripts/reads-outside create mode 100644 checks/owned/reads-outside create mode 100644 checks/particulars/reads-outside create mode 100644 checks/paths/reads-outside create mode 100644 checks/predefined/reads-outside create mode 100644 checks/secrets/reads-outside create mode 100644 checks/sshdir/reads-outside create mode 100644 checks/templates/reads-outside create mode 100644 checks/toolchains/reads-outside create mode 100644 checks/trunk/reads-outside create mode 100644 checks/words/reads-outside create mode 100644 modules/adwaita/internal/desktop/reads-outside create mode 100644 modules/blueman/cmd/blueman-tools/reads-outside create mode 100644 modules/brother/cmd/brother/reads-outside create mode 100644 modules/forticlient/cmd/forticlient-tools/reads-outside create mode 100644 modules/i3/internal/desktop/reads-outside create mode 100644 modules/lemurs/internal/desktop/reads-outside create mode 100644 modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reads-outside create mode 100644 modules/mesh-issues/cmd/mesh-issues/reads-outside create mode 100644 modules/mesh-knowledge/cmd/mesh-knowledge/reads-outside create mode 100644 modules/mesh-mail-notifier/cmd/mesh-mail-notifier/reads-outside create mode 100644 modules/mesh-mail-reader/cmd/mesh-mail-reader/reads-outside create mode 100644 modules/mesh-mail/cmd/mesh-mail/reads-outside create mode 100644 modules/networkmanager/cmd/uplink-tools/reads-outside create mode 100644 modules/nextcloud-client/cmd/nextcloud-client-tools/reads-outside create mode 100644 modules/nm-applet/cmd/nm-applet-tools/reads-outside create mode 100644 modules/openrazer/cmd/openrazer-tools/reads-outside create mode 100644 modules/polychromatic/cmd/polychromatic-tools/reads-outside create mode 100644 modules/slack/cmd/slack-tools/reads-outside create mode 100644 modules/systemd-networkd/cmd/uplink-tools/reads-outside create mode 100644 modules/xorg/internal/desktop/reads-outside create mode 100644 modules/xterm/internal/desktop/reads-outside diff --git a/checks/agenthome/reads-outside b/checks/agenthome/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/agenthome/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/config/reads-outside b/checks/config/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/config/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/deps/reads-outside b/checks/deps/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/deps/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/health/reads-outside b/checks/health/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/health/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/imagebuild/reads-outside b/checks/imagebuild/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/imagebuild/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/imageplace/reads-outside b/checks/imageplace/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/imageplace/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/locks/reads-outside b/checks/locks/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/locks/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/mailstore/reads-outside b/checks/mailstore/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/mailstore/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/noscripts/reads-outside b/checks/noscripts/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/noscripts/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/owned/reads-outside b/checks/owned/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/owned/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/particulars/reads-outside b/checks/particulars/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/particulars/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/paths/reads-outside b/checks/paths/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/paths/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/predefined/reads-outside b/checks/predefined/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/predefined/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/secrets/reads-outside b/checks/secrets/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/secrets/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/sshdir/reads-outside b/checks/sshdir/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/sshdir/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/templates/reads-outside b/checks/templates/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/templates/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/toolchains/reads-outside b/checks/toolchains/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/toolchains/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/trunk/reads-outside b/checks/trunk/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/trunk/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/checks/words/reads-outside b/checks/words/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/checks/words/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/adwaita/internal/desktop/reads-outside b/modules/adwaita/internal/desktop/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/adwaita/internal/desktop/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/blueman/cmd/blueman-tools/reads-outside b/modules/blueman/cmd/blueman-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/blueman/cmd/blueman-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/brother/cmd/brother/reads-outside b/modules/brother/cmd/brother/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/brother/cmd/brother/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/forticlient/cmd/forticlient-tools/reads-outside b/modules/forticlient/cmd/forticlient-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/forticlient/cmd/forticlient-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/i3/internal/desktop/reads-outside b/modules/i3/internal/desktop/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/i3/internal/desktop/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/lemurs/internal/desktop/reads-outside b/modules/lemurs/internal/desktop/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/lemurs/internal/desktop/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reads-outside b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-issues/cmd/mesh-issues/reads-outside b/modules/mesh-issues/cmd/mesh-issues/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-issues/cmd/mesh-issues/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/reads-outside b/modules/mesh-knowledge/cmd/mesh-knowledge/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-mail-notifier/cmd/mesh-mail-notifier/reads-outside b/modules/mesh-mail-notifier/cmd/mesh-mail-notifier/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-mail-notifier/cmd/mesh-mail-notifier/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-mail-reader/cmd/mesh-mail-reader/reads-outside b/modules/mesh-mail-reader/cmd/mesh-mail-reader/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-mail-reader/cmd/mesh-mail-reader/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/mesh-mail/cmd/mesh-mail/reads-outside b/modules/mesh-mail/cmd/mesh-mail/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/mesh-mail/cmd/mesh-mail/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/networkmanager/cmd/uplink-tools/reads-outside b/modules/networkmanager/cmd/uplink-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/networkmanager/cmd/uplink-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/nextcloud-client/cmd/nextcloud-client-tools/reads-outside b/modules/nextcloud-client/cmd/nextcloud-client-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/nextcloud-client/cmd/nextcloud-client-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/nm-applet/cmd/nm-applet-tools/reads-outside b/modules/nm-applet/cmd/nm-applet-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/nm-applet/cmd/nm-applet-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/openrazer/cmd/openrazer-tools/reads-outside b/modules/openrazer/cmd/openrazer-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/openrazer/cmd/openrazer-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/polychromatic/cmd/polychromatic-tools/reads-outside b/modules/polychromatic/cmd/polychromatic-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/polychromatic/cmd/polychromatic-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/slack/cmd/slack-tools/reads-outside b/modules/slack/cmd/slack-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/slack/cmd/slack-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/systemd-networkd/cmd/uplink-tools/reads-outside b/modules/systemd-networkd/cmd/uplink-tools/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/systemd-networkd/cmd/uplink-tools/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/xorg/internal/desktop/reads-outside b/modules/xorg/internal/desktop/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/xorg/internal/desktop/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). diff --git a/modules/xterm/internal/desktop/reads-outside b/modules/xterm/internal/desktop/reads-outside new file mode 100644 index 00000000..f6b2d871 --- /dev/null +++ b/modules/xterm/internal/desktop/reads-outside @@ -0,0 +1 @@ +These tests read files outside this directory (the whole catalogue, the repository, or its root files): mesh-build-go never keeps this package's verdict (issue 1935). From f910b0ceb8562b87c8c7580d7e2d08572aabb0c6 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 13:28:16 +0200 Subject: [PATCH 08/12] Pin mesh-build-go to the group's mesh-sdk head after main's merge, so it builds on the SDK the group delivers --- modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 1f114f46..126f0225 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052 github.com/distribution/distribution/v3 v3.1.2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index 6c96246c..79de922a 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -1,9 +1,5 @@ -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93 h1:FAiFY2KBKEoZSH49OZTt7/zRBIQxyl5g/KhYrpggbN4= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023213200-403a5d72ab93/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721 h1:N//dDGmry1F3HKeBTWd+z/SfK+wb8bUUMJF0OlgR0/g= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024021031-66bf26c0d721/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc h1:MSywVviXmT3bR2pQLJLHErUGK8wCme8jEspS6x/j/Vo= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024022512-dd0d156b9edc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052 h1:iPXa9g9QtywV2DHdtTFF4jHae5aKgCv+lCYdilRbp5k= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= From 03524ecd134f38ebe8a66c7320696944b9ff202f Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 13:48:09 +0200 Subject: [PATCH 09/12] Mark pacman-tools as reading outside its directory: its upgrade-order test reads the root predefined.json, which its digest does not cover (issue 1935) --- modules/pacman/cmd/pacman-tools/reads-outside | 1 + 1 file changed, 1 insertion(+) create mode 100644 modules/pacman/cmd/pacman-tools/reads-outside diff --git a/modules/pacman/cmd/pacman-tools/reads-outside b/modules/pacman/cmd/pacman-tools/reads-outside new file mode 100644 index 00000000..c1b869c0 --- /dev/null +++ b/modules/pacman/cmd/pacman-tools/reads-outside @@ -0,0 +1 @@ +These tests read other catalogue modules' files, outside this module (issue 1935): never kept. From 865f3b6455fb9d7d0e69c07f754b1125e631162f Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 13:48:18 +0200 Subject: [PATCH 10/12] Say what pacman-tools reads outside: the root predefined.json (issue 1935) --- modules/pacman/cmd/pacman-tools/reads-outside | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pacman/cmd/pacman-tools/reads-outside b/modules/pacman/cmd/pacman-tools/reads-outside index c1b869c0..2c69a776 100644 --- a/modules/pacman/cmd/pacman-tools/reads-outside +++ b/modules/pacman/cmd/pacman-tools/reads-outside @@ -1 +1 @@ -These tests read other catalogue modules' files, outside this module (issue 1935): never kept. +These tests read the repository's root predefined.json, outside this module (issue 1935): never kept. From 89b9212c4d0dbd52cc2864dca1ab6a11aa2f8f06 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 14:12:09 +0200 Subject: [PATCH 11/12] Pin to the group's new mesh-sdk head 19c1d359, whose composer names the reader's pinned SDK instead of a bare (devel) (ADR 0482 clause 5) --- modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 126f0225..800ba697 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc github.com/distribution/distribution/v3 v3.1.2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index 79de922a..b10ba6d6 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -1,5 +1,5 @@ -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052 h1:iPXa9g9QtywV2DHdtTFF4jHae5aKgCv+lCYdilRbp5k= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024112544-bc0c25e51052/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc h1:aOONENGflAq/LJPQAcSKrv/EnFBfpNq0tixTirQitn8= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= From 2fabbe556e73e0625e755435815f52192823afbc Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 24 Oct 2026 14:57:35 +0200 Subject: [PATCH 12/12] =?UTF-8?q?Pin=20to=20the=20group's=20new=20mesh-sdk?= =?UTF-8?q?=20head=20bfc3883a,=20whose=20composer=20reads=20a=20fallback?= =?UTF-8?q?=20to=20a=20predefined=20key=20as=20the=20indexer=20does=20(ADR?= =?UTF-8?q?=200348=20=C2=A77)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/mesh-build-go/go.mod | 2 +- modules/mesh-build-go/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/mesh-build-go/go.mod b/modules/mesh-build-go/go.mod index 800ba697..a5118d4a 100644 --- a/modules/mesh-build-go/go.mod +++ b/modules/mesh-build-go/go.mod @@ -3,7 +3,7 @@ module meshbuildgo go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024125710-bfc3883af980 github.com/distribution/distribution/v3 v3.1.2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/modules/mesh-build-go/go.sum b/modules/mesh-build-go/go.sum index b10ba6d6..f32f243f 100644 --- a/modules/mesh-build-go/go.sum +++ b/modules/mesh-build-go/go.sum @@ -1,5 +1,5 @@ -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc h1:aOONENGflAq/LJPQAcSKrv/EnFBfpNq0tixTirQitn8= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024121120-19c1d35939bc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024125710-bfc3883af980 h1:ZEEeYibEPD1rngOAqbODzRY5rUStGC46OpyQwtNCYbs= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024125710-bfc3883af980/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=