Take the catalogue from mesh-sdk in internal/inventory and internal/link, and keep the tests that read this repository's own manifest, Dockerfile and Makefile in internal/ownmanifest (issue 1381, 5 of 6 import swaps)

The three tests of the controller's own module.json (process, claimed seat, addresses), the Dockerfile and Makefile pin test, the build-agent registry test and the manifest-in-use seat test move with their old package, as tests of mesh-sdk's exported API; a moved test is exempt from failing first.
This commit is contained in:
2026-10-20 08:27:10 +00:00
parent bfe7fe1530
commit af267cb557
52 changed files with 253 additions and 48 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"sort"
"strings"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// What the artifact store keeps, and what it may let go (novox/hq ADR 0189, issue 108).
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"fmt"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// What the store keeps, and what it may let go (novox/hq ADR 0189, issue 108).
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// **The settings layers move into mesh-config** (novox/hq ADR 0348 §9 and its consequences, design 57 K5, issue
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// configured is a module in the config form: one value a mergeable file takes, and a directory to place.
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The data a module declares, as the mesh found it on each machine (novox/hq ADR 0233).
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/builder"
"github.com/novox/mesh-controller/internal/catalogue"
)
// The kinds of edge in the catalogue's one dependency relation (novox/hq ADR 0162).
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The catalogue's one dependency relation (novox/hq ADR 0162): four kinds of edge from one call.
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// What removing a module takes with it, and what re-registering one does not.
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The gate's verdicts (novox/hq ADR 0236, to-be 45 §8): what a build did on its first machine, and,
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// `give` takes only a value nobody but a person has (the review of 2026-10-09, M4): never the module's bus
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"testing"
"time"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/chain"
)
+1 -1
View File
@@ -3,8 +3,8 @@ package inventory
import (
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/broker"
"github.com/novox/mesh-controller/internal/catalogue"
)
// novox/hq issue 218: a seat held once for the mesh is granted and issued only to the holder on record;
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"context"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A seat's holder is a row, changed as one act (novox/hq ADR 0131). What these pin is the shape of
+1 -1
View File
@@ -5,7 +5,7 @@ package inventory
import (
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A value a provider's software issued is sealed to every pair that holds the provision from that provider, under
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A base a build copies into the store is recorded where it is copied, and kept while a kept build stood
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// novox/hq 04-ISSUES/219: two builds of one module in flight together, the one asked first heard
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/secrets"
)
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/secrets"
)
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/secrets"
)
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// outsideProvision registers a provider offering tv-api with a credential issued outside the mesh (novox/hq ADR
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"context"
"sort"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// **The move of placement** (novox/hq ADR 0348 clause 11, issue 736; design 57: the moves of data run after the
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// placedLibrary is a module with each kind of placement: a directory to place, two accesses, a container that
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// reachedForge is a module every one of the four words reaches: two endpoints, both published, one with a
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
func aNodeWithModules(t *testing.T, modules ...string) (*Inventory, string) {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The list of predefined keys the mesh publishes (novox/hq ADR 0348 §7, design 57 package K2): the newest trunk
+1 -1
View File
@@ -5,7 +5,7 @@ package inventory
import (
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The list of predefined keys the controller keeps (novox/hq ADR 0348 §7 and its check "a newer trunk build's
+1 -1
View File
@@ -11,8 +11,8 @@ import (
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/broker"
"github.com/novox/mesh-controller/internal/catalogue"
)
// The provisioner's plan of a module on a node (novox/hq ADR 0349 clause 4, design 57 P5, issue 671): what a node's
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// APlan is a whole plan, as design 57 P6 composes one for a module handed to the provisioner.
@@ -6,7 +6,7 @@ import (
"encoding/json"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
func TestAModuleInTheConfigFormIsMirroredWithItsWholeDeclaration(t *testing.T) {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// jsonFields is the names a struct's fields are encoded under.
@@ -7,7 +7,7 @@ import (
"testing"
"time"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
func TestWhatRunsIsTheRegisteredBuildNotANewerOnePutBack(t *testing.T) {
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/broker"
"github.com/novox/mesh-controller/internal/catalogue"
)
// grantMatches is a NATS subject pattern matching a subject: `*` one token, `>` the rest.
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"encoding/json"
"fmt"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The seats the mesh has, as data (novox/hq ADR 0122).
+1 -1
View File
@@ -5,7 +5,7 @@ package inventory
import (
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The seat set is data the control plane owns (novox/hq ADR 0122): seeded from the binary's
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
func TestAMemberGivenIsReadAsGivenAndNothingElseIs(t *testing.T) {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A member of a secret family is given by its full name, at the desk too, and a name outside the family is refused
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"context"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The move reads every row sealed to a machine as the store holds it (design 57's V3, issue 676): its modules' own
+1 -1
View File
@@ -11,8 +11,8 @@ import (
"github.com/jackc/pgx/v5"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/broker"
"github.com/novox/mesh-controller/internal/catalogue"
"github.com/novox/mesh-controller/internal/secrets"
)
+1 -1
View File
@@ -12,7 +12,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/secrets"
"golang.org/x/crypto/nacl/box"
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"reflect"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// novox/hq issue 259: a send keeps which build of each module it carried. A machine never sent
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A setting is judged where it is stored (novox/hq ADR 0163, rule 6): one that cannot compose with
+1 -1
View File
@@ -3,7 +3,7 @@ package inventory
import (
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// 1154/AC2: a module's state with key-ttl is composed into a bucket that carries KeyTTL; without it, none.
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A build kept from before ADR 0326 §3 is still read and composed (novox/hq issue 574). betterbird's
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"slices"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A machine's layer wins over the mesh's for the setting that restricts a stream (novox/hq ADR 0363 §5).
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The manifest the mesh holds carries each file's text (novox/hq ADR 0349 §2): one still naming a template — a
+1 -1
View File
@@ -5,7 +5,7 @@ package inventory
import (
"testing"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// novox/hq ADR 0217: a settings layer can be read, and the one a set or a clear replaced is kept, so
+1 -1
View File
@@ -6,8 +6,8 @@ import (
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/broker"
"github.com/novox/mesh-controller/internal/catalogue"
)
// The tool runner's manifest with the families novox/hq ADR 0367 §5 starts the grant with, and one more.
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"golang.org/x/crypto/nacl/box"
"github.com/novox/mesh-controller/internal/catalogue"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-controller/internal/inventory"
"github.com/novox/mesh-controller/internal/link"
)
@@ -0,0 +1,133 @@
package ownmanifest
import (
"encoding/json"
"fmt"
"os"
"strings"
"testing"
. "git.novox.be/novox/mesh-sdk/go/catalogue"
)
// novox/hq issue 213: the controller is a Go program and was the one piece of the mesh's own Go
// code still shipped as an image (ADR 0188 §1). Its own manifest, composed for the machine that runs
// it, is a Go bundle run by the host as a process — and no container.
func TestTheControllerIsAProcessAndNoContainer(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
if err != nil {
t.Fatal(err)
}
m, err := ParseManifest(raw)
if err != nil {
t.Fatalf("the controller's own manifest does not parse:\n%v", err)
}
if m.Build == nil || len(m.Build.Artifacts) != 1 {
t.Fatalf("the controller builds %+v; it is one bundle", m.Build)
}
a := m.Build.Artifacts[0]
if a.Kind != ArtifactBundle || a.Language != "go" || a.System == "" || BinaryOf(a) != "mesh-controller" {
t.Fatalf("the controller's artifact is %+v, not a Go bundle naming its system and binary", a)
}
for _, c := range m.Capabilities {
if c == "container-runtime" {
t.Error("the controller still requires a container runtime on its machine")
}
}
digest := "sha256:" + strings.Repeat("c", 64)
control, err := m.Resolve([]Built{{Name: a.Name, Kind: ArtifactBundle,
Reference: ArtifactStoreScheme + "mesh-controller/" + a.Name + "@" + digest, Digest: digest}})
if err != nil {
t.Fatal(err)
}
// The node's runtime does not launch it: it serves its seat's verbs itself.
if loads := control.Bundles[0].Loads; len(loads) != 0 {
t.Errorf("the node's runtime would launch the controller as a tools bundle: %v", loads)
}
needed := map[string]map[string]string{"mesh-controller": {}}
for name := range m.OwnSecrets {
needed["mesh-controller"][name] = "sealed-" + name
}
out, err := Resolution{Node: "anchor", Modules: []Manifest{control}}.Declaration(Rendering{
Needed: needed, ArtifactStore: "anchor.internal:5100",
Seats: map[string]map[int]int{"mesh-store": {5432: 6852}},
})
if err != nil {
t.Fatalf("the controller does not compose: %v", err)
}
var process, step map[string]any
account, firstSecret := -1, -1
for i, r := range out {
switch {
case r["type"] == "container":
t.Errorf("the controller's declaration still runs a container: %v", r)
case r["id"] == "mesh-controller.controller":
process = r
case r["id"] == "mesh-controller.controller-prepare":
step = r
if process != nil {
t.Error("the controller's preparation is placed after the process it prepares for")
}
case r["type"] == "user" && r["name"] == "mesh-controller":
account = i
case strings.HasPrefix(fmt.Sprint(r["id"]), "mesh-controller.needs-") && firstSecret < 0:
firstSecret = i
}
}
if process == nil {
t.Fatalf("the controller's process is not in its declaration: %v", out)
}
if run, _ := json.Marshal(process["run"]); string(run) != `["./mesh-controller","serve"]` {
t.Errorf("the controller is run as %s, not its own bundle's binary", run)
}
if process["source"] != "anchor.internal:5100/mesh-controller/"+a.Name+"@"+digest || process["digest"] != digest {
t.Errorf("the controller's bundle is fetched from %v (%v)", process["source"], process["digest"])
}
// The user: an account the host declares, which owns what the process reads.
if process["user"] != "mesh-controller" || account < 0 {
t.Errorf("the controller runs as %v, and the account declared is at %d", process["user"], account)
}
if firstSecret >= 0 && account > firstSecret {
t.Error("the controller's secrets are written before the account they belong to exists")
}
for _, r := range out {
if strings.HasPrefix(fmt.Sprint(r["id"]), "mesh-controller.needs-") && r["owner"] != "mesh-controller" {
t.Errorf("%v belongs to %v, which the controller's process cannot read", r["id"], r["owner"])
}
}
if dir := fileNamed(out, "mesh-controller.mesh-state"); dir == nil || dir["owner"] != "mesh-controller" {
t.Errorf("the controller's state directory is not its account's to enter: %v", dir)
}
// Each mount became a path the process reads: nothing it is told is a path inside a container.
state := fmt.Sprint(fileNamed(out, "mesh-controller.mesh-state")["path"])
env, _ := process["env"].(map[string]any)
for key, value := range env {
v := fmt.Sprint(value)
if strings.HasPrefix(v, "/run/secrets") || strings.HasPrefix(v, "/broker-tls") {
t.Errorf("%s=%s is a path inside the container the controller no longer runs in", key, v)
}
if strings.HasSuffix(key, "_FILE") && !strings.HasPrefix(v, state+"/") {
t.Errorf("%s=%s is not one of the files the mesh places for it", key, v)
}
}
if env["MESH_BROKER_CERTIFICATE"] != "/var/lib/mesh-broker-tls/tls.crt" {
t.Errorf("the controller reads the broker's certificate from %v", env["MESH_BROKER_CERTIFICATE"])
}
if env["MESH_STORE_INVENTORY_PORT"] != "6852" {
t.Errorf("the controller is told the store is on %v; the node put it on 6852", env["MESH_STORE_INVENTORY_PORT"])
}
// The handover: the container it ran as goes only once this is running.
if got, _ := json.Marshal(process["replaces"]); string(got) != `["mesh-controller.server"]` {
t.Errorf("the controller's process replaces %s, not the container it ran as", got)
}
// And its state is prepared first, by the same program as the same account.
if step == nil || step["run-once"] != true || step["user"] != "mesh-controller" {
t.Fatalf("the controller's preparation is %v", step)
}
if run, _ := json.Marshal(step["run"]); string(run) != `["./mesh-controller","prepare"]` {
t.Errorf("the controller's preparation runs %s", run)
}
}
+5
View File
@@ -0,0 +1,5 @@
// Package ownmanifest holds the tests of this repository's own manifests (module.json, modules/*), of its Dockerfile
// and Makefile, and of the catalogue's modules as this repository reads them, against mesh-sdk's go/catalogue: the
// tests that read a file of this repository, which mesh-sdk cannot (design 47 R4b, issue 1381). They were
// internal/catalogue's, moved here with the package (a moved test is exempt from failing first).
package ownmanifest
@@ -0,0 +1,38 @@
package ownmanifest
import (
"fmt"
"testing"
. "git.novox.be/novox/mesh-sdk/go/catalogue"
)
// **The builder requires the registry the npm seat delivers, and carries no binding of its own.**
//
// It used to carry a hand-written binding because nothing provided a package registry to resolve
// one from at genesis. The catalogue now requires it like any consumer, and ADR 0110 makes the
// seat's holder the answer when more than one module provides it — so a carried copy would be a
// second answer to the same question, free to drift from the first. Asserted gone, not merely
// unused.
//
// The builder is the build-agent on every machine since novox/hq ADR 0190; this read the retired
// `builder` and, finding no manifest, skipped unseen from then until novox/hq issue 432.
func TestTheBuilderRequiresTheRegistryTheNpmSeatDelivers(t *testing.T) {
builder := catalogueManifest(t, "build-agent")
seat, _ := SeatNamed("npm-package-registry")
var requires bool
for _, r := range builder.Requires {
requires = requires || r == seat.Delivers
}
if !requires {
t.Fatalf("the builder does not require %q: %v", seat.Delivers, builder.Requires)
}
if builder.Binds[seat.Delivers] == "" {
t.Errorf("the builder is not told where the registry is: binds %v", builder.Binds)
}
for _, r := range builder.Resources {
if fmt.Sprint(r["id"]) == "package-binding" {
t.Fatal("the builder carries its own package binding beside the one the mesh resolves")
}
}
}
@@ -0,0 +1,29 @@
package ownmanifest
import (
"os"
"regexp"
"testing"
)
// novox/hq issue 223: genesis raises the controller as a container built from this repository's own
// Dockerfile, with no build arguments — the manifest no longer builds an image, so nothing passes a
// base in. The Dockerfile's own default must therefore be a Go that builds this module, pinned by
// digest, and the replacement the manifest's process names must be the container genesis raises.
func TestGenesisCanBuildTheControllersImageAsItStands(t *testing.T) {
raw, err := os.ReadFile("../../Dockerfile")
if err != nil {
t.Fatal(err)
}
if !regexp.MustCompile(`(?m)^ARG GO_BASE=golang@sha256:[0-9a-f]{64}$`).Match(raw) {
t.Fatal("the Dockerfile's default Go base is not pinned by digest; genesis builds it with no arguments")
}
makefile, err := os.ReadFile("../../Makefile")
if err != nil {
t.Fatal(err)
}
pin := regexp.MustCompile(`golang@sha256:[0-9a-f]{64}`)
if string(pin.Find(raw)) != string(pin.Find(makefile)) {
t.Errorf("the Dockerfile and the Makefile build on different Go: %s, %s", pin.Find(raw), pin.Find(makefile))
}
}