Test that a node without the go or nodejs module refuses the modules needing a toolchain, against the catalogue as it now stands (issue 1573) #56
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
Vendored
+2
-2
@@ -7,10 +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 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:
|
||||
|
||||
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"scanner": "",
|
||||
"scan-folder": "",
|
||||
"printer": "",
|
||||
"printer-certificate": "",
|
||||
"resolution": 300,
|
||||
"color-mode": "color",
|
||||
"crop": true
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
Regular → Executable
@@ -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",
|
||||
|
||||
@@ -540,6 +540,8 @@
|
||||
],
|
||||
"reads": [
|
||||
"mesh-controller.assignments",
|
||||
"ssh-client.keys"
|
||||
"ssh-client.keys",
|
||||
"mesh-build-go.keys",
|
||||
"mesh-build-node.keys"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"module": "go",
|
||||
"version": "1",
|
||||
"capabilities": [
|
||||
"package-manager"
|
||||
],
|
||||
"provides": [
|
||||
{
|
||||
"name": "go-toolchain",
|
||||
"reach": "machine"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"id": "go",
|
||||
"type": "package",
|
||||
"package": "go"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
Regular → Executable
Vendored
Regular → Executable
Vendored
Regular → Executable
@@ -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",
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
[url "ssh://${bound:forge-account:ssh_alias}/"]
|
||||
insteadOf = ${bound:forge-account:https_base}
|
||||
@@ -0,0 +1 @@
|
||||
${bound:forge-account:ssh_alias} ${bound:forge-account:host_key}
|
||||
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"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_step",
|
||||
"build_go_steps",
|
||||
"build_go_toolchains",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
[url "ssh://${bound:forge-account:ssh_alias}/"]
|
||||
insteadOf = ${bound:forge-account:https_base}
|
||||
@@ -0,0 +1 @@
|
||||
${bound:forge-account:ssh_alias} ${bound:forge-account:host_key}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"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_step",
|
||||
"build_node_steps",
|
||||
"build_node_toolchains",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@
|
||||
"consumes": [
|
||||
"mesh-issues.opened",
|
||||
"mesh-issues.moved",
|
||||
"mesh-delivery.transition",
|
||||
"mesh-delivery-gate.transition"
|
||||
],
|
||||
"invokes": [
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"callers": ["mesh-mail-web"]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}
|
||||
+141
@@ -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), <machine>.<module>, or person.<name> (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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"],
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
"scope": "node",
|
||||
"needs": ["node-notifier"],
|
||||
"serves": ["status"]
|
||||
},
|
||||
{
|
||||
"name": "mail-reading",
|
||||
"scope": "mesh",
|
||||
"serves": ["entries", "groups", "correct", "lessons", "undo", "status"]
|
||||
}
|
||||
],
|
||||
"claims": [
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"time-zone": "",
|
||||
"only-what-needs-me": []
|
||||
"only-what-needs-me": [],
|
||||
"messages-per-hour": 100
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
+12
@@ -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
|
||||
+11
@@ -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
|
||||
@@ -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": {
|
||||
|
||||
Vendored
Regular → Executable
Reference in New Issue
Block a user