Let a user say it never becomes root, so the agents' account can be judged

A declaration may now state root: never on a user (novox/hq ADR 0266), and a
health statement carries it under contract 3; the judging follows.
This commit is contained in:
jochen
2026-10-08 18:26:31 +02:00
parent e813391dcf
commit e420f6587a
2 changed files with 30 additions and 0 deletions
+20
View File
@@ -383,8 +383,25 @@ type User struct {
// has it not. On the account rather than on the unit, because it is the account's: two units of
// one account cannot disagree about it, and undeclaring one of them must not stop the other.
Linger *bool `json:"linger,omitempty"`
// Root says whether this account may become root without a person (novox/hq ADR 0266). "never"
// is the agents' own account: the login an agent session runs as on a machine where it must not
// reach root by itself. Empty asserts nothing, as Shell's does.
//
// **A statement the engine judges, never one it acts on.** The apply gives an account it creates
// no password, no sudo rule and no group beyond those declared, as it always has, and takes none
// away from one it finds: a sudo rule or a group granted by hand is a person's to remove, and a
// declaration that silently stripped them would be the mesh deciding what a person's machine
// grants. What "never" adds is the look: on every look the engine reads whether the account can
// become root by itself — by its uid, a group that grants root, any sudo rule, or a secret the mesh
// placed that it can read — and says it unhealthy while it can (internal/accounts), so the
// controller can tell a machine where it holds from one where it does not.
Root string `json:"root,omitempty"`
}
// RootNever is the one value Root takes besides empty: the account never becomes root without a person.
const RootNever = "never"
// Network is a named network on this machine.
//
// **A name and nothing else.** Not a driver, a subnet or a gateway: each of those is something a
@@ -478,6 +495,9 @@ func (u *User) validate(where string, _ bool) []string {
if u.Home != "" && !strings.HasPrefix(u.Home, "/") {
problems = append(problems, where+": a home directory is an absolute path")
}
if u.Root != "" && u.Root != RootNever {
problems = append(problems, fmt.Sprintf("%s: root is %q or absent, and %q is neither", where, RootNever, u.Root))
}
return problems
}
+10
View File
@@ -227,6 +227,12 @@ const LivenessContract = 1
// older host parses strictly and refuses the whole declaration for it.
const ReadinessContract = 2
// RootContract is the statement of a host that also reads a user's declared `root` and judges it (novox/hq
// ADR 0266): whether an account declared never to become root without a person can. Like the field before
// it, its presence is what tells the controller this host may be sent `root` on a user; an older host
// refuses the whole declaration for a field it does not know.
const RootContract = 3
// Health is one statement of every long-running resource's state on this machine (to-be 48 §4). Said in
// every report, as an event on each change, and again every minute while anything is not healthy — so a
// lost statement is not a lost fault.
@@ -355,6 +361,10 @@ type ResourceHealth struct {
// controller tell a unit that cannot run before a new login from one that is broken. Empty for anything
// the machine's own manager or a container runtime runs.
Account string `json:"account,omitempty"`
// Root is "never" on a verdict of kind KindAccount for an account declared never to become root without
// a person (novox/hq ADR 0266): healthy then also means the engine found no way for it to. Empty on
// every other verdict, and on an account judged for its groups alone.
Root string `json:"root,omitempty"`
}
// HealthSaid is the health event: a machine's statement between its reports, on HealthSubject.