diff --git a/03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md b/03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md index ae0ae8d2..16dcac84 100644 --- a/03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md +++ b/03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md @@ -2,7 +2,7 @@ layer: to-be status: in-progress code: [mesh-controller, mesh-host, mesh-tools, mesh-catalog, mesh-sdk, mesh-lab] -updated: 2026-10-09 +updated: 2026-10-10 decisions: - 02-DECISIONS/0271-a-send-held-for-the-buss-planned-step-is-told-to-the-operator-at-once-and-a-change-that-needs-it-says-so-before-it-merges.md - 02-DECISIONS/0265-a-verb-that-reads-is-answered-on-the-serving-controllers-own-connection-and-every-connection-says-what-it-is.md @@ -73,6 +73,7 @@ Every kind of state the core keeps, and the one component that writes it. Anyone |---|---|---|---| | a machine's declaration | controller (lease holder) | the bus, last per subject | read | | a hand-over asked of a machine ([issue 356](../../04-ISSUES/356-the-operators-command-ran-a-stale-engine-and-a-hand-over-had-no-channel/00-report.md)) | controller, at its terminal | the machine, beside its state | the engine verifies the mesh's signature and records it, or refuses | +| a fresh setuid search asked of a machine ([issue 361](../../04-ISSUES/361-the-control-nodes-agent-account-is-never-judged/00-report.md)) | controller, at its terminal | the machine, which throws its last search away | the engine verifies the mesh's signature and starts it, or refuses | | a machine's applied state and its report | the node-engine's apply queue (§6) | the machine; the report on the bus | the reconcile and a delivery *enqueue*, never apply | | the controller lease | the controller instance holding it | key-value `mesh-controller_lease` | a candidate waits | | plans and their tiers | controller (lease holder), compare-and-set on the plan's revision | the controller's store | read through `plans` | diff --git a/04-ISSUES/361-the-control-nodes-agent-account-is-never-judged/01-diagnosis.md b/04-ISSUES/361-the-control-nodes-agent-account-is-never-judged/01-diagnosis.md index 3838ff01..3ff4e930 100644 --- a/04-ISSUES/361-the-control-nodes-agent-account-is-never-judged/01-diagnosis.md +++ b/04-ISSUES/361-the-control-nodes-agent-account-is-never-judged/01-diagnosis.md @@ -110,3 +110,37 @@ engine agree. What it found, and what was done: every searched filesystem would report each change of mode or owner as it happens, turning the daily walk into a true incremental search. - **Resolution** of this core issue needs a replay in mesh-lab's register, or `replay-none:` with the reason. + +## 2026-10-10 — the search shows its progress, and the operator can ask for a fresh one + +- **The progress was kept and seen by nobody.** At 01:40 the operator asked how far the first walk on the + control-node had got. The walk kept its progress every minute beside the engine's state, but `root-free` said + only "not judged yet (search running), started 01:27", and no tool read further. The node-engine serves no + tools of its own, so the progress now travels where the verdict already does: the agent account's verdict + carries it as fields, and its reason gains one line that `root-free` repeats. The line holds filesystems done + of the total, the mount point being walked, the entries visited, the setuid- or setgid-root files found so far, + when the progress was last kept, and how long each finished filesystem took. Counts, times and mount points + only: the cursor and every file found are often under an account's home, and stay in the engine's state and + journal. The line moves at each checkpoint (once a minute) and is never part of what makes a verdict + "changed", so the journal does not repeat it every minute; the statement is said every minute anyway while + the account is not healthy. An entry is counted once across a resume, as it is kept with the cursor it + matches. The time a filesystem took counts only the time the engine walked it, not the time it was stopped. +- **A change by hand was not searched for until the next day.** The first complete search on the control-node + ended at about 01:48 and found two setuid-root programs no package owns, copies in the operator's home. When the + operator removes them by hand, no apply says so, and nothing searches again until the daily search. The + operator now asks for one at the controller's terminal: `nox node setuid-search ` on the control-node. + The controller signs the ask with the mesh's key, as it signs a hand-over, under a signing context of its own. + The engine throws away the last complete search and any walk under way or kept, and the next look starts a + full search. Until it completes, the verdict is "not judged yet", with its progress. +- **Why at the terminal alone, not a verb.** A search can never make a machine root-free wrongly: it judges only + once complete. But every ask throws a walk away. Asked again and again, it would keep the machine unjudged + for good and its disks busy, and whoever may call a verb includes agents. The operator needs the line only + after a change made by hand. +- **Considered, not built: judge only what the agent account can reach.** A setuid program under another + account's home with mode 0700 cannot be executed by the agent account, because it cannot traverse the + directory. Counting only files whose every parent directory the agent account may traverse would stop the + operator's own copies blocking `root-free`. It is not built, for three reasons. Root or the operator can make + a directory traversable later without any apply, so the verdict would rest on modes that change unseen. ACLs + and group membership have to be read for every parent. A program the agent cannot reach today is still one + no package owns. Deciding it is a change to ADR 0266 §3 item 10, made through playbook 02 if wanted. +