Carry brother's certificate check on a watch process beside the device unit check, as fail2ban does (issue 1510)

This commit is contained in:
2026-10-21 02:05:21 +02:00
parent 7eddb116b1
commit b7243505ca
3 changed files with 45 additions and 3 deletions
+16
View File
@@ -4,6 +4,8 @@ import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
stdio "git.novox.be/novox/mesh-sdk/go"
@@ -13,12 +15,26 @@ func main() {
if len(os.Args) > 1 && os.Args[1] == "device" {
os.Exit(device())
}
if len(os.Args) > 1 && os.Args[1] == "watch" {
os.Exit(watch())
}
if err := stdio.Serve("", tools(os.Getenv("BROTHER_SETTINGS"), time.Now)); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
// watch is `brother watch`: the process that carries the tool check brother_health beside the device process's unit
// check, as fail2ban's watch does (ADR 0240: a tool check is only beside a check the module does not run itself).
// It does nothing itself; the node-engine asks the tool, and this stays up until it is stopped.
func watch() int {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
fmt.Fprintln(os.Stderr, "[brother] watch is up; the node-engine asks brother_health")
<-ctx.Done()
return 0
}
// intArg reads a whole number out of a tool's arguments: a JSON number, which arrives as a float64.
func intArg(args map[string]any, name string) (int, error) {
v, ok := args[name]
+15 -3
View File
@@ -256,9 +256,7 @@ func TestTheAdminProcessIsDeclaredAsMeshMailsSenderIs(t *testing.T) {
if !reflect.DeepEqual(bus["queues"], []any{"device-asks"}) || !reflect.DeepEqual(bus["state"], []any{"device-answers"}) {
t.Errorf("bus = %v", bus)
}
// 1510: liveness is judged for every process without a declaration (ADR 0240 §1); the declared check is the
// tool that compares the printer's certificates with the pins.
if h, _ := p["health"].(map[string]any); h["kind"] != "tool" || h["tool"] != "brother_health" {
if h, _ := p["health"].(map[string]any); h["kind"] != "unit" {
t.Errorf("health = %v", p["health"])
}
env, _ := p["env"].(map[string]any)
@@ -397,3 +395,17 @@ func TestEachConfigPatternAdmitsARealValueWhole(t *testing.T) {
}
}
}
// 1510: the certificate check is a tool check on a process of its own beside the device process's unit check, as
// fail2ban's watch is (ADR 0227 rule 8, ADR 0240: a tool check only beside a check of another kind).
func TestTheCertificateCheckIsAToolCheckBesideTheUnitCheck(t *testing.T) {
m := readManifest(t)
w := resource(t, m, "watch")
h, _ := w["health"].(map[string]any)
if w["type"] != "process" || w["artifact"] != "tools" || h["kind"] != "tool" || h["tool"] != "brother_health" || !reflect.DeepEqual(w["run"], []any{"./brother", "watch"}) {
t.Errorf("watch = %v", w)
}
if !slices.Contains(m.Tools, "brother_health") {
t.Errorf("tools = %v", m.Tools)
}
}
+14
View File
@@ -230,6 +230,20 @@
"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",