package inventory import ( "os" "strings" "testing" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/catalogue" ) // grantMatches is a NATS subject pattern matching a subject: `*` one token, `>` the rest. func grantMatches(pattern, subject string) bool { p, s := strings.Split(pattern, "."), strings.Split(subject, ".") for i, tok := range p { if tok == ">" { return len(s) > i } if i >= len(s) || (tok != "*" && tok != s[i]) { return false } } return len(p) == len(s) } func grantsAny(patterns []string, subject string) bool { for _, p := range patterns { if grantMatches(p, subject) { return true } } return false } // novox/hq ADR 0259 §8 (confirmation review of 2026-10-09): the router honours a verified sender only on the // controller's `root-free` word, asked on the bus. So only the serving controller may answer that verb — be // subscribed to its subject — and nobody may publish into the router's inbox but by answering a request it // made (allow_responses). Composed here from the controller's own manifest, on a machine where the machine's // runtime carries it beside an ordinary module, with the router, a channel, a person and an administrator: a // runtime carrying the controller's module, a node-engine, a channel or anybody else answering `root-free` is // an agent answering it. func TestOnlyTheServingControllerMayAnswerRootFree(t *testing.T) { raw, err := os.ReadFile("../../module.json") if err != nil { t.Fatal(err) } controller, err := catalogue.ParseManifest(raw) if err != nil { t.Fatal(err) } parse := func(s string) catalogue.Manifest { m, err := catalogue.ParseManifest([]byte(s)) if err != nil { t.Fatal(err) } return m } dir := `"resources": [{"id": "state", "type": "directory", "mode": "0700", "place": "."}]` router := parse(`{"module": "messenger", "version": "1", "runs-as": "messenger", "seats": [{"name": "operator-channel", "scope": "mesh", "serves": ["open"], "accepts": ["ask"], "emits": ["decided"], "by-caller": ["ask", "decided"]}], "claims": [{"name": "operator-channel", "scope": "mesh", "serves": ["open"]}], "invokes": ["seat:mesh-controller.root-free", "seat:mesh-controller.conditions"], "own-secrets": {"broker": "${dir:state}/broker"}, "secrets-owner": "messenger", "resources": [{"id": "account", "type": "user", "name": "messenger", "shell": "/usr/bin/nologin", "home": "/var/lib/messenger"}, {"id": "state", "type": "directory", "mode": "0700", "place": ".", "owner": "messenger"}]}`) ordinary := parse(`{"module": "lab-bystander", "version": "1", "own-secrets": {"broker": "${dir:state}/broker"}, ` + dir + `}`) runtime := catalogue.Manifest{Module: broker.RuntimeModule} manifests := []catalogue.Manifest{controller, router, ordinary, runtime} seats := map[string]catalogue.SeatDeclaration{} declarers := map[string]string{} for _, m := range manifests { for _, s := range m.DefinesSeats { seats[s.Name], declarers[s.Name] = s, m.Module } } for _, own := range catalogue.SeatsWithAProtocol() { seats[own.Name] = catalogue.SeatDeclaration{Name: own.Name, Scope: own.Scope, Accepts: own.Accepts, Emits: own.Emits, Serves: own.Serves} } records := broker.Records{Nodes: []string{"anchor", "laptop"}, Assigned: map[string][]broker.Declared{}, People: map[string][]string{"operator": {"*"}, "guest": {"mesh-controller.status"}}, Interchangeable: map[string]bool{}} for _, m := range manifests { records.Assigned["anchor"] = append(records.Assigned["anchor"], declaredFor(m, seats, declarers)) } // And a second machine whose runtime carries an ordinary module: where agents run as the operator. records.Assigned["laptop"] = []broker.Declared{declaredFor(ordinary, seats, declarers), declaredFor(runtime, seats, declarers)} users, err := broker.Users(records) if err != nil { t.Fatal(err) } const verb = "mesh.seat.mesh-controller.tool.root-free" answerers := 0 for _, u := range users { p, err := broker.PermissionsFor(u) if err != nil { t.Fatal(err) } answers := grantsAny(p.Subscribe, verb) if answers != (u.Kind == broker.KindController) { t.Errorf("%s (%s) %s subscribe to %s", u.Username(), u.Kind, map[bool]string{true: "may", false: "may not"}[answers], verb) } if answers { answerers++ } // Nobody publishes into the router's inbox but as an answer to what it asked. for _, inbox := range []string{"_INBOX.anchor.messenger.x1.y", "_INBOX.anchor.messenger.>"} { if u.Username() != "anchor.messenger" && grantsAny(p.Publish, inbox) { t.Errorf("%s may publish into the router's inbox (%s) without being asked", u.Username(), inbox) } } } if answerers != 1 { t.Errorf("%d principals may answer root-free, want the controller alone", answerers) } }