Judge a machine root-free only on a positive, fresh measure, and believe a verified sender only there (hq ADR 0259 §8, review H2/H3)
The agent-root probe read the sudo module's answer, given in the machine's runtime as the very account an agent could become, and took a missing account, a missing answer or no accounts as a pass. One judgement now decides: the machine names an agent account its node-engine judged unable to become root within 15 minutes (agentConfined, mesh-controller #164), and the login shell's execute is not served there; anything not read is not free. The probe raises agent-root on it, the new root-free verb answers it live for the router, and a push composes verified-sender for a kind only while its machine and the router's pass it.
This commit is contained in:
@@ -2,6 +2,7 @@ package broker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
@@ -167,12 +168,25 @@ func PlacementsOf(r Records, interchangeable map[string]bool) Placements {
|
||||
for _, nodes := range p.Nodes {
|
||||
sort.Strings(nodes)
|
||||
}
|
||||
// Where the router runs: a verified sender is believed only while its machine is root-free too. A router
|
||||
// placed nowhere, or on more than one machine, frees nothing.
|
||||
var routerNodes []string
|
||||
for node, declared := range r.Assigned {
|
||||
for _, d := range declared {
|
||||
for _, s := range d.Holds {
|
||||
if s.Name == routerSeat && !slices.Contains(routerNodes, node) {
|
||||
routerNodes = append(routerNodes, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
routerFree := len(routerNodes) == 1 && r.RootFree[routerNodes[0]]
|
||||
for node, declared := range r.Assigned {
|
||||
for _, d := range declared {
|
||||
for _, s := range d.Holds {
|
||||
if s.Kinded && s.Kind != "" {
|
||||
p.Kinds = append(p.Kinds, KindHeld{Seat: s.Name, Kind: s.Kind, Module: d.Module, Node: node,
|
||||
Capabilities: placedCapabilities(s.Capabilities, d.RunsAs)})
|
||||
Capabilities: placedCapabilities(s.Capabilities, d.RunsAs, routerFree && r.RootFree[node])})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,13 +204,19 @@ func PlacementsOf(r Records, interchangeable map[string]bool) Placements {
|
||||
return p
|
||||
}
|
||||
|
||||
// routerSeat is the seat the router of asks holds (novox/hq ADR 0259 §3).
|
||||
const routerSeat = "operator-channel"
|
||||
|
||||
// placedCapabilities is what a kind's claim promises, as far as its placement lets the router believe it
|
||||
// (novox/hq ADR 0259 §8): `verified-sender` only from a holder that runs as an account of its own, on a bus
|
||||
// account of its own — never one the machine's runtime carries as the operator's account.
|
||||
func placedCapabilities(declared []string, runsAs string) []string {
|
||||
// account of its own — never one the machine's runtime carries as the operator's account — and only while
|
||||
// its machine and the router's were root-free when composed (rootFree; the review of 2026-10-09, H3). The
|
||||
// membership carrying it is composed at a push, so it can outlive a pass that later fails: the router asks
|
||||
// the controller's root-free verb again before it honours an approval, and that is the check that holds.
|
||||
func placedCapabilities(declared []string, runsAs string, rootFree bool) []string {
|
||||
var out []string
|
||||
for _, c := range declared {
|
||||
if c == "verified-sender" && runsAs == "" {
|
||||
if c == "verified-sender" && (runsAs == "" || !rootFree) {
|
||||
continue
|
||||
}
|
||||
out = append(out, c)
|
||||
|
||||
@@ -251,7 +251,7 @@ func TestTheRoutersMembershipNamesEveryKindAndItsCapabilities(t *testing.T) {
|
||||
records := Records{Nodes: []string{"anchor", "laptop"}, Assigned: map[string][]Declared{
|
||||
"anchor": {router, {Module: "telegram", Holds: []Seat{tg}, RunsAs: "telegram"}},
|
||||
"laptop": {{Module: "desk-channel", Holds: []Seat{desk}}},
|
||||
}}
|
||||
}, RootFree: map[string]bool{"anchor": true}}
|
||||
where := PlacementsOf(records, nil)
|
||||
m := MembershipFor("anchor", router, where)
|
||||
if m.SeatTraffic == nil || len(m.SeatTraffic.Kinds) != 2 {
|
||||
@@ -329,12 +329,62 @@ func TestTheMachinesRuntimeNeverCarriesATrustedHolder(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// novox/hq ADR 0259 §8: verified-sender reaches the router only from a holder of its own account.
|
||||
// novox/hq ADR 0259 §8: verified-sender reaches the router only from a holder of its own account, on a machine
|
||||
// root-free when composed, with the router's own machine root-free too (the review of 2026-10-09, H3).
|
||||
func TestVerifiedSenderIsBelievedOnlyFromAHolderOfItsOwnAccount(t *testing.T) {
|
||||
if got := placedCapabilities([]string{"choice", "verified-sender"}, ""); namesVerb(got, "verified-sender") {
|
||||
if got := placedCapabilities([]string{"choice", "verified-sender"}, "", true); namesVerb(got, "verified-sender") {
|
||||
t.Errorf("a carried holder keeps verified-sender: %v", got)
|
||||
}
|
||||
if got := placedCapabilities([]string{"choice", "verified-sender"}, "telegram"); !namesVerb(got, "verified-sender") {
|
||||
t.Errorf("a holder of its own account lost verified-sender: %v", got)
|
||||
if got := placedCapabilities([]string{"choice", "verified-sender"}, "telegram", true); !namesVerb(got, "verified-sender") {
|
||||
t.Errorf("a holder of its own account on a root-free machine lost verified-sender: %v", got)
|
||||
}
|
||||
if got := placedCapabilities([]string{"choice", "verified-sender"}, "telegram", false); namesVerb(got, "verified-sender") ||
|
||||
!namesVerb(got, "choice") {
|
||||
t.Errorf("a holder on a machine not root-free keeps verified-sender, or lost the rest: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The kinds the router is told carry verified-sender only while the channel's machine and the router's are
|
||||
// both root-free as composed; no record of a pass is no pass, and neither is a router placed nowhere.
|
||||
func TestVerifiedSenderNeedsTheChannelsAndTheRoutersMachinesRootFree(t *testing.T) {
|
||||
tg := channelSeat("telegram")
|
||||
tg.Capabilities = []string{"choice", "verified-sender"}
|
||||
router := Declared{Module: "messenger", Holds: []Seat{operatorChannel()}, RunsAs: "messenger"}
|
||||
telegram := Declared{Module: "telegram", Holds: []Seat{tg}, RunsAs: "telegram"}
|
||||
verified := func(r Records) bool {
|
||||
for _, k := range PlacementsOf(r, nil).Kinds {
|
||||
if k.Kind == "telegram" {
|
||||
return namesVerb(k.Capabilities, "verified-sender")
|
||||
}
|
||||
}
|
||||
t.Fatal("telegram not placed")
|
||||
return false
|
||||
}
|
||||
same := func(free map[string]bool) Records {
|
||||
return Records{Nodes: []string{"anchor"}, Assigned: map[string][]Declared{"anchor": {router, telegram}}, RootFree: free}
|
||||
}
|
||||
apart := func(free map[string]bool) Records {
|
||||
return Records{Nodes: []string{"anchor", "relay"},
|
||||
Assigned: map[string][]Declared{"anchor": {router}, "relay": {telegram}}, RootFree: free}
|
||||
}
|
||||
if !verified(same(map[string]bool{"anchor": true})) {
|
||||
t.Error("both on one root-free machine: verified-sender withheld")
|
||||
}
|
||||
if verified(same(nil)) {
|
||||
t.Error("no record of a pass, and verified-sender kept")
|
||||
}
|
||||
if verified(apart(map[string]bool{"relay": true})) {
|
||||
t.Error("the router's machine not root-free, and verified-sender kept")
|
||||
}
|
||||
if verified(apart(map[string]bool{"anchor": true})) {
|
||||
t.Error("the channel's machine not root-free, and verified-sender kept")
|
||||
}
|
||||
if !verified(apart(map[string]bool{"anchor": true, "relay": true})) {
|
||||
t.Error("both machines root-free: verified-sender withheld")
|
||||
}
|
||||
noRouter := Records{Nodes: []string{"relay"}, Assigned: map[string][]Declared{"relay": {telegram}},
|
||||
RootFree: map[string]bool{"relay": true}}
|
||||
if verified(noRouter) {
|
||||
t.Error("no router placed, and verified-sender kept")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ type Records struct {
|
||||
// Interchangeable is each module whose definition says its instances are the same anywhere
|
||||
// (ADR 0160), which decides whether the module's plain subject is issued to every instance.
|
||||
Interchangeable map[string]bool
|
||||
// RootFree is each machine judged root-free when this was composed (novox/hq ADR 0259 §8): it names an
|
||||
// account agents run as, judged unable to become root by its node-engine, and serves no login shell
|
||||
// execute. A machine absent is not free: no record of a pass is no pass.
|
||||
RootFree map[string]bool
|
||||
}
|
||||
|
||||
// Users is every user the composed file should contain, in the order it will be written.
|
||||
|
||||
@@ -429,6 +429,15 @@ var ControllerVerbs = []Verb{
|
||||
"cause": "with consumer or older-than: the cause in a word (cleanup-waiting when absent)",
|
||||
}, nil, "confirm")},
|
||||
// What a consumer gave up on (novox/hq issue 330): kept in DEAD_LETTERS until a person acts on it.
|
||||
{Name: "root-free", Description: "Whether each machine named is root-free now (novox/hq ADR 0259 §8): no agent " +
|
||||
"there can become root without a person. Judged when asked, never from a condition: free only when the machine " +
|
||||
"names an account its agents run as, its node-engine judged that account unable to become root within the " +
|
||||
"last 15 minutes, and the login shell's execute is not served there. Anything else, a read that failed " +
|
||||
"included, is not free and says why. The router asks it before an answer from a channel proving its sender " +
|
||||
"may approve. Only reads.",
|
||||
Input: schema(map[string]string{
|
||||
"machines": "the machines to judge, separated by commas",
|
||||
}, []string{"machines"})},
|
||||
{Name: "dead-letters", Description: "Every message a consumer on the bus gave up on after handing it over " +
|
||||
"as often as it may, kept in DEAD_LETTERS: whose consumer, the subject, how often it was handed over and " +
|
||||
"when it was given up, newest first. With id: that one whole, with what it said. With deliver: hand it " +
|
||||
|
||||
Reference in New Issue
Block a user