Carry the engine's verdict on each account declared never to become root, and its contract, in the node's health report, so the self-check's DA and D-root judge on the machine's own word (issue 1952, ADR 0266)

NodeHealth.Root: each such account's verdict (healthy, unhealthy with its way to root, unknown while the setuid search
runs), the module and resource declaring it. NodeHealth.Contract: the engine's statement contract, so a reader tells an
engine older than the judging. Test: a row in TestTheControlRecordsReadTheirWritersValues, read back byte-equal.
This commit is contained in:
2026-10-29 23:48:08 +01:00
parent 992ea0ab66
commit f3677eb6f3
2 changed files with 26 additions and 0 deletions
+4
View File
@@ -32,6 +32,10 @@ func TestTheControlRecordsReadTheirWritersValues(t *testing.T) {
`"relogin":[{"account":"jochen","module":"brother","resource":"brother.scanner","reason":"relogin needed: the session began before scanner","since":"2026-10-29T20:00:00Z"}],` +
`"found":[{"module":"photos","resource":"photos.library","path":"/srv/photos","reason":"used as found: owned by root","since":"2026-10-29T20:00:00Z"}],` +
`"at":"2026-10-29T20:00:00Z"}`, &NodeHealth{}},
// The engine's verdict on an account declared never to become root (ADR 0266), and its contract.
{"a node's health report, the agent account judged", `{"v":1,"node":"anchor","root":[{"account":"agent",` +
`"module":"claude-code","resource":"claude-code.agent","state":"healthy","since":"2026-10-29T20:00:00Z"}],` +
`"contract":13,"at":"2026-10-29T20:00:00Z"}`, &NodeHealth{}},
// A part pointing at another machine names it (issue 774): the hub's tunnel, held at the hub's machine.
{"a node's health report, a part pointing at the hub", `{"v":1,"node":"anchor","network":{"state":"unhealthy",` +
`"since":"2026-10-29T20:00:00Z","parts":[{"part":"tunnel","state":"unhealthy","reason":"the tunnel to the hub has not handshaken for over five minutes",` +
+22
View File
@@ -40,6 +40,13 @@ type NodeHealth struct {
Relogin []NodeAccount `json:"relogin,omitempty"`
// Found are the directories used as found.
Found []NodeDirectory `json:"found,omitempty"`
// Root are the engine's verdicts on each account a module declares never to become root without a person (novox/hq
// ADR 0266), sorted: the agent account's among them where a module declares it. What the self-check's DA and D-root
// judge an agent's confinement by, on the machine's own word.
Root []RootVerdict `json:"root,omitempty"`
// Contract is the engine's statement contract (mesh-host link's NodeKeyContract): a reader tells an engine older
// than a judging it reads (RootContract for Root) from one that judged nothing wrong.
Contract int `json:"contract,omitempty"`
// At is when the engine wrote this, on a change: never a reason to write.
At time.Time `json:"at"`
}
@@ -113,6 +120,21 @@ type NodeAccount struct {
Since time.Time `json:"since"`
}
// RootContract is the statement contract from which an engine judges an account's root (mesh-host link.RootContract).
const RootContract = 3
// RootVerdict is the engine's verdict on one account declared never to become root without a person: healthy (no way
// found), unhealthy (its reason starts "can become root without a person"), or unknown while its setuid search has not
// completed, with the module and resource declaring it.
type RootVerdict struct {
Account string `json:"account"`
Module string `json:"module"`
Resource string `json:"resource"`
State string `json:"state"`
Reason string `json:"reason,omitempty"`
Since time.Time `json:"since"`
}
// NodeDirectory is one directory used as found: the module declaring it, its resource and path, and why.
type NodeDirectory struct {
Module string `json:"module"`