From 86ac7596c92e6d905a62cb060f541cc724560f6a Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 21 Oct 2026 11:17:45 +0200 Subject: [PATCH 1/3] Test that a node without the go or nodejs module refuses the modules needing a toolchain, and with it composes (issue 1573) --- go/catalogue/toolchain_manifests_test.go | 88 ++++++++++ go/testdata/beside/CAPTURED | 1 + .../modules/dev-tools/module.json.captured | 19 +- .../modules/go/module.json.captured | 20 +++ .../modules/lab/module.json.captured | 14 +- .../modules/mesh-build-go/files/forge | 7 + .../modules/mesh-build-go/files/gitconfig | 2 + .../modules/mesh-build-go/files/known_hosts | 1 + .../mesh-build-go/module.json.captured | 145 +++++++++++++++ .../modules/mesh-build-node/files/forge | 7 + .../modules/mesh-build-node/files/gitconfig | 2 + .../modules/mesh-build-node/files/known_hosts | 1 + .../mesh-build-node/module.json.captured | 166 ++++++++++++++++++ .../modules/nodejs/module.json.captured | 25 +++ 14 files changed, 472 insertions(+), 26 deletions(-) create mode 100644 go/catalogue/toolchain_manifests_test.go create mode 100644 go/testdata/beside/mesh-catalog/modules/go/module.json.captured create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/forge create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/gitconfig create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/known_hosts create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/forge create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/gitconfig create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/known_hosts create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured create mode 100644 go/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured diff --git a/go/catalogue/toolchain_manifests_test.go b/go/catalogue/toolchain_manifests_test.go new file mode 100644 index 0000000..a56fd2b --- /dev/null +++ b/go/catalogue/toolchain_manifests_test.go @@ -0,0 +1,88 @@ +package catalogue + +import ( + "strings" + "testing" +) + +// Defends novox/hq ADR 0477 §4 (issue 1573): the go and nodejs modules own the toolchain packages and provide +// them with the machine's reach, so a node without one refuses the module that needs it at resolution, naming +// the provision, and does not find out at its first build. The manifests are the catalogue's, as they are. + +// builderNode is a machine that can run a build module: the package manager and user namespaces it asks of +// the machine, and the forge account (mesh-scope, provided by the forge) stood in for. +func builderNode() Node { + return Node{Name: "builder", Site: "house", + Capabilities: map[string]bool{"package-manager": true, "user-namespaces": true}} +} + +func toolchainShelf(t *testing.T) map[string]Manifest { + t.Helper() + m := map[string]Manifest{ + "forge": {Module: "forge", Version: "1", Provides: []Offer{{Name: "forge-account"}, {Name: "npm-package-registry"}}}, + } + for _, name := range []string{"go", "nodejs", "mesh-build-go", "mesh-build-node", "dev-tools"} { + m[name] = catalogueManifest(t, name) + } + return m +} + +func TestAModuleNeedingAToolchainIsRefusedOnANodeWithoutIt(t *testing.T) { + for _, c := range []struct{ module, provision string }{ + {"mesh-build-go", "go-toolchain"}, + {"mesh-build-node", "node-toolchain"}, + {"dev-tools", "go-toolchain"}, + } { + _, err := Resolve(toolchainShelf(t), []string{"forge", c.module}, builderNode(), World{}) + if err == nil { + t.Fatalf("%s composed on a node with no toolchain module", c.module) + } + for _, want := range []string{`"` + c.provision + `" is wanted by ` + c.module, + "usable only on the machine that provides it"} { + if !strings.Contains(err.Error(), want) { + t.Errorf("%s: the refusal does not say %q:\n%v", c.module, want, err) + } + } + } +} + +func TestAModuleNeedingAToolchainComposesOnANodeWithIt(t *testing.T) { + for _, c := range []struct{ module, owner string }{ + {"mesh-build-go", "go"}, + {"mesh-build-node", "nodejs"}, + {"dev-tools", "go"}, + } { + assigned := []string{"forge", c.owner, c.module} + if c.module == "dev-tools" { + assigned = append(assigned, "nodejs") + } + got, err := Resolve(toolchainShelf(t), assigned, builderNode(), World{}) + if err != nil { + t.Fatalf("%s with %s did not compose: %v", c.module, c.owner, err) + } + in := map[string]bool{} + for _, n := range names(got) { + in[n] = true + } + if !in[c.module] || !in[c.owner] { + t.Errorf("%s with %s composed %v", c.module, c.owner, names(got)) + } + } +} + +// Only the owners declare the packages: a build module that declared go again would compose without the +// owner's provision being met by anything, which is the gap the provision closes. +func TestOnlyTheToolchainModulesDeclareTheToolchainPackages(t *testing.T) { + owner := map[string]string{"go": "go", "nodejs": "nodejs", "npm": "nodejs"} + for name, m := range toolchainShelf(t) { + for _, r := range m.Resources { + if r["type"] != "package" { + continue + } + pkg, _ := r["package"].(string) + if o, ok := owner[pkg]; ok && o != name { + t.Errorf("%s declares the package %s, which only %s may", name, pkg, o) + } + } + } +} diff --git a/go/testdata/beside/CAPTURED b/go/testdata/beside/CAPTURED index dc56ca5..915bf1a 100644 --- a/go/testdata/beside/CAPTURED +++ b/go/testdata/beside/CAPTURED @@ -11,6 +11,7 @@ Only what go/catalogue's tests read is captured (R4b, issue 1379). Refreshed 202 repositories; before that it was mesh-controller's copy, which still held two modules that had left the catalogue. mesh-catalog bb0fe93bbdddd869ad808210352461efc506c3d3 modules/*/module.json, modules/*/files/**, modules/*/templates/**, predefined.json +mesh-catalog 91c2007c modules/{go,nodejs,dev-tools,lab,mesh-build-go,mesh-build-node}/module.json, and files/** of the two build modules, only (branch fix/1573-toolchain-modules, issue 1573: the toolchain modules); the rest stays as captured above. Refresh all of it from the catalogue's main once that is merged. mesh-host cdcba9ca73755854d21e4e657d7e46c32b9b5265 internal/apply/placement_guard.go To move them, from this repository's go/ directory, with the two repositories checked out beside mesh-sdk: diff --git a/go/testdata/beside/mesh-catalog/modules/dev-tools/module.json.captured b/go/testdata/beside/mesh-catalog/modules/dev-tools/module.json.captured index 8ee6fd1..094f833 100644 --- a/go/testdata/beside/mesh-catalog/modules/dev-tools/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/dev-tools/module.json.captured @@ -4,12 +4,11 @@ "capabilities": [ "package-manager" ], + "requires": [ + "go-toolchain", + "node-toolchain" + ], "resources": [ - { - "id": "go", - "type": "package", - "package": "go" - }, { "id": "c-compiler", "type": "package", @@ -20,16 +19,6 @@ "type": "package", "package": "make" }, - { - "id": "nodejs", - "type": "package", - "package": "nodejs" - }, - { - "id": "npm", - "type": "package", - "package": "npm" - }, { "id": "python", "type": "package", diff --git a/go/testdata/beside/mesh-catalog/modules/go/module.json.captured b/go/testdata/beside/mesh-catalog/modules/go/module.json.captured new file mode 100644 index 0000000..48a6bf5 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/go/module.json.captured @@ -0,0 +1,20 @@ +{ + "module": "go", + "version": "1", + "capabilities": [ + "package-manager" + ], + "provides": [ + { + "name": "go-toolchain", + "reach": "machine" + } + ], + "resources": [ + { + "id": "go", + "type": "package", + "package": "go" + } + ] +} diff --git a/go/testdata/beside/mesh-catalog/modules/lab/module.json.captured b/go/testdata/beside/mesh-catalog/modules/lab/module.json.captured index e23963d..ef82b87 100644 --- a/go/testdata/beside/mesh-catalog/modules/lab/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/lab/module.json.captured @@ -6,7 +6,9 @@ "virtualisation" ], "requires": [ - "npm-package-registry" + "npm-package-registry", + "go-toolchain", + "node-toolchain" ], "contributes": { "npm-package-registry": { @@ -84,16 +86,6 @@ "type": "package", "package": "iproute2" }, - { - "id": "npm", - "type": "package", - "package": "npm" - }, - { - "id": "go", - "type": "package", - "package": "go" - }, { "id": "incus", "type": "package", diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/forge b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/forge new file mode 100644 index 0000000..6bbf4e2 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/forge @@ -0,0 +1,7 @@ +Host ${bound:forge-account:ssh_alias} + HostName ${bound:forge-account:ssh_host} + Port ${bound:forge-account:ssh_port} + HostKeyAlias ${bound:forge-account:ssh_alias} + User git + IdentityFile ~/.ssh/mesh_ed25519 + IdentitiesOnly yes diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/gitconfig b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/gitconfig new file mode 100644 index 0000000..0525230 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/gitconfig @@ -0,0 +1,2 @@ +[url "ssh://${bound:forge-account:ssh_alias}/"] + insteadOf = ${bound:forge-account:https_base} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/known_hosts b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/known_hosts new file mode 100644 index 0000000..e0df6d8 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/files/known_hosts @@ -0,0 +1 @@ +${bound:forge-account:ssh_alias} ${bound:forge-account:host_key} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured new file mode 100644 index 0000000..74f4d97 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured @@ -0,0 +1,145 @@ +{ + "module": "mesh-build-go", + "version": "1", + "moved": true, + "runs-as": "mesh-build-go", + "capabilities": [ + "package-manager", + "user-namespaces" + ], + "state": [ + "toolchains", + "keys", + "steps" + ], + "tools": [ + "build_go_fetch", + "build_go_test", + "build_go_digest", + "build_go_build", + "build_go_status", + "build_go_health" + ], + "streams": [ + { + "name": "toolchains-go", + "events": ["toolchain.**"] + } + ], + "requires": [ + "forge-account", + "go-toolchain" + ], + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-build-go", + "runtime-health": { + "kind": "tool", + "tool": "build_go_health", + "interval": "60s", + "timeout": "10s", + "looks": 2, + "grace": "60s" + }, + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-build-go", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-build-go" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-build-go", + "place": ".", + "unknown": "program" + }, + { + "id": "work", + "type": "directory", + "path": "/var/lib/mesh-build-go-work", + "mode": "0700", + "owner": "mesh-build-go", + "unknown": "program" + }, + { + "id": "cache", + "type": "directory", + "path": "/var/lib/mesh-build-go-cache", + "mode": "0700", + "owner": "mesh-build-go", + "unknown": "program" + }, + { + "id": "ssh-dir", + "type": "directory", + "path": "${dir:state}/.ssh", + "mode": "0700", + "owner": "mesh-build-go", + "unknown": "program" + }, + { + "id": "ssh-config", + "type": "file", + "path": "${dir:ssh-dir}/config", + "owner": "mesh-build-go", + "mode": "0600", + "template": "files/forge" + }, + { + "id": "known-hosts", + "type": "file", + "path": "${dir:ssh-dir}/known_hosts", + "owner": "mesh-build-go", + "mode": "0644", + "template": "files/known_hosts" + }, + { + "id": "git-config", + "type": "file", + "path": "${dir:state}/.config/git/config", + "owner": "mesh-build-go", + "mode": "0644", + "template": "files/gitconfig" + }, + { + "id": "git", + "type": "package", + "package": "git" + }, + { + "id": "openssh", + "type": "package", + "package": "openssh" + }, + { + "id": "postgresql", + "type": "package", + "package": "postgresql" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-build-go", + "binary": "mesh-build-go", + "loads": [ + "mesh-build-go" + ] + }, + { + "name": "files", + "kind": "archive", + "from": "files" + } + ] + } +} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/forge b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/forge new file mode 100644 index 0000000..6bbf4e2 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/forge @@ -0,0 +1,7 @@ +Host ${bound:forge-account:ssh_alias} + HostName ${bound:forge-account:ssh_host} + Port ${bound:forge-account:ssh_port} + HostKeyAlias ${bound:forge-account:ssh_alias} + User git + IdentityFile ~/.ssh/mesh_ed25519 + IdentitiesOnly yes diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/gitconfig b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/gitconfig new file mode 100644 index 0000000..0525230 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/gitconfig @@ -0,0 +1,2 @@ +[url "ssh://${bound:forge-account:ssh_alias}/"] + insteadOf = ${bound:forge-account:https_base} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/known_hosts b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/known_hosts new file mode 100644 index 0000000..e0df6d8 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/files/known_hosts @@ -0,0 +1 @@ +${bound:forge-account:ssh_alias} ${bound:forge-account:host_key} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured new file mode 100644 index 0000000..a11cb96 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured @@ -0,0 +1,166 @@ +{ + "module": "mesh-build-node", + "version": "1", + "moved": true, + "runs-as": "mesh-build-node", + "capabilities": [ + "package-manager", + "user-namespaces" + ], + "state": [ + "toolchains", + "keys", + "steps" + ], + "tools": [ + "build_node_fetch", + "build_node_test", + "build_node_build", + "build_node_status", + "build_node_health" + ], + "streams": [ + { + "name": "toolchains-node", + "events": [ + "toolchain.**" + ] + } + ], + "requires": [ + "forge-account", + "npm-package-registry", + "node-toolchain" + ], + "contributes": { + "npm-package-registry": { + "access": "read" + } + }, + "binds": { + "npm-package-registry": "${dir:state}/package-registry.json" + }, + "secrets": { + "npm-package-registry": "${dir:state}/package-registry.secret" + }, + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-build-node", + "runtime-health": { + "kind": "tool", + "tool": "build_node_health", + "interval": "60s", + "timeout": "10s", + "looks": 2, + "grace": "60s" + }, + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-build-node", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-build-node" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-build-node", + "place": ".", + "unknown": "program" + }, + { + "id": "work", + "type": "directory", + "path": "/var/lib/mesh-build-node-work", + "mode": "0700", + "owner": "mesh-build-node", + "unknown": "program" + }, + { + "id": "cache", + "type": "directory", + "path": "/var/lib/mesh-build-node-cache", + "mode": "0700", + "owner": "mesh-build-node", + "unknown": "program" + }, + { + "id": "ssh-dir", + "type": "directory", + "path": "${dir:state}/.ssh", + "mode": "0700", + "owner": "mesh-build-node", + "unknown": "program" + }, + { + "id": "ssh-config", + "type": "file", + "path": "${dir:ssh-dir}/config", + "owner": "mesh-build-node", + "mode": "0600", + "template": "files/forge" + }, + { + "id": "known-hosts", + "type": "file", + "path": "${dir:ssh-dir}/known_hosts", + "owner": "mesh-build-node", + "mode": "0644", + "template": "files/known_hosts" + }, + { + "id": "git-config", + "type": "file", + "path": "${dir:state}/.config/git/config", + "owner": "mesh-build-node", + "mode": "0644", + "template": "files/gitconfig" + }, + { + "id": "toolchain-dir", + "type": "archive", + "path": "${dir:state}/toolchain", + "owner": "mesh-build-node", + "artifact": "toolchain", + "unknown": "program" + }, + { + "id": "git", + "type": "package", + "package": "git" + }, + { + "id": "openssh", + "type": "package", + "package": "openssh" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-build-node", + "binary": "mesh-build-node", + "loads": [ + "mesh-build-node" + ] + }, + { + "name": "files", + "kind": "archive", + "from": "files" + }, + { + "name": "toolchain", + "kind": "archive", + "from": "toolchain" + } + ] + } +} diff --git a/go/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured b/go/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured new file mode 100644 index 0000000..c357344 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured @@ -0,0 +1,25 @@ +{ + "module": "nodejs", + "version": "1", + "capabilities": [ + "package-manager" + ], + "provides": [ + { + "name": "node-toolchain", + "reach": "machine" + } + ], + "resources": [ + { + "id": "nodejs", + "type": "package", + "package": "nodejs" + }, + { + "id": "npm", + "type": "package", + "package": "npm" + } + ] +} From a86d607e4824491256972d183aadff52440b618d Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 21 Oct 2026 12:45:01 +0200 Subject: [PATCH 2/3] Refresh the captured catalogue from mesh-catalog main, with the toolchain modules (issue 1573) --- go/testdata/beside/CAPTURED | 5 +- .../files/bin/zephyrus-backlight | 0 .../files/bin/zephyrus-display | 0 .../files/bin/zephyrus-kbd-notify | 0 .../files/bin/zephyrus-media | 0 .../files/bin/zephyrus-notify | 0 .../files/bin/zephyrus-session | 0 .../files/bin/zephyrus-touchpad | 0 .../modules/betterbird/files/betterbird | 0 .../modules/brother/files/settings.json | 9 + .../modules/brother/files/store.json | 9 + .../modules/brother/module.json.captured | 280 ++++++++++++++++++ .../modules/ca-trust/files/anchor | 0 .../modules/claude-code/files/claude-agent | 0 .../modules/clipmenu/files/bin/xsel | 0 .../mesh-catalog/modules/feh/files/fehbg | 0 .../modules/gitea/module.json.captured | 4 +- .../mesh-catalog/modules/i3/files/wms/i3 | 0 .../i3status-rust/files/bin/i3bar-watchdog | 0 .../i3status-rust/files/bin/i3status-updates | 0 .../i3status-rust/files/bin/i3status-value | 0 .../mesh-catalog/modules/lemurs/files/xserver | 0 .../mesh-build-go/module.json.captured | 3 + .../mesh-build-node/module.json.captured | 3 + .../mesh-delivery/module.json.captured | 95 ------ .../modules/mesh-issues/module.json.captured | 1 - .../mesh-mail-reader/files/callers.json | 3 + .../mesh-mail-reader/files/database-url | 1 + .../mesh-mail-reader/module.json.captured | 141 +++++++++ .../mesh-mail-web/module.json.captured | 8 +- .../modules/mesh-mail/module.json.captured | 5 + .../modules/messenger/files/settings.json | 3 +- .../modules/messenger/module.json.captured | 10 +- .../files/mesh-pacman-weekly-upgrade.service | 12 + .../files/mesh-pacman-weekly-upgrade.timer | 11 + .../modules/pacman/module.json.captured | 44 ++- .../modules/power/files/bin/power-moment | 0 .../mesh-catalog/modules/rofi/files/bin/dmenu | 0 .../modules/rofi/files/bin/rofi-launch | 0 .../modules/rofi/files/bin/rofi-powermenu | 0 .../modules/screen-lock/files/bin/screen-lock | 0 .../mesh-catalog/modules/xorg/files/xinitrc | 0 42 files changed, 542 insertions(+), 105 deletions(-) mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-backlight mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-display mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-kbd-notify mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-media mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-notify mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-session mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-touchpad mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/betterbird/files/betterbird create mode 100644 go/testdata/beside/mesh-catalog/modules/brother/files/settings.json create mode 100644 go/testdata/beside/mesh-catalog/modules/brother/files/store.json create mode 100644 go/testdata/beside/mesh-catalog/modules/brother/module.json.captured mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/ca-trust/files/anchor mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/claude-code/files/claude-agent mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/clipmenu/files/bin/xsel mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/feh/files/fehbg mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/i3/files/wms/i3 mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3bar-watchdog mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-updates mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-value mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/lemurs/files/xserver delete mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-delivery/module.json.captured create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/callers.json create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/database-url create mode 100644 go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/module.json.captured create mode 100644 go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.service create mode 100644 go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.timer mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/power/files/bin/power-moment mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/rofi/files/bin/dmenu mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-launch mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-powermenu mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/screen-lock/files/bin/screen-lock mode change 100644 => 100755 go/testdata/beside/mesh-catalog/modules/xorg/files/xinitrc diff --git a/go/testdata/beside/CAPTURED b/go/testdata/beside/CAPTURED index 915bf1a..9f1bb1c 100644 --- a/go/testdata/beside/CAPTURED +++ b/go/testdata/beside/CAPTURED @@ -7,11 +7,10 @@ The copy carries the catalogue's private details: domains, first names in module private addresses. That is acceptable while mesh-sdk is private; if it ever goes public, this copy is a second place to clean besides the catalogue itself. -Only what go/catalogue's tests read is captured (R4b, issue 1379). Refreshed 2026-10-20 from the mains of both +Only what go/catalogue's tests read is captured (R4b, issue 1379). Refreshed 2026-10-21 from the mains of both repositories; before that it was mesh-controller's copy, which still held two modules that had left the catalogue. -mesh-catalog bb0fe93bbdddd869ad808210352461efc506c3d3 modules/*/module.json, modules/*/files/**, modules/*/templates/**, predefined.json -mesh-catalog 91c2007c modules/{go,nodejs,dev-tools,lab,mesh-build-go,mesh-build-node}/module.json, and files/** of the two build modules, only (branch fix/1573-toolchain-modules, issue 1573: the toolchain modules); the rest stays as captured above. Refresh all of it from the catalogue's main once that is merged. +mesh-catalog b5dbfbb784507e211372a7c9640d91f7d6dadd84 modules/*/module.json, modules/*/files/**, modules/*/templates/**, predefined.json mesh-host cdcba9ca73755854d21e4e657d7e46c32b9b5265 internal/apply/placement_guard.go To move them, from this repository's go/ directory, with the two repositories checked out beside mesh-sdk: diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-backlight b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-backlight old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-display b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-display old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-kbd-notify b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-kbd-notify old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-media b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-media old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-notify b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-notify old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-session b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-session old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-touchpad b/go/testdata/beside/mesh-catalog/modules/asus-zephyrus-g14/files/bin/zephyrus-touchpad old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/betterbird/files/betterbird b/go/testdata/beside/mesh-catalog/modules/betterbird/files/betterbird old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/brother/files/settings.json b/go/testdata/beside/mesh-catalog/modules/brother/files/settings.json new file mode 100644 index 0000000..80aed32 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/brother/files/settings.json @@ -0,0 +1,9 @@ +{ + "scanner": "", + "scan-folder": "", + "printer": "", + "printer-certificate": "", + "resolution": 300, + "color-mode": "color", + "crop": true +} diff --git a/go/testdata/beside/mesh-catalog/modules/brother/files/store.json b/go/testdata/beside/mesh-catalog/modules/brother/files/store.json new file mode 100644 index 0000000..8c2075d --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/brother/files/store.json @@ -0,0 +1,9 @@ +{ + "scheme": "${bound:s3-bucket:scheme}", + "at": "${bound:s3-bucket:at}", + "port": "${bound:s3-bucket:port}", + "bucket": "${bound:s3-bucket:bucket}", + "region": "${bound:s3-bucket:region}", + "key": "${bound:s3-bucket:as}", + "secret": "${secret:s3-bucket}" +} diff --git a/go/testdata/beside/mesh-catalog/modules/brother/module.json.captured b/go/testdata/beside/mesh-catalog/modules/brother/module.json.captured new file mode 100644 index 0000000..57559d5 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/brother/module.json.captured @@ -0,0 +1,280 @@ +{ + "module": "brother", + "version": "1", + "requires": [ + "s3-bucket" + ], + "binds": { + "s3-bucket": "${dir:state}/store-binding.json" + }, + "secrets": { + "s3-bucket": "${dir:state}/store.secret" + }, + "config": { + "scanner": { + "type": "string", + "description": "The network scanner's eSCL address, such as http://192.0.2.10/eSCL: the scanner's own address and the path its eSCL service answers on; the operator's, with no default.", + "pattern": "^https?://.+", + "trusted": true, + "required": true + }, + "scan-folder": { + "type": "string", + "description": "The absolute path of the folder the scans are filed in as PDF files; the module makes it when it files the first scan, and never touches a file in it that it did not write. The operator's, with no default.", + "pattern": "^/.+$", + "trusted": true, + "required": true + }, + "printer": { + "type": "string", + "description": "The printer's host, such as 192.0.2.10: where its admin page (HTTPS) and its IPP service answer. The device is the scanner's own; the operator's, with no default.", + "pattern": "^[A-Za-z0-9.:-]+$", + "trusted": true, + "required": true + }, + "printer-certificate": { + "type": "string", + "description": "The SHA-256 fingerprint of the certificate the printer's admin page serves, as 32 upper-case hex pairs joined by colons; several, separated by commas, when the printer serves more than one (it serves an ECDSA and an RSA certificate for one name). The module trusts those certificates alone and refuses any other; the operator's, with no default.", + "pattern": "^([0-9A-F]{2}:){31}[0-9A-F]{2}(, *([0-9A-F]{2}:){31}[0-9A-F]{2})*$", + "trusted": true, + "required": true + }, + "resolution": { + "type": "number", + "description": "The resolution asked of the scanner, in dpi: 100, 200, 300 or 600. A scanner may give another; the scan is filed at the resolution it gave.", + "enum": [ + 100, + 200, + 300, + 600 + ], + "trusted": false, + "default": 300 + }, + "color-mode": { + "type": "string", + "description": "Whether the scan is in colour or in grays: color or gray.", + "enum": [ + "color", + "gray" + ], + "trusted": false, + "default": "color" + }, + "crop": { + "type": "boolean", + "description": "Whether the document is cut out of the platen's white lid; false files the whole platen. A feeder scan is never cropped.", + "trusted": false, + "default": true + } + }, + "own-secrets": { + "admin-password": { + "path": "${dir:state}/admin-password.secret", + "issued-by": "outside", + "prompt": "the admin password of the Brother printer", + "owner": "brother-device" + }, + "broker-device": { + "path": "${dir:state}/broker-device.secret", + "owner": "brother-device" + } + }, + "streams": [ + { + "name": "device-asks", + "events": [ + "device.asked" + ], + "max-age-days": 1, + "max-mib": 8, + "retention": "work-queue", + "max-deliveries": 3, + "duplicates": 24 + } + ], + "state": [ + { + "name": "device-answers", + "ttl-seconds": 600 + } + ], + "seats": [ + { + "name": "scanner", + "scope": "mesh", + "serves": [ + "scan", + "status", + "list", + "document" + ] + }, + { + "name": "printer", + "scope": "mesh", + "serves": [ + "status", + "settings", + "print", + "upload" + ] + } + ], + "claims": [ + { + "name": "scanner", + "scope": "mesh", + "serves": [ + "scan", + "status", + "list", + "document" + ] + }, + { + "name": "printer", + "scope": "mesh", + "serves": [ + "status", + "settings", + "print", + "upload" + ] + } + ], + "emits": [ + "scan.added" + ], + "tools": [ + "scanner.scan", + "scanner.status", + "scanner.list", + "scanner.document", + "printer.status", + "printer.settings", + "printer.print", + "printer.upload", + "brother_health" + ], + "resources": [ + { + "id": "account", + "type": "user", + "name": "brother-device", + "shell": "/usr/bin/nologin" + }, + { + "id": "state", + "type": "directory", + "mode": "0711", + "owner": "${machine:account}", + "place": ".", + "unknown": "program" + }, + { + "id": "settings", + "type": "file", + "path": "${dir:state}/settings.json", + "owner": "${machine:account}", + "mode": "0644", + "takes-config": [ + "scanner", + "scan-folder", + "printer", + "printer-certificate", + "resolution", + "color-mode", + "crop" + ], + "merge": "json", + "template": "files/settings.json", + "trusted": true + }, + { + "id": "store", + "type": "file", + "path": "${dir:state}/store.json", + "owner": "brother-device", + "mode": "0600", + "template": "files/store.json" + }, + { + "id": "device", + "type": "process", + "name": "brother-device", + "artifact": "tools", + "run": [ + "./brother", + "device" + ], + "user": "brother-device", + "env": { + "BROTHER_SETTINGS": "${dir:state}/settings.json", + "BROTHER_ADMIN_PASSWORD": "${dir:state}/admin-password.secret", + "BROTHER_BROKER": "${dir:state}/broker-device.secret", + "BROTHER_STORE": "${dir:state}/store.json" + }, + "restart-on": [ + "settings", + "store" + ], + "bus": { + "queues": [ + "device-asks" + ], + "state": [ + "device-answers" + ], + "emits": [ + "scan.added" + ] + }, + "health": { + "kind": "unit" + } + }, + { + "id": "watch", + "type": "process", + "name": "brother-watch", + "artifact": "tools", + "run": [ + "./brother", + "watch" + ], + "user": "brother-device", + "health": { + "kind": "tool", + "tool": "brother_health", + "interval": "60s", + "timeout": "10s", + "looks": 2, + "grace": "60s" + } + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/brother", + "binary": "brother", + "loads": [ + "brother" + ], + "env": { + "BROTHER_SETTINGS": "${dir:state}/settings.json" + } + }, + { + "name": "files", + "kind": "archive", + "from": "files" + } + ] + } +} diff --git a/go/testdata/beside/mesh-catalog/modules/ca-trust/files/anchor b/go/testdata/beside/mesh-catalog/modules/ca-trust/files/anchor old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/claude-code/files/claude-agent b/go/testdata/beside/mesh-catalog/modules/claude-code/files/claude-agent old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/clipmenu/files/bin/xsel b/go/testdata/beside/mesh-catalog/modules/clipmenu/files/bin/xsel old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/feh/files/fehbg b/go/testdata/beside/mesh-catalog/modules/feh/files/fehbg old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/gitea/module.json.captured b/go/testdata/beside/mesh-catalog/modules/gitea/module.json.captured index 2de9730..118224c 100644 --- a/go/testdata/beside/mesh-catalog/modules/gitea/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/gitea/module.json.captured @@ -540,6 +540,8 @@ ], "reads": [ "mesh-controller.assignments", - "ssh-client.keys" + "ssh-client.keys", + "mesh-build-go.keys", + "mesh-build-node.keys" ] } diff --git a/go/testdata/beside/mesh-catalog/modules/i3/files/wms/i3 b/go/testdata/beside/mesh-catalog/modules/i3/files/wms/i3 old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3bar-watchdog b/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3bar-watchdog old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-updates b/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-updates old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-value b/go/testdata/beside/mesh-catalog/modules/i3status-rust/files/bin/i3status-value old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/lemurs/files/xserver b/go/testdata/beside/mesh-catalog/modules/lemurs/files/xserver old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured index 74f4d97..9f0fd7f 100644 --- a/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured @@ -17,6 +17,9 @@ "build_go_test", "build_go_digest", "build_go_build", + "build_go_step", + "build_go_steps", + "build_go_toolchains", "build_go_status", "build_go_health" ], diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured index a11cb96..b92212a 100644 --- a/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured @@ -16,6 +16,9 @@ "build_node_fetch", "build_node_test", "build_node_build", + "build_node_step", + "build_node_steps", + "build_node_toolchains", "build_node_status", "build_node_health" ], diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-delivery/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-delivery/module.json.captured deleted file mode 100644 index 1a40896..0000000 --- a/go/testdata/beside/mesh-catalog/modules/mesh-delivery/module.json.captured +++ /dev/null @@ -1,95 +0,0 @@ -{ - "module": "mesh-delivery", - "version": "1", - "slug": "deliver", - "claims": [ - { - "name": "mesh-delivery", - "scope": "mesh", - "serves": [ - "deliveries", - "times", - "show", - "groups", - "what-if", - "checks", - "table", - "stalled", - "recheck", - "release", - "stop", - "close", - "retire-history" - ] - } - ], - "consumes": [ - "gitea.pull.updated", - "gitea.pull.merged", - "gitea.pull.closed", - "gitea.forge.status", - "gitea.forge.pull-request.edited", - "gitea.forge.pull-request.closed", - "mesh-controller.checked", - "mesh-controller.plan-moved" - ], - "emits": [ - "transition", - "group", - "merged" - ], - "invokes": [ - "seat:mesh-controller.delivery-plan", - "seat:mesh-controller.delivery-check", - "seat:mesh-controller.deliver", - "seat:mesh-controller.delivery-backups-again", - "seat:mesh-controller.delivery-stop", - "seat:mesh-controller.delivery-walks", - "seat:mesh-controller.forget-checks", - "gitea.gitea_note_append", - "gitea.gitea_delivery_view", - "gitea.gitea_commit_status", - "gitea.gitea_commit_statuses", - "gitea.gitea_contains", - "gitea.gitea_open_pulls", - "gitea.gitea_merge_pull_request", - "gitea.gitea_add_comment", - "seat:operator-channel.notify" - ], - "uses": [ - "operator-channel" - ], - "state": [ - "deliveries", - "groups", - "asked", - "pulls" - ], - "tools": [ - "delivery_status" - ], - "resources": [ - { - "id": "state", - "type": "directory", - "mode": "0700", - "place": ".", - "unknown": "program" - } - ], - "build": { - "artifacts": [ - { - "name": "tools", - "kind": "bundle", - "language": "go", - "system": "arch", - "from": "cmd/mesh-delivery", - "binary": "mesh-delivery", - "loads": [ - "mesh-delivery" - ] - } - ] - } -} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured index 592e81c..dcfc71c 100644 --- a/go/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured @@ -57,7 +57,6 @@ "consumes": [ "mesh-issues.opened", "mesh-issues.moved", - "mesh-delivery.transition", "mesh-delivery-gate.transition" ], "invokes": [ diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/callers.json b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/callers.json new file mode 100644 index 0000000..84dd800 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/callers.json @@ -0,0 +1,3 @@ +{ + "callers": ["mesh-mail-web"] +} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/database-url b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/database-url new file mode 100644 index 0000000..dc59da9 --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/files/database-url @@ -0,0 +1 @@ +postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/module.json.captured new file mode 100644 index 0000000..b83e8bb --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/mesh-mail-reader/module.json.captured @@ -0,0 +1,141 @@ +{ + "module": "mesh-mail-reader", + "version": "1", + "runs-as": "mesh-mail-reader", + "claims": [ + { + "name": "mail-reading", + "scope": "mesh", + "serves": ["entries", "groups", "correct", "lessons", "undo", "status"] + } + ], + "consumes": [ + "mesh-mail.mail.*.message.added" + ], + "invokes": [ + "seat:mail-store.read", + "seat:mail-store.accounts", + "claude-code.claude_code_judge", + "claude-code.claude_code_judged", + "messenger.messenger_check", + "seat:operator-channel.tell" + ], + "requires": ["postgres-database"], + "contributes": { + "postgres-database": { + "name": "mail-reader" + } + }, + "binds": { + "postgres-database": "${dir:state}/database.json" + }, + "secrets": { + "postgres-database": "${dir:state}/database.secret" + }, + "config": { + "callers": { + "type": "list", + "description": "Who may call one of mail-reading's six verbs (entries, groups, correct, lessons, undo, status): a module's name (on every machine), ., or person. (novox/hq ADR 0459 §2). mesh-mail-web alone by default.", + "trusted": true, + "default": ["mesh-mail-web"] + } + }, + "tools": [ + "mail-reading.entries", + "mail-reading.groups", + "mail-reading.correct", + "mail-reading.lessons", + "mail-reading.undo", + "mail-reading.status", + "mail_reader_health" + ], + "runtime-health": { + "kind": "tool", + "tool": "mail_reader_health", + "interval": "60s", + "timeout": "10s", + "looks": 2, + "grace": "60s" + }, + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-mail-reader", + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-mail-reader", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-mail-reader" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-mail-reader", + "place": ".", + "unknown": "program" + }, + { + "id": "callers", + "trusted": true, + "type": "file", + "path": "${dir:state}/callers.json", + "mode": "0600", + "owner": "mesh-mail-reader", + "merge": "json", + "template": "files/callers.json", + "takes-config": ["callers"] + }, + { + "id": "database-url", + "type": "file", + "path": "${dir:state}/database.url", + "mode": "0600", + "owner": "mesh-mail-reader", + "template": "files/database-url" + }, + { + "id": "prepare", + "type": "process", + "name": "mesh-mail-reader-prepare", + "artifact": "tools", + "run": [ + "./mesh-mail-reader", + "prepare" + ], + "run-once": true, + "env": { + "DATABASE_URL_FILE": "${dir:state}/database.url" + }, + "restart-on": [ + "database-url" + ] + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-mail-reader", + "binary": "mesh-mail-reader", + "loads": [ + "mesh-mail-reader" + ], + "env": { + "DATABASE_URL_FILE": "${dir:state}/database.url", + "MESH_MAIL_READER_CALLERS": "${dir:state}/callers.json" + } + }, + { + "name": "files", + "kind": "archive", + "from": "files" + } + ] + } +} diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-mail-web/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-mail-web/module.json.captured index fd92839..c6c0d3d 100644 --- a/go/testdata/beside/mesh-catalog/modules/mesh-mail-web/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/mesh-mail-web/module.json.captured @@ -15,7 +15,13 @@ "seat:mail-store.search", "seat:mail-store.read", "seat:mail-store.send", - "seat:mail-store.send-status" + "seat:mail-store.send-status", + "seat:mail-reading.entries", + "seat:mail-reading.groups", + "seat:mail-reading.status", + "seat:mail-reading.correct", + "seat:mail-reading.lessons", + "seat:mail-reading.undo" ], "reads": ["mesh-mail.accounts"], "requires": ["route", "oidc-client"], diff --git a/go/testdata/beside/mesh-catalog/modules/mesh-mail/module.json.captured b/go/testdata/beside/mesh-catalog/modules/mesh-mail/module.json.captured index 1eba0cf..735fbc5 100644 --- a/go/testdata/beside/mesh-catalog/modules/mesh-mail/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/mesh-mail/module.json.captured @@ -18,6 +18,11 @@ "scope": "node", "needs": ["node-notifier"], "serves": ["status"] + }, + { + "name": "mail-reading", + "scope": "mesh", + "serves": ["entries", "groups", "correct", "lessons", "undo", "status"] } ], "claims": [ diff --git a/go/testdata/beside/mesh-catalog/modules/messenger/files/settings.json b/go/testdata/beside/mesh-catalog/modules/messenger/files/settings.json index ce76334..6d22854 100644 --- a/go/testdata/beside/mesh-catalog/modules/messenger/files/settings.json +++ b/go/testdata/beside/mesh-catalog/modules/messenger/files/settings.json @@ -1,4 +1,5 @@ { "time-zone": "", - "only-what-needs-me": [] + "only-what-needs-me": [], + "messages-per-hour": 100 } diff --git a/go/testdata/beside/mesh-catalog/modules/messenger/module.json.captured b/go/testdata/beside/mesh-catalog/modules/messenger/module.json.captured index 8501bd4..6045195 100644 --- a/go/testdata/beside/mesh-catalog/modules/messenger/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/messenger/module.json.captured @@ -132,6 +132,14 @@ "description": "The kinds of channel set to say only what needs the operator: a walk that delivered with nothing held and nothing open is not told there (ADR 0308 §4); empty is none.", "trusted": true, "default": [] + }, + "messages-per-hour": { + "type": "number", + "description": "messages per channel per hour before the rest are held as one; 0 turns the pause off. The tell verb has its own cap of 10 and is not counted here.", + "minimum": 0, + "maximum": 1000, + "trusted": false, + "default": 100 } }, "resources": [ @@ -155,7 +163,7 @@ "type": "file", "path": "${dir:state}/settings.json", "mode": "0600", - "takes-config": ["time-zone", "desktop-machines", "only-what-needs-me"], + "takes-config": ["time-zone", "desktop-machines", "only-what-needs-me", "messages-per-hour"], "merge": "json", "template": "files/settings.json", "owner": "messenger" diff --git a/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.service b/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.service new file mode 100644 index 0000000..69741dd --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.service @@ -0,0 +1,12 @@ +# Generated by the mesh. Do not edit — module pacman writes this file and replaces it at every push. +[Unit] +Description=Weekly full upgrade (the mesh's pacman module, ADR 0477) +Wants=network-online.target +After=network-online.target + +[Service] +# The upgrade pacman_upgrade runs (pacman -Syu --noconfirm), as a oneshot whose result is the module's health +# (pacman_upgrade_health). The mesh restarts no machine for an upgrade: a new kernel waits for the next restart. +Type=oneshot +Nice=10 +ExecStart=/usr/bin/pacman -Syu --noconfirm diff --git a/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.timer b/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.timer new file mode 100644 index 0000000..a8a9b4d --- /dev/null +++ b/go/testdata/beside/mesh-catalog/modules/pacman/files/mesh-pacman-weekly-upgrade.timer @@ -0,0 +1,11 @@ +# Generated by the mesh. Do not edit — module pacman writes this file and replaces it at every push. +[Unit] +Description=Weekly full upgrade, Saturday 04:00 local time on every node (the mesh's pacman module, ADR 0477) + +[Timer] +# The same moment on every node: no random delay. A node that was off or asleep then upgrades at its next start. +OnCalendar=Sat *-*-* 04:00:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/go/testdata/beside/mesh-catalog/modules/pacman/module.json.captured b/go/testdata/beside/mesh-catalog/modules/pacman/module.json.captured index 746c8c5..ca1a81a 100644 --- a/go/testdata/beside/mesh-catalog/modules/pacman/module.json.captured +++ b/go/testdata/beside/mesh-catalog/modules/pacman/module.json.captured @@ -19,6 +19,7 @@ "pacman_files", "pacman_updates", "pacman_upgrade", + "pacman_upgrade_health", "pacman_orphans", "pacman_remove_orphans", "pacman_cache", @@ -63,14 +64,53 @@ "type": "service", "unit": "reflector.timer", "state": "running", - "boot": "enabled" + "boot": "enabled", + "health": { + "kind": "unit" + } }, { "id": "cache-cleaning", "type": "service", "unit": "paccache.timer", "state": "running", - "boot": "enabled" + "boot": "enabled", + "health": { + "kind": "unit" + } + }, + { + "id": "upgrade-service", + "type": "file", + "path": "/etc/systemd/system/mesh-pacman-weekly-upgrade.service", + "mode": "0644", + "template": "files/mesh-pacman-weekly-upgrade.service" + }, + { + "id": "upgrade-timer", + "type": "file", + "path": "/etc/systemd/system/mesh-pacman-weekly-upgrade.timer", + "mode": "0644", + "template": "files/mesh-pacman-weekly-upgrade.timer" + }, + { + "id": "weekly-upgrade", + "type": "service", + "unit": "mesh-pacman-weekly-upgrade.timer", + "state": "running", + "boot": "enabled", + "restart-on": [ + "upgrade-service", + "upgrade-timer" + ], + "health": { + "kind": "tool", + "tool": "pacman_upgrade_health", + "interval": "60s", + "timeout": "20s", + "looks": 2, + "grace": "60s" + } } ], "build": { diff --git a/go/testdata/beside/mesh-catalog/modules/power/files/bin/power-moment b/go/testdata/beside/mesh-catalog/modules/power/files/bin/power-moment old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/dmenu b/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/dmenu old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-launch b/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-launch old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-powermenu b/go/testdata/beside/mesh-catalog/modules/rofi/files/bin/rofi-powermenu old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/screen-lock/files/bin/screen-lock b/go/testdata/beside/mesh-catalog/modules/screen-lock/files/bin/screen-lock old mode 100644 new mode 100755 diff --git a/go/testdata/beside/mesh-catalog/modules/xorg/files/xinitrc b/go/testdata/beside/mesh-catalog/modules/xorg/files/xinitrc old mode 100644 new mode 100755 From ddfa1197209b02a5358e9fea605f722f7d9fe458 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 21 Oct 2026 12:45:04 +0200 Subject: [PATCH 3/3] Cite ADR 0478's accepted clause numbers --- go/delivery/buildrecord.go | 2 +- go/delivery/source.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/delivery/buildrecord.go b/go/delivery/buildrecord.go index d3f9fb9..1bccc22 100644 --- a/go/delivery/buildrecord.go +++ b/go/delivery/buildrecord.go @@ -25,7 +25,7 @@ type BuildRecord struct { } // Artifact is one thing a build made: mesh-controller internal/chain/records.go Artifact, json keys name, kind and -// reference, nothing else (novox/hq ADR 0478 clause 7). +// reference, nothing else (novox/hq ADR 0478 clause 8). type Artifact struct { Name string `json:"name"` Kind string `json:"kind"` diff --git a/go/delivery/source.go b/go/delivery/source.go index e82ce1d..8d85b64 100644 --- a/go/delivery/source.go +++ b/go/delivery/source.go @@ -390,7 +390,7 @@ type Module struct { Repository string `json:"repository"` Commit string `json:"commit"` // Path is the module's directory in its repository, trimmed of slashes, and RootPath (".") when its manifest is the - // repository's root (novox/hq ADR 0478 clause 8, issue 1615): the build tools need it. Empty means not known: a value + // repository's root (novox/hq ADR 0478 clause 9, issue 1615): the build tools need it. Empty means not known: a value // written before the indexer learned paths has none. Path string `json:"path,omitempty"` // Toolchains are the toolchains FP2 was computed with, by language (go, typescript): the version installed and the