Carry the power draw to the bar over the bus, not through a file (hq ADR 0260)

Modules talk over the bus. The power module's bundle puts each fresh reading of its own
sampler in its state draw, keyed by the machine; the bar's block shows that state, which
the bar's bundle watches under the read the mesh grants it. A new catalogue check refuses
a module naming another module's path under /run or /var/lib.
This commit is contained in:
jochen
2026-10-08 16:12:37 +02:00
parent e1b7fcd8c9
commit 76b63744e6
21 changed files with 697 additions and 73 deletions
+3
View File
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-catalog/checks/paths
go 1.22
+134
View File
@@ -0,0 +1,134 @@
// Command paths holds the catalogue's modules to talking over the bus (novox/hq ADR 0260): no module
// names a path under /run or /var/lib that another module's manifest places. Such a path is that
// module's state on its machine, and a second module reading or writing it is two modules talking
// through a file, which the bus exists to replace.
//
// A module owns every `path` of its resources under /run/ or /var/lib/. Every other module's manifest
// and every file of its own except its documentation and its tests is searched for each, as a whole
// path: followed by nothing, a slash, or a character no path takes.
//
// go run . <catalogue root>
//
// Exits 1 on a finding.
package main
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
)
// stateRoots are where a machine keeps a module's state.
var stateRoots = []string{"/run/", "/var/lib/"}
type manifest struct {
Module string `json:"module"`
Resources []map[string]any `json:"resources"`
}
// Finding is one module naming another's path.
type Finding struct {
Module, File, Path, Owner string
}
func (f Finding) String() string {
return fmt.Sprintf("%s names %s in %s, and the path is %s's; modules talk over the bus (novox/hq ADR 0260)",
f.Module, f.Path, f.File, f.Owner)
}
// Check is every finding in the catalogue at root.
func Check(root string) ([]Finding, error) {
dirs, err := filepath.Glob(filepath.Join(root, "modules", "*", "module.json"))
if err != nil {
return nil, err
}
owner := map[string]string{}
modules := map[string]string{}
for _, f := range dirs {
raw, err := os.ReadFile(f)
if err != nil {
return nil, err
}
var m manifest
if err := json.Unmarshal(raw, &m); err != nil {
return nil, fmt.Errorf("%s: %w", f, err)
}
modules[m.Module] = filepath.Dir(f)
for _, r := range m.Resources {
p, _ := r["path"].(string)
for _, root := range stateRoots {
if strings.HasPrefix(p, root) && len(p) > len(root) {
owner[strings.TrimRight(p, "/")] = m.Module
}
}
}
}
paths := make([]string, 0, len(owner))
for p := range owner {
paths = append(paths, p)
}
sort.Strings(paths)
patterns := map[string]*regexp.Regexp{}
for _, p := range paths {
patterns[p] = regexp.MustCompile(regexp.QuoteMeta(p) + `(?:$|[^A-Za-z0-9._-])`)
}
var out []Finding
names := make([]string, 0, len(modules))
for n := range modules {
names = append(names, n)
}
sort.Strings(names)
for _, module := range names {
dir := modules[module]
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return err
}
name := d.Name()
if strings.HasSuffix(name, ".md") || strings.HasSuffix(name, "_test.go") ||
name == "go.sum" || name == "package-lock.json" {
return nil
}
raw, err := os.ReadFile(path)
if err != nil {
return err
}
text := string(raw)
for _, p := range paths {
if owner[p] != module && patterns[p].MatchString(text) {
rel, _ := filepath.Rel(root, path)
out = append(out, Finding{Module: module, File: rel, Path: p, Owner: owner[p]})
}
}
return nil
})
if err != nil {
return nil, err
}
}
return out, nil
}
func main() {
root := "."
if len(os.Args) > 1 {
root = os.Args[1]
}
found, err := Check(root)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
for _, f := range found {
fmt.Println(f)
}
if len(found) > 0 {
os.Exit(1)
}
fmt.Println("paths: no module names another's state on its machine")
}
+63
View File
@@ -0,0 +1,63 @@
package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
func catalogue(t *testing.T, files map[string]string) string {
t.Helper()
root := t.TempDir()
for p, c := range files {
full := filepath.Join(root, p)
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(full, []byte(c), 0o644); err != nil {
t.Fatal(err)
}
}
return root
}
const owner = `{"module":"power","resources":[{"id":"d","type":"directory","path":"/run/mesh-power"}]}`
func TestAModuleReadingAnothersStateIsFound(t *testing.T) {
root := catalogue(t, map[string]string{
"modules/power/module.json": owner,
"modules/power/cmd/power/draw.go": `const f = "/run/mesh-power/draw"`,
"modules/bar/module.json": `{"module":"bar","resources":[{"id":"x","type":"file","path":"/etc/x","content":"cat /run/mesh-power/draw"}]}`,
"modules/other/module.json": `{"module":"other"}`,
"modules/other/files/bin/read": "#!/bin/sh\ncat /run/mesh-power\n",
"modules/other/README.md": "it once read /run/mesh-power/draw",
"modules/other/cmd/x/x_test.go": `"/run/mesh-power"`,
"modules/near/module.json": `{"module":"near","resources":[{"id":"y","type":"file","path":"/etc/y","content":"/run/mesh-power-other/x"}]}`,
})
found, err := Check(root)
if err != nil {
t.Fatal(err)
}
var got []string
for _, f := range found {
got = append(got, f.Module+" "+f.File)
}
want := []string{"bar modules/bar/module.json", "other modules/other/files/bin/read"}
if strings.Join(got, "|") != strings.Join(want, "|") {
t.Fatalf("found %v, want %v", got, want)
}
if !strings.Contains(found[0].String(), "power's") {
t.Fatalf("%s", found[0])
}
}
func TestACatalogueWhereEachKeepsToItsOwnIsClean(t *testing.T) {
root := catalogue(t, map[string]string{
"modules/power/module.json": owner,
"modules/power/cmd/power/draw.go": `const f = "/run/mesh-power/draw"`,
})
if found, err := Check(root); err != nil || len(found) != 0 {
t.Fatalf("%v %v", found, err)
}
}