From 3f05df5d1ac9d06e09e6752113555ec7417a6767 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 29 Oct 2026 22:19:39 +0100 Subject: [PATCH 1/4] Pin mesh-sdk 2e5cc4f, so the controller reads the release's new manifest words (issue 774) The controller on dbcaa29 parses manifests strictly and refuses `bus` on an artifact and `max-age-days` on a log, both in the re-land group's catalogue. The SDK's conformance events are captured again at the pinned commit, as testdata/beside/CAPTURED asks; they are unchanged. --- go.mod | 2 +- go.sum | 4 ++-- testdata/beside/CAPTURED | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 13af4240..70953c5c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/novox/mesh-controller go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029145421-dbcaa29a1a38 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635 github.com/jackc/pgx/v5 v5.10.0 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/go.sum b/go.sum index 7acf1f03..2b4b9568 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5 h1:E5stfIeCN6uYgA9TCv+4K8JgaURg3zQppvUgJLaDMP4= git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5/go.mod h1:4wyoCr6IIIIarEUuROThWDj7DAvJvIidqMjWcpSnOwE= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029145421-dbcaa29a1a38 h1:gJwMmK8isI9HwFM2WOCZXjiTqZmGQxs2UY38stk1ZOA= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029145421-dbcaa29a1a38/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635 h1:ImOyj4WqH9lwxOr95aH9Wq2iJkUwdtnEyPrASm9TrYA= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/testdata/beside/CAPTURED b/testdata/beside/CAPTURED index e86ebfe6..edfdb984 100644 --- a/testdata/beside/CAPTURED +++ b/testdata/beside/CAPTURED @@ -9,7 +9,7 @@ a second place to clean besides the catalogue itself. mesh-catalog 3a1017f5594217092a654dd1e2d72226766bc16a modules/*/module.json, modules/*/files, modules/*/templates, predefined.json mesh-host 9d9e3a46c4f5943cfffb413d962ce48b75e2fd39 examples/foundation-first-node.lock -mesh-sdk dbcaa29a1a386c5b6f9e45f0f19fb493ca3a89f2 conformance/events/module-event.json +mesh-sdk 2e5cc4f16635a1705596be9b9c6b61d5050a424b conformance/events/module-event.json To move them, from this repository's root, with the two repositories checked out beside it: -- 2.54.0 From 816cf9645969199226a05807ed900aa3788b458b Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 00:07:04 +0100 Subject: [PATCH 2/4] Pin mesh-sdk 007b6fd, the release's final sdk, so the controller reads the release's manifests and composes as the group does (issue 774) The sdk now refuses an offer that says no credential form (6b8c694, ADR 0570). So: - the catalogue copy in testdata/beside is captured again at the release branch's catalogue 8ae8e88d, whose offers each say one, and the sdk's conformance events at 007b6fd, as CAPTURED asks; - the fixtures of identity_bound_test and issued_test say the form their rows meant: pair for a login of each consumer's own, none for a keyless provision. No behaviour of the controller changed. --- cmd/mesh-controller/identity_bound_test.go | 4 +- cmd/mesh-controller/issued_test.go | 9 +- go.mod | 2 +- go.sum | 4 +- testdata/beside/CAPTURED | 4 +- .../artifact-store-tools/files/store-address | 1 + .../artifact-store-tools/module.json.captured | 57 ++++++++--- .../modules/buildah/module.json.captured | 5 +- .../modules/disk-load/module.json.captured | 17 +++- .../modules/distribution/module.json.captured | 5 +- .../modules/dnsmasq/files/mesh.conf | 11 ++- .../modules/dnsmasq/module.json.captured | 5 +- .../modules/docker/module.json.captured | 2 +- .../modules/gitea/module.json.captured | 21 ++++- .../modules/go/module.json.captured | 5 +- .../modules/influxdb/module.json.captured | 3 + .../modules/kernel/files/modules-load.conf | 4 + .../modules/kernel/module.json.captured | 19 ++++ .../modules/keycloak/module.json.captured | 4 +- .../modules/mailu/module.json.captured | 12 ++- .../modules/mesh-build-go/files/settings.json | 4 +- .../mesh-build-go/module.json.captured | 26 +++-- .../mesh-build-image/files/settings.json | 4 +- .../mesh-build-image/module.json.captured | 23 ++++- .../mesh-build-node/files/settings.json | 4 +- .../mesh-build-node/module.json.captured | 23 ++++- .../modules/mesh-catalog/module.json.captured | 13 ++- .../mesh-conditions/module.json.captured | 87 +++++++++++++++++ .../modules/mesh-config/module.json.captured | 29 +++++- .../mesh-delivery-gate/files/settings.json | 3 +- .../mesh-delivery-gate/module.json.captured | 31 +++++- .../mesh-hand-acts/module.json.captured | 65 +++++++++++++ .../modules/mesh-healers/module.json.captured | 82 ++++++++++++++++ .../modules/mesh-issues/module.json.captured | 25 ++++- .../mesh-knowledge/module.json.captured | 18 +++- .../mesh-provisioner/module.json.captured | 27 +++++- .../mesh-self-check/module.json.captured | 87 +++++++++++++++++ .../modules/mesh-vault/module.json.captured | 43 ++++++++- .../modules/mesh-watcher/module.json.captured | 14 ++- .../modules/messenger/module.json.captured | 9 +- .../modules/minio/module.json.captured | 7 +- .../modules/mongodb/module.json.captured | 3 + .../modules/mosquitto/module.json.captured | 3 + .../modules/mounts/module.json.captured | 30 +++--- .../modules/mssql/module.json.captured | 3 + .../modules/nats/module.json.captured | 33 ++++++- .../modules/nextcloud/module.json.captured | 2 +- .../modules/nfs-server/module.json.captured | 37 ++++---- .../modules/nodejs/module.json.captured | 5 +- .../modules/ollama/module.json.captured | 5 +- .../modules/postgres/module.json.captured | 4 +- .../modules/power/module.json.captured | 42 +++++++++ .../system/halt.target.d/mesh-power.conf | 8 ++ .../system/poweroff.target.d/mesh-power.conf | 8 ++ .../system/reboot.target.d/mesh-power.conf | 8 ++ .../modules/redis/module.json.captured | 3 + .../modules/restic/module.json.captured | 94 ++++++++++--------- .../route-adapter/module.json.captured | 4 +- .../modules/showcase/module.json.captured | 5 +- .../modules/step-ca/module.json.captured | 5 +- .../systemd-resolved/module.json.captured | 5 +- .../modules/umami/module.json.captured | 5 +- .../modules/xorg/module.json.captured | 5 +- 63 files changed, 951 insertions(+), 184 deletions(-) create mode 100644 testdata/beside/mesh-catalog/modules/artifact-store-tools/files/store-address create mode 100644 testdata/beside/mesh-catalog/modules/kernel/files/modules-load.conf create mode 100644 testdata/beside/mesh-catalog/modules/mesh-conditions/module.json.captured create mode 100644 testdata/beside/mesh-catalog/modules/mesh-hand-acts/module.json.captured create mode 100644 testdata/beside/mesh-catalog/modules/mesh-healers/module.json.captured create mode 100644 testdata/beside/mesh-catalog/modules/mesh-self-check/module.json.captured create mode 100644 testdata/beside/mesh-catalog/modules/power/templates/systemd/system/halt.target.d/mesh-power.conf create mode 100644 testdata/beside/mesh-catalog/modules/power/templates/systemd/system/poweroff.target.d/mesh-power.conf create mode 100644 testdata/beside/mesh-catalog/modules/power/templates/systemd/system/reboot.target.d/mesh-power.conf diff --git a/cmd/mesh-controller/identity_bound_test.go b/cmd/mesh-controller/identity_bound_test.go index a3160af9..d8a5e0c9 100644 --- a/cmd/mesh-controller/identity_bound_test.go +++ b/cmd/mesh-controller/identity_bound_test.go @@ -23,10 +23,10 @@ func TestModuleCheckRefusesAnIdentityThatOverflowsWhatItRequires(t *testing.T) { return p } objects := write("objects", `{"module":"objects","version":"1", - "provides":[{"name":"s3-bucket","scope":"mesh","identity":{"max":20,"in":"an S3 access key"}}], + "provides":[{"name":"s3-bucket","scope":"mesh","identity":{"max":20,"in":"an S3 access key"},"credential":{"form":"pair"}}], "receives":{"s3-bucket":"/var/lib/mesh/objects/mesh.json"}}`) resolver := write("resolver", `{"module":"resolver","version":"1", - "provides":[{"name":"wildcard-resolution","scope":"mesh","identity":false}]}`) + "provides":[{"name":"wildcard-resolution","scope":"mesh","identity":false,"credential":{"form":"none"}}]}`) album := write("photoalbum", `{"module":"photoalbum","version":"1","requires":["s3-bucket"]}`) nm := write("networkmanager", `{"module":"networkmanager","version":"1","requires":["wildcard-resolution"]}`) diff --git a/cmd/mesh-controller/issued_test.go b/cmd/mesh-controller/issued_test.go index baa1b90a..48e045bd 100644 --- a/cmd/mesh-controller/issued_test.go +++ b/cmd/mesh-controller/issued_test.go @@ -182,6 +182,9 @@ func TestANeedIsIssuedToItsHolderOnlyWhereTheProviderIsMovedAndItsSoftwareIssues offer := catalogue.Offer{Name: "gitea-read", Scope: catalogue.ScopeMesh} if issued { offer.Credential = &catalogue.OfferCredential{IssuedBy: catalogue.IssuedBySoftware, Tool: "gitea_agent_token"} + } else { + // A login of each consumer's own, said: an offer naming no form has no credential (mesh-sdk 6b8c694). + offer.Credential = &catalogue.OfferCredential{Form: catalogue.CredentialFormPair} } return catalogue.Manifest{Module: "gitea", Version: "1", Moved: moved, Provides: []catalogue.Offer{offer}} } @@ -216,8 +219,10 @@ func TestANeedIsIssuedToItsHolderOnlyWhereTheProviderIsMovedAndItsSoftwareIssues // marked moved; another module is not. func TestTheModuleHoldingTheVaultSeatCountsAsMovedForItsConsumers(t *testing.T) { vault := catalogue.Manifest{Module: "mesh-vault", Version: "1", Claims: []catalogue.Claim{{Name: "mesh-vault", Scope: catalogue.ScopeMesh}}, - Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh}}} - other := catalogue.Manifest{Module: "mesh-vault", Version: "1", Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh}}} + Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh, + Credential: &catalogue.OfferCredential{Form: catalogue.CredentialFormPair}}}} + other := catalogue.Manifest{Module: "mesh-vault", Version: "1", Provides: []catalogue.Offer{{Name: "secret", Scope: catalogue.ScopeMesh, + Credential: &catalogue.OfferCredential{Form: catalogue.CredentialFormPair}}}} if got := needOf(t, map[string]catalogue.Manifest{"mesh-vault": vault}, "mesh-vault", "gitea", "secret"); !got.IssuedToHolder || !got.ProviderMoved { t.Errorf("the vault's consumer is not answered by a moved provider: %+v", got) } diff --git a/go.mod b/go.mod index 70953c5c..6e6167b2 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/novox/mesh-controller go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7 github.com/jackc/pgx/v5 v5.10.0 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/go.sum b/go.sum index 2b4b9568..142c307a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5 h1:E5stfIeCN6uYgA9TCv+4K8JgaURg3zQppvUgJLaDMP4= git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5/go.mod h1:4wyoCr6IIIIarEUuROThWDj7DAvJvIidqMjWcpSnOwE= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635 h1:ImOyj4WqH9lwxOr95aH9Wq2iJkUwdtnEyPrASm9TrYA= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029211750-2e5cc4f16635/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7 h1:9FZLjq5H+FShqsaSvZ5vGGjDFaQkdhGCna6ofiBd+p4= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/testdata/beside/CAPTURED b/testdata/beside/CAPTURED index edfdb984..092e26d9 100644 --- a/testdata/beside/CAPTURED +++ b/testdata/beside/CAPTURED @@ -7,9 +7,9 @@ The copy carries the catalogue's private details: domains, first names in module private addresses. That is acceptable while mesh-controller is private; if it ever goes public, this copy is a second place to clean besides the catalogue itself. -mesh-catalog 3a1017f5594217092a654dd1e2d72226766bc16a modules/*/module.json, modules/*/files, modules/*/templates, predefined.json +mesh-catalog 8ae8e88dddc86c646de4d1be35919d109ab4c779 modules/*/module.json, modules/*/files, modules/*/templates, predefined.json mesh-host 9d9e3a46c4f5943cfffb413d962ce48b75e2fd39 examples/foundation-first-node.lock -mesh-sdk 2e5cc4f16635a1705596be9b9c6b61d5050a424b conformance/events/module-event.json +mesh-sdk 007b6fd45fc7e7bfa93e76f6b9009725f881e29f conformance/events/module-event.json To move them, from this repository's root, with the two repositories checked out beside it: diff --git a/testdata/beside/mesh-catalog/modules/artifact-store-tools/files/store-address b/testdata/beside/mesh-catalog/modules/artifact-store-tools/files/store-address new file mode 100644 index 00000000..1bcadab2 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/artifact-store-tools/files/store-address @@ -0,0 +1 @@ +${seat:mesh-artifact-store:reach} diff --git a/testdata/beside/mesh-catalog/modules/artifact-store-tools/module.json.captured b/testdata/beside/mesh-catalog/modules/artifact-store-tools/module.json.captured index 208329cd..f1ef7a43 100644 --- a/testdata/beside/mesh-catalog/modules/artifact-store-tools/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/artifact-store-tools/module.json.captured @@ -1,26 +1,52 @@ { "module": "artifact-store-tools", "version": "1", + "claims": [ + { + "name": "mesh-artifact-sweep", + "scope": "mesh", + "serves": [ + "artifacts", + "held", + "collect", + "mirrors", + "images" + ] + } + ], + "requires": [ + "artifact-store" + ], "invokes": [ - "seat:mesh-controller.artifacts", - "seat:mesh-controller.collect", + "seat:mesh-hand-acts.hand-act", "mesh-catalog.catalog_modules", "mesh-catalog.catalog_module" ], + "reads": [ + "mesh-delivery-assigner.wants", + "mesh-delivery-builder.builds", + "mesh-delivery-builder.build-log", + "mesh-delivery-indexer.manifests", + "node-engine.have", + "mesh-controller.lease" + ], + "state": [ + "findings" + ], "tools": [ "artifact_store_repositories", "artifact_store_usage", "artifact_store_references", "artifact_store_collect" ], - "config": { - "older-store-names": { - "type": "string", - "description": "The names the artifact store had before, as host names or host:port separated by spaces, or none when it had no other. artifact_store_references reads every definition under these as well as under the store's current name, so an image a definition pins under one is said to be named by a definition (novox/hq issue 323).", - "pattern": "none|[A-Za-z0-9.:-]+( [A-Za-z0-9.:-]+)*", - "default": "none" - } - }, + "config": { + "older-store-names": { + "type": "string", + "description": "The names the artifact store had before, as host names or host:port separated by spaces, or none when it had no other. artifact_store_references reads every definition under these as well as under the store's current name, so an image a definition pins under one is said to be named by a definition (novox/hq issue 323).", + "pattern": "none|[A-Za-z0-9.:-]+( [A-Za-z0-9.:-]+)*", + "default": "none" + } + }, "resources": [ { "id": "state", @@ -36,6 +62,14 @@ "mode": "0600", "trusted": false, "template": "files/store-names" + }, + { + "id": "store-address", + "type": "file", + "path": "${dir:state}/store-address", + "mode": "0600", + "trusted": false, + "template": "files/store-address" } ], "build": { @@ -52,7 +86,8 @@ ], "env": { "MESH_ARTIFACT_STORE_CONTAINER": "mesh-registry", - "MESH_ARTIFACT_STORE_NAMES_FILE": "${dir:state}/store-names" + "MESH_ARTIFACT_STORE_NAMES_FILE": "${dir:state}/store-names", + "MESH_ARTIFACT_STORE_ADDRESS_FILE": "${dir:state}/store-address" } }, { diff --git a/testdata/beside/mesh-catalog/modules/buildah/module.json.captured b/testdata/beside/mesh-catalog/modules/buildah/module.json.captured index 70ddd0a4..bdfbe96b 100644 --- a/testdata/beside/mesh-catalog/modules/buildah/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/buildah/module.json.captured @@ -8,7 +8,10 @@ "provides": [ { "name": "rootless-image-build", - "reach": "machine" + "reach": "machine", + "credential": { + "form": "none" + } } ], "resources": [ diff --git a/testdata/beside/mesh-catalog/modules/disk-load/module.json.captured b/testdata/beside/mesh-catalog/modules/disk-load/module.json.captured index 9b48041d..4b4313ca 100644 --- a/testdata/beside/mesh-catalog/modules/disk-load/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/disk-load/module.json.captured @@ -7,7 +7,9 @@ "disk_filesystems", "disk_folders", "disk_devices", - "cpu_top" + "cpu_top", + "disk_readings", + "disk_measure" ], "build": { "artifacts": [ @@ -23,5 +25,16 @@ ] } ] - } + }, + "state": [ + "readings" + ], + "reads": [ + "mesh-config.resolved", + "mesh-delivery-assigner.placement", + "mesh-delivery-builder.builds", + "mesh-delivery-indexer.manifests", + "mesh-delivery-indexer.modules", + "node-engine.have" + ] } diff --git a/testdata/beside/mesh-catalog/modules/distribution/module.json.captured b/testdata/beside/mesh-catalog/modules/distribution/module.json.captured index eb9f7c24..5037f429 100644 --- a/testdata/beside/mesh-catalog/modules/distribution/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/distribution/module.json.captured @@ -4,7 +4,10 @@ "provides": [ { "name": "artifact-store", - "scope": "mesh" + "scope": "mesh", + "credential": { + "form": "none" + } } ], "claims": [ diff --git a/testdata/beside/mesh-catalog/modules/dnsmasq/files/mesh.conf b/testdata/beside/mesh-catalog/modules/dnsmasq/files/mesh.conf index 96d8d7d6..7f86d122 100644 --- a/testdata/beside/mesh-catalog/modules/dnsmasq/files/mesh.conf +++ b/testdata/beside/mesh-catalog/modules/dnsmasq/files/mesh.conf @@ -1,14 +1,15 @@ # Written by the mesh (module dnsmasq, novox/hq issue 348). Replaced on every push. # # The resolver binds its addresses once, at start (bind-interfaces), so it starts only once this -# machine's private address is there: it waits up to 80 seconds for it, and a start that found it -# missing is tried again every ten seconds rather than left failed. +# machine's private address is there: a start that finds it missing fails after at most two seconds and +# is tried again every ten seconds (Restart=on-failure, no start limit) until the tunnel has brought it. +# It does not order itself After= or Wants= network-online.target, and its wait is short: the packaged +# unit is Before= network-online.target and nss-lookup.target, and the tunnel is ordered after them, so +# a long wait would hold the tunnel back and a drop-in ordering would be a cycle (issue 1126). [Unit] -After=network-online.target -Wants=network-online.target StartLimitIntervalSec=0 [Service] -ExecStartPre=/usr/bin/sh -c 'for i in $(seq 1 80); do ip -4 -o addr show to ${machine:address} | grep -q . && exit 0; sleep 1; done; echo "${machine:address} is not on this machine" >&2; exit 1' +ExecStartPre=/usr/bin/sh -c 'for i in $(seq 1 2); do ip -4 -o addr show to ${machine:address} | grep -q . && exit 0; sleep 1; done; echo "${machine:address} is not on this machine" >&2; exit 1' Restart=on-failure RestartSec=10s diff --git a/testdata/beside/mesh-catalog/modules/dnsmasq/module.json.captured b/testdata/beside/mesh-catalog/modules/dnsmasq/module.json.captured index 58cc0da5..7e832067 100644 --- a/testdata/beside/mesh-catalog/modules/dnsmasq/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/dnsmasq/module.json.captured @@ -9,7 +9,10 @@ { "name": "wildcard-resolution", "scope": "mesh", - "identity": false + "identity": false, + "credential": { + "form": "none" + } } ], "requires": [ diff --git a/testdata/beside/mesh-catalog/modules/docker/module.json.captured b/testdata/beside/mesh-catalog/modules/docker/module.json.captured index fae954c3..500faea6 100644 --- a/testdata/beside/mesh-catalog/modules/docker/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/docker/module.json.captured @@ -7,7 +7,7 @@ "privileged" ], "invokes": [ - "seat:mesh-controller.images" + "seat:mesh-artifact-sweep.images" ], "claims": [ { diff --git a/testdata/beside/mesh-catalog/modules/gitea/module.json.captured b/testdata/beside/mesh-catalog/modules/gitea/module.json.captured index 1ac1aeb8..69b88adb 100644 --- a/testdata/beside/mesh-catalog/modules/gitea/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/gitea/module.json.captured @@ -40,6 +40,7 @@ ], "emits": [ "repo.created", + "repo.writable", "issue.opened", "pull.merged", "pull.updated", @@ -181,6 +182,12 @@ "trusted": true, "default": {} }, + "check-gates-merge": { + "type": "boolean", + "description": "Whether gitea_merge_pull_request judges mesh/check before it merges. True (the default): a head merges only on a passing mesh/check judged against the trunk's head (ADR 0447, ADR 0534 §4). False (the operator, 2026-10-25 22:56: \"run the check locally only, but not as a gate, it loses us too much time\"): a head the operator's Approve names in approved_heads merges whatever its mesh/check says (pending, failed, missing or judged on an older trunk); a head that moved, a branch no rule guards and a merge git refuses are still refused. Set together with mesh-delivery-gate's check-gates-merge.", + "trusted": true, + "default": true + }, "main-mergers": { "type": "list", "description": "The forge logins that may merge into main beside the tools' account, on every repository of the organisation (ADR 0534 §2): the operator's own, so the operator can always merge by hand at the forge. The tools' account is always on main's merge whitelist; no agent's account belongs here.", @@ -316,7 +323,8 @@ "takes-config": [ "url", "keep-main-rules", - "main-mergers" + "main-mergers", + "check-gates-merge" ] }, { @@ -391,6 +399,7 @@ "provides": [ { "name": "npm-package-registry", + "credential": {"form": "pair"}, "scope": "mesh", "identity": { "max": 40, @@ -399,6 +408,7 @@ }, { "name": "git", + "credential": {"form": "none"}, "scope": "mesh" }, { @@ -411,6 +421,7 @@ }, { "name": "forge-account", + "credential": {"form": "none"}, "scope": "mesh" } ], @@ -537,6 +548,7 @@ "MESH_GITEA_ADMIN_PASSWORD_FILE": "${dir:state}/admin.secret", "MESH_GITEA_ORIGINS_FILE": "${dir:mesh-state}/origins", "MESH_GITEA_SSH_PORT": "222", + "MESH_GITEA_HOST_KEY_FILE": "${dir:data}/ssh/ssh_host_ed25519_key.pub", "MESH_FORGE_HOST_FILE": "/etc/gitea/forge-host" } } @@ -554,11 +566,14 @@ "announced" ], "reads": [ - "mesh-controller.assignments", + "mesh-provisioner.plans", + "mesh-provisioner.provisions", "ssh-client.keys", "mesh-build-go.keys", "mesh-build-node.keys", "mesh-build-image.keys", - "mesh-delivery-checker.owed" + "mesh-delivery-checker.owed", + "mesh-delivery-indexer.modules", + "mesh-delivery-gate.source" ] } diff --git a/testdata/beside/mesh-catalog/modules/go/module.json.captured b/testdata/beside/mesh-catalog/modules/go/module.json.captured index 48a6bf57..9783eda4 100644 --- a/testdata/beside/mesh-catalog/modules/go/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/go/module.json.captured @@ -7,7 +7,10 @@ "provides": [ { "name": "go-toolchain", - "reach": "machine" + "reach": "machine", + "credential": { + "form": "none" + } } ], "resources": [ diff --git a/testdata/beside/mesh-catalog/modules/influxdb/module.json.captured b/testdata/beside/mesh-catalog/modules/influxdb/module.json.captured index 53389a5f..13a7905f 100644 --- a/testdata/beside/mesh-catalog/modules/influxdb/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/influxdb/module.json.captured @@ -7,6 +7,9 @@ "scope": "mesh", "identity": { "in": "an InfluxDB v1 authorization" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/kernel/files/modules-load.conf b/testdata/beside/mesh-catalog/modules/kernel/files/modules-load.conf new file mode 100644 index 00000000..eccad6ce --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/kernel/files/modules-load.conf @@ -0,0 +1,4 @@ +# Written by the mesh's kernel module (systemd-modules-load reads it at boot). +# tun: buildah's network for a RUN line (pasta) and every other user-space tunnel open /dev/net/tun. +# Loaded at boot, so an upgrade that removes the running kernel's modules cannot keep it out later. +tun diff --git a/testdata/beside/mesh-catalog/modules/kernel/module.json.captured b/testdata/beside/mesh-catalog/modules/kernel/module.json.captured index 2a63563e..8fc90d09 100644 --- a/testdata/beside/mesh-catalog/modules/kernel/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/kernel/module.json.captured @@ -100,6 +100,25 @@ "id": "linux-lts-headers", "type": "package", "package": "linux-lts-headers" + }, + { + "id": "modules-load", + "type": "file", + "path": "/etc/modules-load.d/mesh-kernel.conf", + "mode": "0644", + "template": "files/modules-load.conf" + }, + { + "id": "modules-keep", + "type": "package", + "package": "kernel-modules-hook" + }, + { + "id": "modules-cleanup", + "type": "service", + "unit": "linux-modules-cleanup.service", + "state": "stopped", + "boot": "enabled" } ], "build": { diff --git a/testdata/beside/mesh-catalog/modules/keycloak/module.json.captured b/testdata/beside/mesh-catalog/modules/keycloak/module.json.captured index 847d5f4f..84c08f10 100644 --- a/testdata/beside/mesh-catalog/modules/keycloak/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/keycloak/module.json.captured @@ -9,6 +9,7 @@ "provides": [ { "name": "oidc-client", + "credential": {"form": "pair"}, "scope": "mesh", "identity": { "max": 255, @@ -240,6 +241,7 @@ "bound" ], "reads": [ - "mesh-controller.assignments" + "mesh-provisioner.plans", + "mesh-provisioner.provisions" ] } diff --git a/testdata/beside/mesh-catalog/modules/mailu/module.json.captured b/testdata/beside/mesh-catalog/modules/mailu/module.json.captured index 93d72adb..0faccc58 100644 --- a/testdata/beside/mesh-catalog/modules/mailu/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mailu/module.json.captured @@ -665,7 +665,14 @@ "path": "${dir:mesh-state}/config.json", "mode": "0600", "template": "files/config.json", - "takes-config": ["domain", "proxy-address", "sitename", "website", "url", "container"], + "takes-config": [ + "domain", + "proxy-address", + "sitename", + "website", + "url", + "container" + ], "merge": "json" }, { @@ -758,6 +765,9 @@ "identity": { "max": 64, "in": "a mailbox's local part" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-go/files/settings.json b/testdata/beside/mesh-catalog/modules/mesh-build-go/files/settings.json index 3175fe39..3b65dd1c 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-go/files/settings.json +++ b/testdata/beside/mesh-catalog/modules/mesh-build-go/files/settings.json @@ -1,3 +1,5 @@ { - "capacity": "shanks=3,ace=2,g14=0,novox=0" + "capacity": 0, + "cores-per-step": 6, + "build-hours": "" } diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured index 4d2b080a..88fbba9b 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-build-go/module.json.captured @@ -10,7 +10,7 @@ "state": [ "toolchains", "keys", - "steps" + {"name": "steps", "ttl-seconds": 172800}, "pauses" ], "claims": [ { @@ -20,14 +20,27 @@ } ], "reads": [ - "mesh-delivery-checker.kept" + "mesh-delivery-checker.kept", + "mesh-delivery-indexer.manifests" ], "config": { "capacity": { + "type": "number", + "description": "How many asks of the Go build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.", + "minimum": 0, + "default": 0 + }, + "build-hours": { "type": "string", - "description": "How many asks of the Go build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.", - "pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*", - "default": "shanks=3,ace=2,g14=0,novox=0" + "description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.", + "pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]", + "default": "" + }, + "cores-per-step": { + "type": "number", + "description": "How many processors one Go step of this module needs (a full check of a large repository takes what it is given: three at about 4 cores each ran past the 30-minute step bound on 2026-10-26). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.", + "minimum": 0.1, + "default": 6 } }, "tools": [ @@ -38,6 +51,7 @@ "build_go_release", "build_go_step", "build_go_steps", + "build_go_step_end", "build_go_toolchains", "build_go_status", "build_go_health" @@ -105,7 +119,7 @@ "path": "${dir:state}/settings.json", "mode": "0600", "owner": "mesh-build-go", - "takes-config": ["capacity"], + "takes-config": ["capacity", "cores-per-step", "build-hours"], "merge": "json", "template": "files/settings.json" }, diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-image/files/settings.json b/testdata/beside/mesh-catalog/modules/mesh-build-image/files/settings.json index 3175fe39..4a445c34 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-image/files/settings.json +++ b/testdata/beside/mesh-catalog/modules/mesh-build-image/files/settings.json @@ -1,3 +1,5 @@ { - "capacity": "shanks=3,ace=2,g14=0,novox=0" + "capacity": 0, + "cores-per-step": 2, + "build-hours": "" } diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-image/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-build-image/module.json.captured index cfe8489f..54bc2fb0 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-image/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-build-image/module.json.captured @@ -9,7 +9,7 @@ ], "state": [ "keys", - "steps" + {"name": "steps", "ttl-seconds": 172800}, "pauses" ], "claims": [ { @@ -20,10 +20,22 @@ ], "config": { "capacity": { + "type": "number", + "description": "How many asks of the image build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.", + "minimum": 0, + "default": 0 + }, + "build-hours": { "type": "string", - "description": "How many asks of the image build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.", - "pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*", - "default": "shanks=3,ace=2,g14=0,novox=0" + "description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.", + "pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]", + "default": "" + }, + "cores-per-step": { + "type": "number", + "description": "How many processors one image step of this module needs (buildah, whose RUN lines are mostly fetches). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.", + "minimum": 0.1, + "default": 2 } }, "tools": [ @@ -33,6 +45,7 @@ "build_image_release", "build_image_step", "build_image_steps", + "build_image_step_end", "build_image_status", "build_image_health" ], @@ -77,7 +90,7 @@ "path": "${dir:state}/settings.json", "mode": "0600", "owner": "mesh-build-image", - "takes-config": ["capacity"], + "takes-config": ["capacity", "cores-per-step", "build-hours"], "merge": "json", "template": "files/settings.json" }, diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-node/files/settings.json b/testdata/beside/mesh-catalog/modules/mesh-build-node/files/settings.json index 3175fe39..4a445c34 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-node/files/settings.json +++ b/testdata/beside/mesh-catalog/modules/mesh-build-node/files/settings.json @@ -1,3 +1,5 @@ { - "capacity": "shanks=3,ace=2,g14=0,novox=0" + "capacity": 0, + "cores-per-step": 2, + "build-hours": "" } diff --git a/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured index 25f858eb..25f8611b 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-build-node/module.json.captured @@ -10,7 +10,7 @@ "state": [ "toolchains", "keys", - "steps" + {"name": "steps", "ttl-seconds": 172800}, "pauses" ], "claims": [ { @@ -21,10 +21,22 @@ ], "config": { "capacity": { + "type": "number", + "description": "How many asks of the Node build seat this module runs at once on this node (novox/hq ADR 0525 §5); 0 pulls nothing. It is set per node in the mesh's configuration; a node with no value builds nothing.", + "minimum": 0, + "default": 0 + }, + "build-hours": { "type": "string", - "description": "How many asks of the Node build seat this module runs at once on each node, as node=asks pairs separated by commas, such as shanks=3,ace=2 (novox/hq ADR 0525 §5); a node set to 0 pulls nothing, a node not named runs one at a time. The control-node and the laptop build nothing.", - "pattern": "|[a-z0-9_-]+=[0-9]+(,[a-z0-9_-]+=[0-9]+)*", - "default": "shanks=3,ace=2,g14=0,novox=0" + "description": "When this node may take this module's build asks: one window HH:MM-HH:MM in the node's local time (an end before its start crosses midnight, 18:00-06:00). Outside it the node takes no new step and finishes the ones it runs; an empty value builds at any hour. It is set per node in the mesh's configuration.", + "pattern": "|([01][0-9]|2[0-3]):[0-5][0-9]-([01][0-9]|2[0-3]):[0-5][0-9]", + "default": "" + }, + "cores-per-step": { + "type": "number", + "description": "How many processors one Node step of this module needs (tsc, esbuild and a test runner; a median step takes 15 s). The capacity above is an upper bound: on each node the module runs at most floor(the cores of its build slice's CPU quota / this) steps at once, the quota read live from its cgroup (issue 1806), so a lowered build CPU share never starves its steps. Above 0.", + "minimum": 0.1, + "default": 2 } }, "tools": [ @@ -34,6 +46,7 @@ "build_node_release", "build_node_step", "build_node_steps", + "build_node_step_end", "build_node_toolchains", "build_node_status", "build_node_health" @@ -99,7 +112,7 @@ "path": "${dir:state}/settings.json", "mode": "0600", "owner": "mesh-build-node", - "takes-config": ["capacity"], + "takes-config": ["capacity", "cores-per-step", "build-hours"], "merge": "json", "template": "files/settings.json" }, diff --git a/testdata/beside/mesh-catalog/modules/mesh-catalog/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-catalog/module.json.captured index b8f45096..c5ad61a4 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-catalog/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-catalog/module.json.captured @@ -25,9 +25,7 @@ "secrets": { "postgres-database": "${dir:state}/database.secret" }, - "consumes": [ - "mesh-controller.built-before" - ], + "consumes": [], "emits": [ "registered", "upgraded", @@ -92,5 +90,12 @@ "from": "files" } ] - } + }, + "invokes": [ + "mesh-delivery-builder.builder_builds_since" + ], + "reads": [ + "mesh-delivery-builder.builds", + "mesh-delivery-indexer.manifests" + ] } diff --git a/testdata/beside/mesh-catalog/modules/mesh-conditions/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-conditions/module.json.captured new file mode 100644 index 00000000..d676b3cf --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/mesh-conditions/module.json.captured @@ -0,0 +1,87 @@ +{ + "module": "mesh-conditions", + "version": "1", + "runs-as": "mesh-conditions", + "claims": [ + { + "name": "mesh-conditions", + "scope": "mesh", + "serves": [ + "conditions", + "silence", + "compare", + "take-over", + "hand-back", + "resync" + ] + } + ], + "uses": [ + "operator-channel" + ], + "reads": [ + "mesh-delivery-watchman.findings", + "mesh-self-check.findings", + "mesh-healers.findings", + "mesh-delivery-assigner.findings", + "messenger.findings", + "mesh-provisioner.findings", + "artifact-store-tools.findings", + "mesh-healers.attempts", + "mesh-controller.conditions", + "mesh-controller.lease", + "mesh-delivery-assigner.wants", + "node-engine.have", + "mesh-delivery-assigner.placement" + ], + "state": [ + "conditions", + { + "name": "history", + "ttl-seconds": 7776000 + }, + "takeover", + "held", + { + "name": "bounds", + "key-ttl": true + }, + "asked" + ], + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-conditions", + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-conditions", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-conditions" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-conditions", + "place": ".", + "unknown": "program" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-conditions", + "binary": "mesh-conditions", + "loads": [ + "mesh-conditions" + ] + } + ] + } +} diff --git a/testdata/beside/mesh-catalog/modules/mesh-config/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-config/module.json.captured index f93497e1..9554db29 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-config/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-config/module.json.captured @@ -7,7 +7,10 @@ "name": "mesh-config", "scope": "mesh", "serves": [ - "config" + "config", + "compare", + "take-over", + "hand-back" ] } ], @@ -23,14 +26,30 @@ "gitea.forge.pull-request.closed" ], "invokes": [ + "seat:mesh-hand-acts.hand-act", + "seat:mesh-hand-acts.warranted", "seat:mesh-controller.hand-act", "seat:mesh-controller.warranted", "gitea.gitea_get_pull_request" ], "reads": [ - "mesh-controller.assignments", + "mesh-delivery-assigner.placement", + "mesh-delivery-assigner.wants", + "mesh-delivery-builder.builds", + "mesh-delivery-indexer.modules", + "mesh-delivery-indexer.manifests", + "mesh-controller.predefined", "mesh-controller.declared-config", - "mesh-controller.predefined" + "mesh-delivery-indexer.predefined", + "mesh-delivery-indexer.config-candidates", + "mesh-controller.lease" + ], + "tools": [ + "config_compare", + "config_take_over", + "config_hand_back", + "config_declared", + "config_resync" ], "state": [ "values", @@ -38,7 +57,9 @@ "predefined", "proposals", "pulls", - "kept" + "kept", + "declared", + "takeover" ], "logs": [ "history" diff --git a/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/files/settings.json b/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/files/settings.json index 848f5158..66c66f87 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/files/settings.json +++ b/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/files/settings.json @@ -1,4 +1,5 @@ { "refusal-stall-floor-minutes": 10, - "author-new-head-minutes": 120 + "author-new-head-minutes": 120, + "check-gates-merge": true } diff --git a/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/module.json.captured index 74da6dc0..ef5d1b80 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-delivery-gate/module.json.captured @@ -14,7 +14,8 @@ "table", "stalled", "recheck", - "close" + "close", + "settle" ] } ], @@ -26,13 +27,17 @@ "gitea.forge.pull-request.edited", "gitea.forge.pull-request.closed", "mesh-delivery-forge-bridge.forge.**", - "mesh-config.config-changed" + "mesh-config.config-changed", + "gitea.repo.writable" ], "emits": [ "transition", "group", "merged" ], + "uses": [ + "operator-channel" + ], "invokes": [ "gitea.gitea_commit_statuses", "gitea.gitea_contains", @@ -57,14 +62,23 @@ { "name": "source", "history": 64 + }, + "conditions", + { + "name": "turns", + "history": 5 } ], "reads": [ "mesh-delivery-teller.answers", - "mesh-delivery-checker.verdicts" + "mesh-delivery-checker.verdicts", + "mesh-delivery-view.reach" ], "tools": [ - "delivery_status" + "delivery_hand_now", + "delivery_merge_again", + "delivery_status", + "delivery_turns" ], "config": { "refusal-stall-floor-minutes": { @@ -82,6 +96,12 @@ "maximum": 10080, "trusted": false, "default": 120 + }, + "check-gates-merge": { + "type": "boolean", + "description": "Whether mesh/check gates the merge. True (the default): the operator's Approve is asked, and a merge handed, only on a passing verdict judged against the trunk's head, and a trunk's move puts a verdict out of date (ADR 0447, ADR 0505 §4). False (the operator, 2026-10-25 22:56: \"run the check locally only, but not as a gate, it loses us too much time\"; developers run the unit and integration levels locally before a pull request): a pull request reviewed at its head is ready, and its Approve is asked once the check at its heads (a group: of all its heads together) has a verdict, a pass or a failure said in the ask, or after 60 minutes with none, said so (the operator, 2026-10-27 23:54: \"if you don't want me to approve it, don't send the approval request\"); an approved merge waits for no verdict; no merge is refused for a check judged on an older trunk; a later verdict is shown on the pull request and the delivery, and asks a pending Approve again in its words; a group still merges all its members in one pass. Set it false together with the gitea module's check-gates-merge, which lets its merge tool merge an approved head without a passing mesh/check.", + "trusted": false, + "default": true } }, "resources": [ @@ -99,7 +119,8 @@ "mode": "0600", "takes-config": [ "refusal-stall-floor-minutes", - "author-new-head-minutes" + "author-new-head-minutes", + "check-gates-merge" ], "merge": "json", "template": "files/settings.json" diff --git a/testdata/beside/mesh-catalog/modules/mesh-hand-acts/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-hand-acts/module.json.captured new file mode 100644 index 00000000..96aff8b1 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/mesh-hand-acts/module.json.captured @@ -0,0 +1,65 @@ +{ + "module": "mesh-hand-acts", + "version": "1", + "runs-as": "mesh-hand-acts", + "claims": [ + { + "name": "mesh-hand-acts", + "scope": "mesh", + "serves": [ + "hand-act", + "hand-acts", + "warranted" + ] + } + ], + "reads": [ + "mesh-controller.hand-acts", + "messenger.asks" + ], + "logs": [ + { + "name": "acts", + "max-age-days": 400 + } + ], + "state": [ + "warrants" + ], + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-hand-acts", + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-hand-acts", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-hand-acts" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-hand-acts", + "place": ".", + "unknown": "program" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-hand-acts", + "binary": "mesh-hand-acts", + "loads": [ + "mesh-hand-acts" + ] + } + ] + } +} diff --git a/testdata/beside/mesh-catalog/modules/mesh-healers/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-healers/module.json.captured new file mode 100644 index 00000000..634dd388 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/mesh-healers/module.json.captured @@ -0,0 +1,82 @@ +{ + "module": "mesh-healers", + "version": "1", + "runs-as": "mesh-healers", + "claims": [ + { + "name": "mesh-healers", + "scope": "mesh", + "serves": [ + "healers", + "heal", + "drill" + ] + } + ], + "consumes": [ + "mesh-conditions.condition-raised", + "mesh-conditions.condition-changed", + "mesh-hand-acts.act-recorded" + ], + "invokes": [ + "mesh-grants.grants_assert", + "seat:mesh-hand-acts.hand-act", + "seat:mesh-controller.drill" + ], + "reads": [ + "mesh-controller.lease", + "mesh-conditions.conditions", + "mesh-controller.hand-acts" + ], + "state": [ + { + "name": "attempts", + "key-ttl": true + }, + { + "name": "would", + "key-ttl": true + }, + "findings", + { + "name": "wakes", + "key-ttl": true + } + ], + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-healers", + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-healers", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-healers" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-healers", + "place": ".", + "unknown": "program" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-healers", + "binary": "mesh-healers", + "loads": [ + "mesh-healers" + ] + } + ] + } +} diff --git a/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured index ee14150a..d359bda2 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured @@ -13,12 +13,17 @@ "move", "note", "link", + "milestones", + "milestone-set", + "milestone-move", "import", "groom", "set", "tracking", "reserve", - "fix-times" + "fix-times", + "learn-fixes", + "changes" ] } ], @@ -33,12 +38,17 @@ "move", "note", "link", + "milestones", + "milestone-set", + "milestone-move", "import", "groom", "set", "tracking", "reserve", - "fix-times" + "fix-times", + "learn-fixes", + "changes" ] } ], @@ -52,7 +62,9 @@ "triaged", "ready", "ready-to-verify", - "reserved" + "reserved", + "milestone-set", + "milestone-moved" ], "consumes": [ "mesh-issues.opened", @@ -66,6 +78,7 @@ "seat:operator-channel.notify", "gitea.gitea_pull_reviews", "gitea.gitea_contains", + "gitea.gitea_get_pull_request", "records.records_status", "records.records_list", "records.records_read", @@ -81,7 +94,11 @@ }, "counters", "grooming", - "reservations" + "reservations", + { + "name": "milestones", + "history": 5 + } ], "config": { "first-number": { diff --git a/testdata/beside/mesh-catalog/modules/mesh-knowledge/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-knowledge/module.json.captured index 92b15f2d..335a1a19 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-knowledge/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-knowledge/module.json.captured @@ -32,7 +32,8 @@ "propose", "import", "return", - "withdraw" + "withdraw", + "progress" ] } ], @@ -52,13 +53,15 @@ "propose", "import", "return", - "withdraw" + "withdraw", + "progress" ] } ], "tools": [ "knowledge_health", - "knowledge_highest" + "knowledge_highest", + "knowledge_marks" ], "emits": [ "reserved", @@ -81,7 +84,14 @@ "records.records_status", "records.records_list", "records.records_read", - "seat:operator-channel.notify" + "seat:operator-channel.notify", + "seat:issue-tracker.list", + "seat:issue-tracker.get", + "seat:issue-tracker.milestones", + "seat:issue-tracker.changes", + "seat:mesh-delivery.deliveries", + "seat:mesh-delivery.show", + "seat:mesh-delivery.groups" ], "config": { "judge-model": { diff --git a/testdata/beside/mesh-catalog/modules/mesh-provisioner/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-provisioner/module.json.captured index 650425b3..1aba09af 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-provisioner/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-provisioner/module.json.captured @@ -11,11 +11,36 @@ ] } ], + "uses": [ + "operator-channel" + ], + "reads": [ + "mesh-delivery-assigner.placement", + "mesh-delivery-assigner.wants", + "mesh-delivery-indexer.modules", + "mesh-delivery-indexer.manifests", + "mesh-delivery-builder.builds", + "node-engine.have", + "mesh-config.resolved", + "gitea.bound", + "keycloak.bound", + "postgres.bound", + "route-adapter.bound", + "mesh-vault.bound" + ], + "tools": [ + "provisioner_provisions", + "provisioner_plans", + "provisioner_compose", + "provisioner_decide" + ], "state": [ "registry", "needs", "applied", - "collect" + "collect", + "provisions", + "plans" ], "own-secrets": { "broker": "${dir:state}/broker" diff --git a/testdata/beside/mesh-catalog/modules/mesh-self-check/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-self-check/module.json.captured new file mode 100644 index 00000000..e4037e98 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/mesh-self-check/module.json.captured @@ -0,0 +1,87 @@ +{ + "module": "mesh-self-check", + "version": "1", + "runs-as": "mesh-self-check", + "claims": [ + { + "name": "mesh-self-check", + "scope": "mesh", + "serves": [ + "doctor", + "probes" + ] + } + ], + "invokes": [ + "nats.nats_streams", + "nats.nats_closed_connections", + "seat:mesh-watchdogs.signals", + "seat:node-intrusion-prevention.banned" + ], + "reads": [ + "mesh-delivery-assigner.placement", + "mesh-delivery-assigner.seat-holders", + "mesh-delivery-watchman.presence", + "mesh-host.health", + "disk-load.readings", + "restic.good", + "mesh-delivery-indexer.modules", + "mesh-delivery-indexer.manifests" + ], + "state": [ + "findings", + "verdict", + { + "name": "verdicts", + "ttl-seconds": 604800 + } + ], + "own-secrets": { + "broker": "${dir:state}/broker" + }, + "secrets-owner": "mesh-self-check", + "resources": [ + { + "id": "account", + "type": "user", + "name": "mesh-self-check", + "shell": "/usr/bin/nologin", + "home": "/var/lib/mesh-self-check" + }, + { + "id": "state", + "type": "directory", + "mode": "0700", + "owner": "mesh-self-check", + "place": ".", + "unknown": "program" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/mesh-self-check", + "binary": "mesh-self-check", + "loads": [ + "mesh-self-check" + ] + } + ] + }, + "config": { + "probes": { + "type": "list", + "description": "The ids of the probes that run, each judging one thing of the mesh (mesh-self-check.probes lists them with what each asserts). A probe not listed runs nothing and raises nothing, and what it raised before is cleared. D8 and DA are in the code and off by default.", + "trusted": true, + "default": [ + "D13", + "D-fill" + ], + "runtime": true + } + } +} diff --git a/testdata/beside/mesh-catalog/modules/mesh-vault/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-vault/module.json.captured index 44944c95..efea0cb1 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-vault/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-vault/module.json.captured @@ -5,6 +5,9 @@ "provides": [ { "name": "secret", + "credential": { + "form": "pair" + }, "scope": "mesh", "identity": { "in": "a vault entry" @@ -14,10 +17,27 @@ "emits": [ "provisioned", "rotated", - "secret-changed" + "secret-changed", + "account-hashed", + "own-replaced", + "account-issued", + "signed" ], "reads": [ - "mesh-controller.assignments" + "node-engine.have", + "mesh-grants.accounts", + "mesh-controller.lease", + "mesh-delivery-assigner.placement", + "mesh-provisioner.plans", + "mesh-provisioner.provisions" + ], + "state": [ + { + "name": "bus-accounts", + "history": 2 + }, + "signers", + "bound" ], "receives": { "secret": "${dir:grants}/mesh.json" @@ -135,7 +155,8 @@ "MESH_VAULT_LEDGER": "${dir:ledger}", "MESH_VAULT_ROOT": "${dir:root}", "MESH_VAULT_STORE": "${dir:store}", - "MESH_VAULT_STATE": "${dir:state}" + "MESH_VAULT_STATE": "${dir:state}", + "MESH_VAULT_SECRET_ASK_CALLERS": "node-tools" } } ] @@ -145,6 +166,10 @@ "secret_holders", "secret_verify", "secret_handed", + "secret_own", + "account_hash", + "account_adopt", + "account_retire", "secret_asks", "secret_vault_export", "provisioner_retirement", @@ -152,7 +177,12 @@ "provisioner_retire_reject", "provisioner_delete", "vault_status", - "vault_health" + "vault_health", + "own_drift", + "own_take_switch", + "vault_signers", + "vault_signed", + "signers_reassert" ], "claims": [ { @@ -166,7 +196,10 @@ "rotate", "move-in", "node-key", - "move-asks" + "move-asks", + "own", + "issue-account", + "sign" ] } ] diff --git a/testdata/beside/mesh-catalog/modules/mesh-watcher/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-watcher/module.json.captured index e9543a5d..ac05e105 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-watcher/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-watcher/module.json.captured @@ -3,11 +3,15 @@ "version": "1", "slug": "watch", "consumes": [ - "mesh-controller.doctor-heartbeat" + "mesh-controller.doctor-heartbeat", + "mesh-self-check.checked" + ], + "reads": [ + "mesh-conditions.takeover", + "mesh-delivery-assigner.seat-holders" ], "invokes": [ - "mesh-watcher.watcher_ping", - "seat:mesh-controller.seats" + "mesh-watcher.watcher_ping" ], "own-secrets": { "telegram-token": "${dir:state}/telegram-token" @@ -39,7 +43,9 @@ "type": "file", "path": "${dir:state}/settings.json", "mode": "0600", - "takes-config": ["telegram-chat-id"], + "takes-config": [ + "telegram-chat-id" + ], "merge": "json", "template": "files/settings.json" } diff --git a/testdata/beside/mesh-catalog/modules/messenger/module.json.captured b/testdata/beside/mesh-catalog/modules/messenger/module.json.captured index 4aceaebe..eec860f0 100644 --- a/testdata/beside/mesh-catalog/modules/messenger/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/messenger/module.json.captured @@ -77,6 +77,9 @@ "mesh-controller.condition-raised", "mesh-controller.condition-changed", "mesh-controller.condition-cleared", + "mesh-conditions.condition-raised", + "mesh-conditions.condition-changed", + "mesh-conditions.condition-cleared", "mesh-delivery-view.moving", "mesh-delivery-view.settled", "mesh-delivery-view.stuck", @@ -90,9 +93,13 @@ ], "invokes": [ "seat:mesh-controller.conditions", - "seat:mesh-controller.root-free", + "seat:mesh-conditions.conditions", + "seat:node-engine.root-free", "seat:issue-tracker.tracking" ], + "reads": [ + "mesh-conditions.takeover" + ], "state": [ "open", "sent", diff --git a/testdata/beside/mesh-catalog/modules/minio/module.json.captured b/testdata/beside/mesh-catalog/modules/minio/module.json.captured index 01a966af..60b40a4b 100644 --- a/testdata/beside/mesh-catalog/modules/minio/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/minio/module.json.captured @@ -12,6 +12,9 @@ "identity": { "max": 20, "in": "an S3 access key" + }, + "credential": { + "form": "pair" } } ], @@ -36,8 +39,8 @@ ] } ], - "invokes": [ - "seat:mesh-controller.seats" + "reads": [ + "mesh-delivery-assigner.seat-holders" ], "contributes": { "route": { diff --git a/testdata/beside/mesh-catalog/modules/mongodb/module.json.captured b/testdata/beside/mesh-catalog/modules/mongodb/module.json.captured index cbb12681..fc7d5212 100644 --- a/testdata/beside/mesh-catalog/modules/mongodb/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mongodb/module.json.captured @@ -12,6 +12,9 @@ "identity": { "max": 63, "in": "a MongoDB database name" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/mosquitto/module.json.captured b/testdata/beside/mesh-catalog/modules/mosquitto/module.json.captured index 21058e0a..a7213d44 100644 --- a/testdata/beside/mesh-catalog/modules/mosquitto/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mosquitto/module.json.captured @@ -8,6 +8,9 @@ "scope": "mesh", "identity": { "in": "a Mosquitto client and topic prefix" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/mounts/module.json.captured b/testdata/beside/mesh-catalog/modules/mounts/module.json.captured index 488ebb97..dc1e3785 100644 --- a/testdata/beside/mesh-catalog/modules/mounts/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mounts/module.json.captured @@ -5,11 +5,9 @@ "nfs-share" ], "reads": [ + "disk-load.readings", "nfs-server.exports" ], - "invokes": [ - "seat:mesh-controller.data" - ], "capabilities": [ "package-manager", "service-manager" @@ -38,20 +36,20 @@ "per-machine": true } ], - "config": { - "shares": { - "type": "string", - "description": "The shares of another machine this machine mounts: space-separated name=mountpoint, each optionally :ro, or none (novox/hq ADR 0263 rule 5).", - "trusted": true, - "default": "none" - }, - "sources": { - "type": "string", - "description": "The occasional sources this machine mounts: space-separated name=smb://[@]/@ or name=disk:@, each optionally :ro, or none (novox/hq ADR 0263 rule 6); an SMB source's username is in its entry, its password the secret smb-password- (novox/hq ADR 0283).", - "trusted": true, - "default": "none" - } + "config": { + "shares": { + "type": "string", + "description": "The shares of another machine this machine mounts: space-separated name=mountpoint, each optionally :ro, or none (novox/hq ADR 0263 rule 5).", + "trusted": true, + "default": "none" }, + "sources": { + "type": "string", + "description": "The occasional sources this machine mounts: space-separated name=smb://[@]/@ or name=disk:@, each optionally :ro, or none (novox/hq ADR 0263 rule 6); an SMB source's username is in its entry, its password the secret smb-password- (novox/hq ADR 0283).", + "trusted": true, + "default": "none" + } + }, "own-secrets": { "smb-password-*": { "path": "${dir:state}/smb-password-*.secret", diff --git a/testdata/beside/mesh-catalog/modules/mssql/module.json.captured b/testdata/beside/mesh-catalog/modules/mssql/module.json.captured index ed4e4488..35cdbe6e 100644 --- a/testdata/beside/mesh-catalog/modules/mssql/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mssql/module.json.captured @@ -12,6 +12,9 @@ "identity": { "max": 128, "in": "a SQL Server login and database name" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/nats/module.json.captured b/testdata/beside/mesh-catalog/modules/nats/module.json.captured index 106aac92..d2d02efe 100644 --- a/testdata/beside/mesh-catalog/modules/nats/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/nats/module.json.captured @@ -8,7 +8,10 @@ "provides": [ { "name": "mesh-bus", - "scope": "mesh" + "scope": "mesh", + "credential": { + "form": "none" + } } ], "claims": [ @@ -19,12 +22,16 @@ ], "bus-users": "/var/lib/nats-module/conf/accounts.conf", "own-secrets": { - "broker": "${dir:mesh-state}/broker" + "broker": "${dir:mesh-state}/broker", + "broker-nats-tools": "${dir:tools-secret}/broker-nats-tools" }, "capabilities": [ "container-runtime" ], - "emits": [], + "emits": [ + "consumer-removed", + "bucket-keys-removed" + ], "consumes": [], "listens": [ { @@ -45,7 +52,9 @@ "nats_buckets", "nats_users", "nats_user_can", - "nats_snapshot_verify" + "nats_snapshot_verify", + "nats_consumer_remove", + "nats_bucket_remove" ], "guards": [ 8222 @@ -86,6 +95,13 @@ "mode": "0700", "unknown": "program" }, + { + "id": "tools-secret", + "type": "directory", + "path": "/var/lib/mesh/nats-tools", + "mode": "0711", + "unknown": "program" + }, { "id": "snapshots", "type": "directory", @@ -190,11 +206,18 @@ "loads": [ "nats-tools" ], + "bus": { + "removes": [ + "DEAD_LETTER_NOTICES.controller", + "mesh-host_acts" + ] + }, "env": { "MESH_NATS_MONITOR": "http://127.0.0.1:8222", "MESH_NATS_CONTAINER": "mesh-broker-nats", "MESH_NATS_USERS_FILE": "/etc/nats/accounts.conf", - "MESH_NATS_SNAPSHOTS_DIR": "${dir:snapshots}" + "MESH_NATS_SNAPSHOTS_DIR": "${dir:snapshots}", + "NATS_TOOLS_CREDENTIAL": "${dir:tools-secret}/broker-nats-tools" } }, { diff --git a/testdata/beside/mesh-catalog/modules/nextcloud/module.json.captured b/testdata/beside/mesh-catalog/modules/nextcloud/module.json.captured index dd28417f..5d9f2ddc 100644 --- a/testdata/beside/mesh-catalog/modules/nextcloud/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/nextcloud/module.json.captured @@ -72,7 +72,7 @@ }, "user": { "type": "string", - "description": "The Nextcloud account the module's tools act as; empty is admin.", + "description": "The Nextcloud account the module's tools act as; empty is mesh-admin, the account the module makes and keeps for itself. Any other account is used as given and never repaired.", "trusted": true, "default": "" } diff --git a/testdata/beside/mesh-catalog/modules/nfs-server/module.json.captured b/testdata/beside/mesh-catalog/modules/nfs-server/module.json.captured index f9994d16..c7082176 100644 --- a/testdata/beside/mesh-catalog/modules/nfs-server/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/nfs-server/module.json.captured @@ -13,7 +13,10 @@ { "name": "nfs-share", "scope": "mesh", - "identity": false + "identity": false, + "credential": { + "form": "none" + } } ], "data": { @@ -45,26 +48,24 @@ } ], "reads": [ + "disk-load.readings", + "mesh-delivery-assigner.seat-holders", "mounts.shares" ], - "invokes": [ - "seat:mesh-controller.seats", - "seat:mesh-controller.data" - ], - "config": { - "shares": { - "type": "string", - "description": "The folders this machine exports, as space-separated name=path; the operator's, with no default (novox/hq ADR 0263).", - "trusted": true, - "required": true - }, - "grants": { - "type": "string", - "description": "Which nodes may mount which share, and how: share=node:rw|ro[,node:rw|ro], entries separated by spaces, or none to export to no node whatever a node wants (novox/hq ADR 0263).", - "trusted": true, - "default": "none" - } + "config": { + "shares": { + "type": "string", + "description": "The folders this machine exports, as space-separated name=path; the operator's, with no default (novox/hq ADR 0263).", + "trusted": true, + "required": true }, + "grants": { + "type": "string", + "description": "Which nodes may mount which share, and how: share=node:rw|ro[,node:rw|ro], entries separated by spaces, or none to export to no node whatever a node wants (novox/hq ADR 0263).", + "trusted": true, + "default": "none" + } + }, "facts": { "machines": { "path": "/etc/nfs-server/machines", diff --git a/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured b/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured index c3573444..2f4a049a 100644 --- a/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/nodejs/module.json.captured @@ -7,7 +7,10 @@ "provides": [ { "name": "node-toolchain", - "reach": "machine" + "reach": "machine", + "credential": { + "form": "none" + } } ], "resources": [ diff --git a/testdata/beside/mesh-catalog/modules/ollama/module.json.captured b/testdata/beside/mesh-catalog/modules/ollama/module.json.captured index 2d5fb48c..312ef6bf 100644 --- a/testdata/beside/mesh-catalog/modules/ollama/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/ollama/module.json.captured @@ -7,7 +7,10 @@ "provides": [ { "name": "model-access", - "scope": "node" + "scope": "node", + "credential": { + "form": "none" + } } ], "listens": [ diff --git a/testdata/beside/mesh-catalog/modules/postgres/module.json.captured b/testdata/beside/mesh-catalog/modules/postgres/module.json.captured index e8a59069..8f9f0579 100644 --- a/testdata/beside/mesh-catalog/modules/postgres/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/postgres/module.json.captured @@ -9,6 +9,7 @@ "provides": [ { "name": "postgres-database", + "credential": {"form": "pair"}, "scope": "mesh", "identity": { "max": 63, @@ -195,6 +196,7 @@ "bound" ], "reads": [ - "mesh-controller.assignments" + "mesh-provisioner.plans", + "mesh-provisioner.provisions" ] } diff --git a/testdata/beside/mesh-catalog/modules/power/module.json.captured b/testdata/beside/mesh-catalog/modules/power/module.json.captured index a110d410..909499ad 100644 --- a/testdata/beside/mesh-catalog/modules/power/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/power/module.json.captured @@ -314,6 +314,48 @@ "mode": "0644", "template": "templates/systemd/system/suspend-then-hibernate.target.d/mesh-power.conf" }, + { + "id": "reboot-drop-ins", + "type": "directory", + "path": "/etc/systemd/system/reboot.target.d", + "mode": "0755", + "unknown": "program" + }, + { + "id": "reboot-bound", + "type": "file", + "path": "/etc/systemd/system/reboot.target.d/mesh-power.conf", + "mode": "0644", + "template": "templates/systemd/system/reboot.target.d/mesh-power.conf" + }, + { + "id": "poweroff-drop-ins", + "type": "directory", + "path": "/etc/systemd/system/poweroff.target.d", + "mode": "0755", + "unknown": "program" + }, + { + "id": "poweroff-bound", + "type": "file", + "path": "/etc/systemd/system/poweroff.target.d/mesh-power.conf", + "mode": "0644", + "template": "templates/systemd/system/poweroff.target.d/mesh-power.conf" + }, + { + "id": "halt-drop-ins", + "type": "directory", + "path": "/etc/systemd/system/halt.target.d", + "mode": "0755", + "unknown": "program" + }, + { + "id": "halt-bound", + "type": "file", + "path": "/etc/systemd/system/halt.target.d/mesh-power.conf", + "mode": "0644", + "template": "templates/systemd/system/halt.target.d/mesh-power.conf" + }, { "id": "udev-rule", "type": "file", diff --git a/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/halt.target.d/mesh-power.conf b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/halt.target.d/mesh-power.conf new file mode 100644 index 00000000..569d7fd9 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/halt.target.d/mesh-power.conf @@ -0,0 +1,8 @@ +# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push. +# +# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown +# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the +# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own +# forcing action: the last phase still ends every process, unmounts and syncs. +[Unit] +JobTimeoutSec=10min diff --git a/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/poweroff.target.d/mesh-power.conf b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/poweroff.target.d/mesh-power.conf new file mode 100644 index 00000000..569d7fd9 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/poweroff.target.d/mesh-power.conf @@ -0,0 +1,8 @@ +# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push. +# +# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown +# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the +# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own +# forcing action: the last phase still ends every process, unmounts and syncs. +[Unit] +JobTimeoutSec=10min diff --git a/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/reboot.target.d/mesh-power.conf b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/reboot.target.d/mesh-power.conf new file mode 100644 index 00000000..569d7fd9 --- /dev/null +++ b/testdata/beside/mesh-catalog/modules/power/templates/systemd/system/reboot.target.d/mesh-power.conf @@ -0,0 +1,8 @@ +# Written by the mesh (module power, novox/hq ADR 0211; issue 1126). Replaced on every push. +# +# A shutdown is bounded at ten minutes, not systemd's thirty. A unit started again during the shutdown +# (on ace, 2026-10-28, the bus and the authorization manager) is never stopped a second time, and the +# shutdown then waits on this job's timeout with nothing on the console. The target keeps its own +# forcing action: the last phase still ends every process, unmounts and syncs. +[Unit] +JobTimeoutSec=10min diff --git a/testdata/beside/mesh-catalog/modules/redis/module.json.captured b/testdata/beside/mesh-catalog/modules/redis/module.json.captured index 58e11064..4cc6c4e5 100644 --- a/testdata/beside/mesh-catalog/modules/redis/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/redis/module.json.captured @@ -7,6 +7,9 @@ "scope": "mesh", "identity": { "in": "a Redis ACL user and key prefix" + }, + "credential": { + "form": "pair" } } ], diff --git a/testdata/beside/mesh-catalog/modules/restic/module.json.captured b/testdata/beside/mesh-catalog/modules/restic/module.json.captured index ea5ec8b9..05927fe2 100644 --- a/testdata/beside/mesh-catalog/modules/restic/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/restic/module.json.captured @@ -41,40 +41,40 @@ } ] }, - "config": { - "keep-daily": { - "type": "number", - "description": "How many nightly restore points are kept, a count from 1 to 9999: two weeks undo a mistake noticed within a fortnight. Read by the night, which thins nothing while it does not read (novox/hq issue 416); lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", - "minimum": 1, - "maximum": 9999, - "trusted": true, - "default": 14 - }, - "keep-weekly": { - "type": "number", - "description": "How many weekly restore points are kept behind the dailies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", - "minimum": 1, - "maximum": 9999, - "trusted": true, - "default": 8 - }, - "keep-monthly": { - "type": "number", - "description": "How many monthly restore points are kept behind the weeklies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", - "minimum": 1, - "maximum": 9999, - "trusted": true, - "default": 6 - }, - "keep-hand-taken-days": { - "type": "number", - "description": "How many days a restore point taken by hand (node-backup.now, or the mesh's before a module moves) is kept at least, a count from 1 to 9999; it is kept until a later good night of its module exists, and this many days in any case, so the next thinning never takes the one taken against a risky change (novox/hq issue 453). Lowering it lets go of the older ones taken by hand at the next thinning, and that cannot be undone.", - "minimum": 1, - "maximum": 9999, - "trusted": true, - "default": 7 - } + "config": { + "keep-daily": { + "type": "number", + "description": "How many nightly restore points are kept, a count from 1 to 9999: two weeks undo a mistake noticed within a fortnight. Read by the night, which thins nothing while it does not read (novox/hq issue 416); lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", + "minimum": 1, + "maximum": 9999, + "trusted": true, + "default": 14 }, + "keep-weekly": { + "type": "number", + "description": "How many weekly restore points are kept behind the dailies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", + "minimum": 1, + "maximum": 9999, + "trusted": true, + "default": 8 + }, + "keep-monthly": { + "type": "number", + "description": "How many monthly restore points are kept behind the weeklies, a count from 1 to 9999, refused by the night like keep-daily; lowering it deletes the restore points beyond the new count at the next night, and that cannot be undone.", + "minimum": 1, + "maximum": 9999, + "trusted": true, + "default": 6 + }, + "keep-hand-taken-days": { + "type": "number", + "description": "How many days a restore point taken by hand (node-backup.now, or the mesh's before a module moves) is kept at least, a count from 1 to 9999; it is kept until a later good night of its module exists, and this many days in any case, so the next thinning never takes the one taken against a risky change (novox/hq issue 453). Lowering it lets go of the older ones taken by hand at the next thinning, and that cannot be undone.", + "minimum": 1, + "maximum": 9999, + "trusted": true, + "default": 7 + } + }, "resources": [ { "id": "state", @@ -139,22 +139,17 @@ "MESH_BACKUP_DATA": "${dir:state}/data.conf" }, "health": { - "kind": "tool", - "tool": "backup_health", - "interval": "60s", - "timeout": "20s", - "looks": 2, - "grace": "60s" + "kind": "unit" } }, { - "id": "measure", + "id": "awake", "type": "process", - "name": "restic-measure", + "name": "restic-awake", "artifact": "tools", "run": [ "./restic-backups", - "measure" + "awake" ], "user": "${machine:account}", "env": { @@ -165,7 +160,12 @@ "MESH_BACKUP_DATA": "${dir:state}/data.conf" }, "health": { - "kind": "unit" + "kind": "tool", + "tool": "backup_health", + "interval": "60s", + "timeout": "20s", + "looks": 2, + "grace": "60s" } } ], @@ -195,5 +195,11 @@ "from": "files" } ] - } + }, + "reads": [ + "disk-load.readings" + ], + "state": [ + "good" + ] } diff --git a/testdata/beside/mesh-catalog/modules/route-adapter/module.json.captured b/testdata/beside/mesh-catalog/modules/route-adapter/module.json.captured index 5234c78b..2827462c 100644 --- a/testdata/beside/mesh-catalog/modules/route-adapter/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/route-adapter/module.json.captured @@ -9,6 +9,7 @@ "provides": [ { "name": "route", + "credential": {"form": "none"}, "scope": "mesh", "identity": false } @@ -129,6 +130,7 @@ "bound" ], "reads": [ - "mesh-controller.assignments" + "mesh-provisioner.plans", + "mesh-provisioner.provisions" ] } diff --git a/testdata/beside/mesh-catalog/modules/showcase/module.json.captured b/testdata/beside/mesh-catalog/modules/showcase/module.json.captured index e657e2ab..6b0db672 100644 --- a/testdata/beside/mesh-catalog/modules/showcase/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/showcase/module.json.captured @@ -9,7 +9,10 @@ "provides": [ { "name": "greeting", - "scope": "mesh" + "scope": "mesh", + "credential": { + "form": "none" + } } ], "serves": { diff --git a/testdata/beside/mesh-catalog/modules/step-ca/module.json.captured b/testdata/beside/mesh-catalog/modules/step-ca/module.json.captured index b11d2b99..3f44ead7 100644 --- a/testdata/beside/mesh-catalog/modules/step-ca/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/step-ca/module.json.captured @@ -7,7 +7,10 @@ "provides": [ { "name": "internal-acme-ca", - "scope": "mesh" + "scope": "mesh", + "credential": { + "form": "none" + } } ], "serves": { diff --git a/testdata/beside/mesh-catalog/modules/systemd-resolved/module.json.captured b/testdata/beside/mesh-catalog/modules/systemd-resolved/module.json.captured index b850afcf..24b3bc85 100644 --- a/testdata/beside/mesh-catalog/modules/systemd-resolved/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/systemd-resolved/module.json.captured @@ -8,7 +8,10 @@ "provides": [ { "name": "split-dns", - "reach": "machine" + "reach": "machine", + "credential": { + "form": "none" + } } ], "requires": [ diff --git a/testdata/beside/mesh-catalog/modules/umami/module.json.captured b/testdata/beside/mesh-catalog/modules/umami/module.json.captured index 22ead419..e3b9aa0d 100644 --- a/testdata/beside/mesh-catalog/modules/umami/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/umami/module.json.captured @@ -32,7 +32,10 @@ "provides": [ { "name": "analytics", - "scope": "mesh" + "scope": "mesh", + "credential": { + "form": "none" + } } ], "serves": { diff --git a/testdata/beside/mesh-catalog/modules/xorg/module.json.captured b/testdata/beside/mesh-catalog/modules/xorg/module.json.captured index 7b0b6b1e..1685dcb4 100644 --- a/testdata/beside/mesh-catalog/modules/xorg/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/xorg/module.json.captured @@ -9,7 +9,10 @@ "provides": [ { "name": "x11-display", - "reach": "machine" + "reach": "machine", + "credential": { + "form": "none" + } } ], "claims": [ -- 2.54.0 From 80df1b6361af186ad11bcb6350ae1628b7f8110d Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 00:20:10 +0100 Subject: [PATCH 3/4] Pin mesh-sdk 6e4a301, the release's final sdk (issue 774) The sdk's conformance events are unchanged at 6e4a301 and captured so. The whole integration suite passes at this head against a local store and bus: 1706 tests, 8 skipped for a registry, a container, a refusing bus or a lab's run. --- go.mod | 2 +- go.sum | 4 ++-- testdata/beside/CAPTURED | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 6e6167b2..c9447cad 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/novox/mesh-controller go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029231453-6e4a3014cbde github.com/jackc/pgx/v5 v5.10.0 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 diff --git a/go.sum b/go.sum index 142c307a..73e8e20b 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5 h1:E5stfIeCN6uYgA9TCv+4K8JgaURg3zQppvUgJLaDMP4= git.novox.be/novox/mesh-host v0.0.0-20261018171808-9d9e3a46c4f5/go.mod h1:4wyoCr6IIIIarEUuROThWDj7DAvJvIidqMjWcpSnOwE= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7 h1:9FZLjq5H+FShqsaSvZ5vGGjDFaQkdhGCna6ofiBd+p4= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029230207-007b6fd45fc7/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029231453-6e4a3014cbde h1:ddf/jKI9c87sQKDmZLoG6PMnvXwsNH16ByVveyuFME4= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029231453-6e4a3014cbde/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/testdata/beside/CAPTURED b/testdata/beside/CAPTURED index 092e26d9..0d715fcd 100644 --- a/testdata/beside/CAPTURED +++ b/testdata/beside/CAPTURED @@ -9,7 +9,7 @@ a second place to clean besides the catalogue itself. mesh-catalog 8ae8e88dddc86c646de4d1be35919d109ab4c779 modules/*/module.json, modules/*/files, modules/*/templates, predefined.json mesh-host 9d9e3a46c4f5943cfffb413d962ce48b75e2fd39 examples/foundation-first-node.lock -mesh-sdk 007b6fd45fc7e7bfa93e76f6b9009725f881e29f conformance/events/module-event.json +mesh-sdk 6e4a3014cbde924dcd24158369cbe9ad287ce2c9 conformance/events/module-event.json To move them, from this repository's root, with the two repositories checked out beside it: -- 2.54.0 From 8b32e04e2f8b064dae2ac68dc5e2814025ad0ce2 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 10:38:29 +0100 Subject: [PATCH 4/4] Judge the controller's module check against the catalogue it is released with, captured at the group's catalogue head f3a57dcc, so a group that brings a word the trunk's catalogue lacks does not fail on the trunk (issue 774) The release's fourth check failed TestModuleCheckPassesTheCatalogue with 27 problems. The checker clones the catalogue beside a controller's tests at its trunk, even in a group holding a catalogue pull request (mesh-delivery checker internal/check/beside.go besideFor, ADR 0484 clause 4). The release's sdk refuses an offer stating no credential form, and the trunk's catalogue states none until the release's catalogue merges. - Quick fix (not chosen): recapture alone, which the test never reads while MESH_CHECK_BESIDE is set. - Chosen: the test reads the captured copy, now at the group's catalogue f3a57dcc, through beside.CapturedDir. Every other beside test still reads the clone. The check itself is unchanged: every rule, every manifest. Moving CAPTURED to the catalogue a change is released with is part of that change. Run as the checker runs it (catalogue at main, mesh-host at main, mesh-sdk at the pin, mesh-controller's trunk beside): the whole unit and integration suite passes, 1706 tests, 8 skipped. The test also passes with the catalogue at f3a57dcc beside, and with nothing beside. --- cmd/mesh-controller/check_test.go | 10 ++++++++-- internal/beside/beside.go | 13 +++++++++++-- testdata/beside/CAPTURED | 2 +- .../mesh-catalog/modules/gitea/module.json.captured | 3 ++- .../modules/mesh-issues/files/settings.json | 4 ++++ .../modules/mesh-issues/module.json.captured | 4 ++++ 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/cmd/mesh-controller/check_test.go b/cmd/mesh-controller/check_test.go index 608b6b69..6d323986 100644 --- a/cmd/mesh-controller/check_test.go +++ b/cmd/mesh-controller/check_test.go @@ -56,9 +56,15 @@ func TestModuleCheckJudgesBetweenTheManifestsGiven(t *testing.T) { } } -// The real catalogue passes the command, the way it passes the test that used to be the only check. +// The real catalogue passes the command, the way it passes the test that used to be the only check: the catalogue this +// controller is released with, captured in testdata/beside at the commit CAPTURED names. Not the clone a merge check puts +// beside, which is the catalogue's trunk even in a delivery group holding a catalogue pull request (ADR 0484 clause 4): +// a controller whose check reads a word that group's catalogue brings would fail on the trunk's catalogue before the +// group merges both (issue 774: the release's sdk refuses an offer that states no credential form, and the catalogue's +// trunk states none until the release's catalogue merges). Moving CAPTURED to the catalogue a change is released with is +// part of that change. func TestModuleCheckPassesTheCatalogue(t *testing.T) { - root := beside.Catalogue(t) + root := filepath.Join(beside.CapturedDir(t, "mesh-catalog"), "modules") paths, err := manifestsUnder(root) if err != nil || len(paths) == 0 { t.Fatalf("no manifests under %s: %v", root, err) diff --git a/internal/beside/beside.go b/internal/beside/beside.go index 3ae47abf..159d8867 100644 --- a/internal/beside/beside.go +++ b/internal/beside/beside.go @@ -53,6 +53,16 @@ func Dir(t testing.TB, repository string) string { t.Logf("judged against %s as cloned beside this check", dir) return dir } + t.Logf("no %s beside this check: a merge check judges %s against its own clone", Env, repository) + return CapturedDir(t, repository) +} + +// CapturedDir is the copy of the named repository captured in testdata/beside, laid out as Dir lays it out, whatever +// MESH_CHECK_BESIDE says: for a test that judges this repository against the commit it was released with, which a +// merge check does not clone (it clones the catalogue at its trunk even in a delivery group holding a catalogue pull +// request, ADR 0484 clause 4). +func CapturedDir(t testing.TB, repository string) string { + t.Helper() from := filepath.Join(Captured(), repository) if _, err := os.Stat(from); err != nil { t.Fatalf("no captured copy of %s at %s: %v", repository, from, err) @@ -81,8 +91,7 @@ func Dir(t testing.TB, repository string) string { if err != nil { t.Fatalf("the captured copy of %s could not be laid out: %v", repository, err) } - t.Logf("judged against the copy of %s captured in testdata/beside (see CAPTURED); a merge check "+ - "judges it against the repository's own clone", repository) + t.Logf("judged against the copy of %s captured in testdata/beside (see CAPTURED)", repository) return dir } diff --git a/testdata/beside/CAPTURED b/testdata/beside/CAPTURED index f84c54a4..9fb61a4d 100644 --- a/testdata/beside/CAPTURED +++ b/testdata/beside/CAPTURED @@ -7,7 +7,7 @@ The copy carries the catalogue's private details: domains, first names in module private addresses. That is acceptable while mesh-controller is private; if it ever goes public, this copy is a second place to clean besides the catalogue itself. -mesh-catalog 8ae8e88dddc86c646de4d1be35919d109ab4c779 modules/*/module.json, modules/*/files, modules/*/templates, predefined.json +mesh-catalog f3a57dcc56fb6c198095cafd11d0decff9f720c4 modules/*/module.json, modules/*/files, modules/*/templates, predefined.json mesh-host 9d9e3a46c4f5943cfffb413d962ce48b75e2fd39 examples/foundation-first-node.lock mesh-sdk 2da0de75c3f0087cff9c2f5ef789ca6dc3c59045 conformance/events/module-event.json diff --git a/testdata/beside/mesh-catalog/modules/gitea/module.json.captured b/testdata/beside/mesh-catalog/modules/gitea/module.json.captured index 69b88adb..2b197288 100644 --- a/testdata/beside/mesh-catalog/modules/gitea/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/gitea/module.json.captured @@ -266,7 +266,8 @@ "env": { "DB_TYPE": "postgres", "USER_UID": "1000", - "USER_GID": "1000" + "USER_GID": "1000", + "SSH_MAX_STARTUPS": "100:30:200" }, "env-file": [ "${dir:state}/server.env" diff --git a/testdata/beside/mesh-catalog/modules/mesh-issues/files/settings.json b/testdata/beside/mesh-catalog/modules/mesh-issues/files/settings.json index 0231a55d..265fe2da 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-issues/files/settings.json +++ b/testdata/beside/mesh-catalog/modules/mesh-issues/files/settings.json @@ -62,10 +62,13 @@ "mesh-catalog modules/mesh-build-node", "mesh-catalog modules/mesh-catalog", "mesh-catalog modules/mesh-cli", + "mesh-catalog modules/mesh-conditions", "mesh-catalog modules/mesh-config", "mesh-catalog modules/mesh-delivery", "mesh-catalog modules/mesh-delivery-gate", "mesh-catalog modules/mesh-files", + "mesh-catalog modules/mesh-hand-acts", + "mesh-catalog modules/mesh-healers", "mesh-catalog modules/mesh-issues", "mesh-catalog modules/mesh-knowledge", "mesh-catalog modules/mesh-mail", @@ -75,6 +78,7 @@ "mesh-catalog modules/mesh-provisioner", "mesh-catalog modules/mesh-provisioner-client", "mesh-catalog modules/mesh-reads", + "mesh-catalog modules/mesh-self-check", "mesh-catalog modules/mesh-vault", "mesh-catalog modules/mesh-watcher", "mesh-catalog modules/messenger", diff --git a/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured b/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured index d359bda2..196c586c 100644 --- a/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured +++ b/testdata/beside/mesh-catalog/modules/mesh-issues/module.json.captured @@ -174,10 +174,13 @@ "mesh-catalog modules/mesh-build-node", "mesh-catalog modules/mesh-catalog", "mesh-catalog modules/mesh-cli", + "mesh-catalog modules/mesh-conditions", "mesh-catalog modules/mesh-config", "mesh-catalog modules/mesh-delivery", "mesh-catalog modules/mesh-delivery-gate", "mesh-catalog modules/mesh-files", + "mesh-catalog modules/mesh-hand-acts", + "mesh-catalog modules/mesh-healers", "mesh-catalog modules/mesh-issues", "mesh-catalog modules/mesh-knowledge", "mesh-catalog modules/mesh-mail", @@ -187,6 +190,7 @@ "mesh-catalog modules/mesh-provisioner", "mesh-catalog modules/mesh-provisioner-client", "mesh-catalog modules/mesh-reads", + "mesh-catalog modules/mesh-self-check", "mesh-catalog modules/mesh-vault", "mesh-catalog modules/mesh-watcher", "mesh-catalog modules/messenger", -- 2.54.0