package catalogue import ( "strings" "testing" ) // The router of novox/hq ADR 0259: it declares the operator's seat and the two kinded benches. func router() Manifest { return Manifest{Module: "messenger", Tools: []string{"open", "history", "notify"}, State: []StateDeclaration{{Name: "asks"}}, RunsAs: "messenger", SecretsOwner: "messenger", DefinesSeats: []SeatDeclaration{ {Name: "operator-channel", Scope: ScopeMesh, Accepts: []string{"ask", "cancel"}, Emits: []string{"decided"}, ByCaller: []string{"ask", "cancel", "decided"}, Records: []string{"asks"}, Serves: []Verb{{Name: "open"}, {Name: "history"}, {Name: "notify"}}}, {Name: "channel", Scope: ScopeMesh, Kinded: true, Accepts: []string{"show", "edit", "send"}}, {Name: "intake", Scope: ScopeMesh, Kinded: true, Emits: []string{"choice", "link"}, Proofs: []string{"code"}}, }, Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh}}, Uses: []string{"channel"}} } func aChannel(module, kind string) Manifest { return Manifest{Module: module, Claims: []Claim{ {Name: "channel", Scope: ScopeMesh, Kind: kind}, {Name: "intake", Scope: ScopeMesh, Kind: kind}}} } func TestTwoChannelsOfDifferentKindsHoldTheBenches(t *testing.T) { shelf := Shelf{"messenger": router(), "telegram": aChannel("telegram", "telegram"), "desk-channel": aChannel("desk-channel", "desktop")} if got := problemsFor(t, shelf); got != "" { t.Fatalf("two kinds were refused: %s", got) } for _, m := range shelf { if got := declaredSeatProblems(m); len(got) > 0 { t.Fatalf("%s: %v", m.Module, got) } } } func TestASecondClaimOfOneKindIsRefused(t *testing.T) { got := problemsFor(t, Shelf{"messenger": router(), "telegram": aChannel("telegram", "telegram"), "telegram-two": aChannel("telegram-two", "telegram")}) if !strings.Contains(got, `of kind "telegram", which telegram already claims`) { t.Fatalf("a second holder of one kind stood: %s", got) } } func TestAKindedBenchNeedsAKindAndNoOtherSeatTakesOne(t *testing.T) { got := problemsFor(t, Shelf{"messenger": router(), "nameless": aChannel("nameless", "")}) if !strings.Contains(got, "claims the kinded bench channel and names no kind") { t.Fatalf("a claim without a kind stood: %s", got) } odd := Manifest{Module: "odd", Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh, Kind: "telegram"}}} got = problemsFor(t, Shelf{"messenger": router(), "odd": odd}) if !strings.Contains(got, "only a kinded bench takes a kind") { t.Fatalf("a kind on a seat that is not kinded stood: %s", got) } dotted := problemsFor(t, Shelf{"messenger": router(), "dotted": aChannel("dotted", "a.b")}) if !strings.Contains(dotted, "not a usable name") { t.Fatalf("a kind that would widen a subject stood: %s", dotted) } } func TestOnlyChannelAndIntakeAreKinded(t *testing.T) { m := Manifest{Module: "x", DefinesSeats: []SeatDeclaration{{Name: "pager", Kinded: true, Accepts: []string{"page"}}}} if got := strings.Join(declaredSeatProblems(m), "; "); !strings.Contains(got, "only channel and intake are kinded") { t.Fatalf("another kinded bench was declared: %s", got) } } func TestTheNewRulesAreHeldToWhatTheSeatSays(t *testing.T) { m := Manifest{Module: "x", DefinesSeats: []SeatDeclaration{{Name: "thing", Accepts: []string{"do"}, ByCaller: []string{"undo"}, Proofs: []string{"code"}, Records: []string{"nothing"}}}} got := strings.Join(declaredSeatProblems(m), "; ") for _, want := range []string{"names thing.undo by its caller, which the seat neither accepts nor emits", "declares proofs on thing, which is not kinded", `read its records "nothing", which it keeps no state of`} { if !strings.Contains(got, want) { t.Errorf("not refused: %q in %s", want, got) } } } // Two kinds on one machine are two holders, and one kind on two machines is a second claimant. func TestEachKindIsItsOwnHolderWhenResolved(t *testing.T) { modules := []Manifest{aChannel("telegram", "telegram"), aChannel("desk-channel", "desktop")} held, problems := checkClaims(modules, Node{Name: "anchor"}, nil, nil) if len(problems) > 0 || len(held) != 4 { t.Fatalf("two kinds on one machine: held %v, problems %v", held, problems) } _, problems = checkClaims([]Manifest{aChannel("telegram", "telegram")}, Node{Name: "home"}, held, nil) if len(problems) == 0 { t.Fatal("one kind held on two machines was not refused") } } // A channel's capabilities come from the fixed vocabulary, and only a kinded claim carries any. func TestCapabilitiesAreTheVocabularysAndOnlyOnAKindedClaim(t *testing.T) { good := aChannel("telegram", "telegram") good.Claims[0].Capabilities = []string{"deliver", "choice", "verified-sender", "max-length:4096"} good.RunsAs = "telegram" if got := problemsFor(t, Shelf{"messenger": router(), "telegram": good}); got != "" { t.Fatalf("the vocabulary was refused: %s", got) } bad := aChannel("telegram", "telegram") bad.Claims[0].Capabilities = []string{"trusted", "max-length:lots"} got := problemsFor(t, Shelf{"messenger": router(), "telegram": bad}) for _, w := range []string{`"trusted"`, `"max-length:lots"`} { if !strings.Contains(got, w+", which channel-capabilities/1 does not have") { t.Errorf("%s was not refused: %s", w, got) } } odd := Manifest{Module: "odd", Claims: []Claim{{Name: "operator-channel", Scope: ScopeMesh, Capabilities: []string{"deliver"}}}} if got := problemsFor(t, Shelf{"messenger": router(), "odd": odd}); !strings.Contains(got, "only a kinded bench's claim carries them") { t.Errorf("capabilities on a seat that is not kinded stood: %s", got) } } // novox/hq ADR 0259 §8: a module saying warrants, or speaking for a kind that proves its sender, runs as an // account of its own — never carried by the machine's runtime, which runs as the operator's account. func TestATrustedHolderMustRunAsAnAccountOfItsOwn(t *testing.T) { r := router() r.RunsAs = "" if got := problemsFor(t, Shelf{"messenger": r}); !strings.Contains(got, "messenger must run as an account of its own") { t.Errorf("a router on the machine's runtime stood: %s", got) } tg := aChannel("telegram", "telegram") tg.Claims[0].Capabilities = []string{"choice", "verified-sender"} if got := problemsFor(t, Shelf{"messenger": router(), "telegram": tg}); !strings.Contains(got, "telegram must run as an account of its own") { t.Errorf("a verified channel on the machine's runtime stood: %s", got) } desk := aChannel("desk-channel", "desktop") desk.Claims[0].Capabilities = []string{"choice"} if got := problemsFor(t, Shelf{"messenger": router(), "desk-channel": desk}); got != "" { t.Errorf("a channel proving nothing was held to it: %s", got) } // A kind that is `private` shows a link's code, which links an account as the operator: its holder is // trusted with it, so it runs as its own account too (the confirmation review of 2026-10-09). private := aChannel("desk-channel", "desktop") private.Claims[0].Capabilities = []string{"choice", "private"} if got := problemsFor(t, Shelf{"messenger": router(), "desk-channel": private}); !strings.Contains(got, "desk-channel must run as an account of its own") { t.Errorf("a private channel on the machine's runtime stood: %s", got) } } func TestRunsAsIsAnAccountOfTheModulesOwn(t *testing.T) { ok := Manifest{Module: "telegram", RunsAs: "telegram", SecretsOwner: "telegram", OwnSecrets: OwnSecrets{"broker": {Path: "/var/lib/telegram/broker"}}, Resources: []map[string]any{{"id": "account", "type": "user", "name": "telegram"}}} if got := RunsAsProblems(ok); len(got) != 0 { t.Fatalf("a sound runs-as was refused: %v", got) } for want, change := range map[string]func(*Manifest){ "never root": func(m *Manifest) { m.RunsAs, m.SecretsOwner = "root", "root" }, "not an account name": func(m *Manifest) { m.RunsAs = "${machine:account}" }, "which it does not make": func(m *Manifest) { m.Resources = nil }, "declares no own secret": func(m *Manifest) { m.OwnSecrets = nil }, "they are the account's own": func(m *Manifest) { m.SecretsOwner = "" }, } { m := ok m.Resources = append([]map[string]any(nil), ok.Resources...) m.OwnSecrets = OwnSecrets{"broker": {Path: "/x"}} change(&m) if got := strings.Join(RunsAsProblems(m), "; "); !strings.Contains(got, want) { t.Errorf("want %q, got %q", want, got) } } }