ADR 0266 and issue 333: on the control node, agents run under an account of their own #225

Merged
mesh-admin merged 6 commits from decision/0266-agents-run-under-an-account-of-their-own into main 2026-10-09 10:56:11 +00:00
Contributor

The operator decided on 2026-10-08 that agents on the control node run under an account of their own, without sudo, and that the operator's account keeps its sudo. This is that decision written down, with the parts the operator left open filled in. Merging this accepts those parts too.

  • ADR 0266:
    • A node may name an agent account. The operator states it at the controller's terminal; no verb or setting can change it.
    • The claude-code module declares the account as a user with root: never.
    • The node-engine judges on every look that the account has no uid 0, no group that grants root, no sudo rule, and no readable secret placed for another account. That covers the tool runner's credential.
    • The self-check raises agent-can-become-root when the judgement fails or is missing. ADR 0259 §8 rule 2 reads the same judgement.
    • The agent's files are written as the agent through a helper.
    • The guard refuses any session not running as the agent account.
    • claude-agent starts a session through the operator's own sudo.
    • The tool runner stays on the operator's account, and the record says why.
  • Issue 333: the measured symptom. On the control node, the operator account has two passwordless sudo grants (the mesh's drop-in and a line set by hand) and is in the docker group.
  • To-be 36 §9: the design amendment, including the operator's day afterwards and the steps on the control node in order. The operator's own sudo is never touched.
  • Glossary: agent account.

The code pull requests:

  • mesh-host #61: the node-engine judges root: never.
  • mesh-controller: the node fact, the machine facts, the self-check invariant (pull request to follow, linked in a comment).
  • mesh-catalog #140: the module's code.
  • mesh-catalog (to follow): the manifest.

ADR 0259 is still on pull request 211, so it is named without a link. All four checks in merge-check.sh pass locally.

The operator decided on 2026-10-08 that agents on the control node run under an account of their own, without sudo, and that the operator's account keeps its sudo. This is that decision written down, with the parts the operator left open filled in. **Merging this accepts those parts too.** - **ADR 0266**: - A node may name an **agent account**. The operator states it at the controller's terminal; no verb or setting can change it. - The `claude-code` module declares the account as a `user` with `root: never`. - The node-engine judges on every look that the account has no uid 0, no group that grants root, no sudo rule, and no readable secret placed for another account. That covers the tool runner's credential. - The self-check raises `agent-can-become-root` when the judgement fails or is missing. ADR 0259 §8 rule 2 reads the same judgement. - The agent's files are written as the agent through a helper. - The guard refuses any session not running as the agent account. - `claude-agent` starts a session through the operator's own sudo. - The tool runner stays on the operator's account, and the record says why. - **Issue 333**: the measured symptom. On the control node, the operator account has two passwordless sudo grants (the mesh's drop-in and a line set by hand) and is in the `docker` group. - **To-be 36 §9**: the design amendment, including the operator's day afterwards and the steps on the control node in order. The operator's own sudo is never touched. - **Glossary**: *agent account*. The code pull requests: - mesh-host #61: the node-engine judges `root: never`. - mesh-controller: the node fact, the machine facts, the self-check invariant (pull request to follow, linked in a comment). - mesh-catalog #140: the module's code. - mesh-catalog (to follow): the manifest. ADR 0259 is still on pull request 211, so it is named without a link. All four checks in `merge-check.sh` pass locally.
Author
Contributor

Delivery novox/hq@cb907d5810a2 — delivered since 2026-10-09T10:56:38Z

Delivery plan — builds nothing: the change touches no module of the mesh's graph

Transitions

  • 2026-10-09 10:27 (new) → proposed (announced): novox/hq#225's head announced
  • 2026-10-09 10:28 proposed → checked (checked): the verdict names this commit
  • 2026-10-09 10:28 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-09 10:56 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-09 10:56 published → delivered (done): nothing for a walk to move

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/hq@cb907d5810a2` — **delivered** since 2026-10-09T10:56:38Z **Delivery plan** — builds nothing: the change touches no module of the mesh's graph **Transitions** - 2026-10-09 10:27 (new) → proposed (announced): novox/hq#225's head announced - 2026-10-09 10:28 proposed → checked (checked): the verdict names this commit - 2026-10-09 10:28 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-09 10:56 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-09 10:56 published → delivered (done): nothing for a walk to move The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
jschoubben added 4 commits 2026-10-09 09:03:30 +00:00
The operator chose this remedy for ADR 0259 section 8: an agent there could
become root through the operator account's sudo and docker group, and read the
tool runner's credential. Record the node fact, the node-engine's judgement
the self-check reads, the guard, and how a session starts; issue 333 holds
the measured symptom and to-be 36 the design.
The review found ways round the record: a verb that set the accounts, root
following a link below a home, a tool reading any path as the operator, a
restore written beside the agent's files, a stale verdict passing. Record each
bound, the exact ways judged and not judged, the guard on every tool and its
record's limits, and a rollout order the guard does not block.
The re-review closed the command verb to reads, moved enrolment to the
controller's terminal, widened what the node-engine judges, and found the
store's reader able to read every secret; say each, and that the boundary is
not in force until the store is fixed.
ADR 0266: say where the boundary stands on 2026-10-09, and the rollout's order
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
ee314a26ca
The routes found around the agent account since the record was written are
closed on main (the store's reader, places and served keys, what every session
obeys, execute withheld on the control node); the record names them, drops the
store gap it said kept the boundary from holding, and says plainly what still
remains, first the login shell's execute on the other nodes. To-be 36 §9 gains
the prerequisites and the order the parts go out in.
jschoubben force-pushed decision/0266-agents-run-under-an-account-of-their-own from cfa06b68bc to ee314a26ca 2026-10-09 09:03:30 +00:00 Compare
Author
Contributor

Rebased and brought up to date on 2026-10-09 (head ee314a2).

ADR 0266 §7 now says where the boundary stands. The store gap paragraph is replaced. The routes closed on main are named: the store's reader (issue 337), places, accesses and served keys at the terminal (issue 339), what every session obeys (issue 340), and execute withheld on the control node (ADR 0268).

What still remains, said plainly:

  • execute on the other nodes, the desk's terminal open and rofi_run all run a caller's command as that node's operator, who has passwordless sudo there.
  • Tool servers already on the bus.
  • The tool runner still runs as the operator.
  • The duplicate root probe in mesh-controller #154.

Smaller changes:

  • §7 records the engine's own agent-home refusal and plans retry.
  • The checked-by table names the engine test.
  • To-be 36 §9 gains step 0 (the prerequisites) and the order the parts go out in.

Code heads: mesh-host #61 b28d7bb, mesh-controller #164 926dbd7, mesh-catalog #140 c8fb001, #141 eacda6e.

**Rebased and brought up to date on 2026-10-09 (head ee314a2).** **ADR 0266 §7 now says where the boundary stands.** The store gap paragraph is replaced. The routes closed on main are named: the store's reader (issue 337), places, accesses and served keys at the terminal (issue 339), what every session obeys (issue 340), and `execute` withheld on the control node (ADR 0268). **What still remains, said plainly:** - `execute` on the other nodes, the desk's terminal `open` and `rofi_run` all run a caller's command as that node's operator, who has passwordless sudo there. - Tool servers already on the bus. - The tool runner still runs as the operator. - The duplicate root probe in mesh-controller #154. **Smaller changes:** - §7 records the engine's own agent-home refusal and `plans retry`. - The checked-by table names the engine test. - To-be 36 §9 gains step 0 (the prerequisites) and the order the parts go out in. Code heads: mesh-host #61 b28d7bb, mesh-controller #164 926dbd7, mesh-catalog #140 c8fb001, #141 eacda6e.
jschoubben added 1 commit 2026-10-09 09:49:27 +00:00
ADR 0266: the setuid search's bound is 15 minutes, and the two routes and the restart condition the review of 2026-10-09 found
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
d7999e6fc9
Item 10 said two minutes; the engine's bound is 15, with a two-minute limit
inside it still to settle. What still remains now names a build from another
repository registering a module (mesh-controller 174), the forge's tools
changing its protection (mesh-catalog 153), and the urgent condition every
engine restart raises (mesh-controller 175).
jschoubben added 1 commit 2026-10-09 10:27:15 +00:00
ADR 0266: an agent can merge its own pull request, and the restart condition's quiet counts on the controller's clock
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
cb907d5810
The record said a merge needs a person; the forge requires no approval and
the merge tool merges once the checks pass, so nothing enforces the
operator's yes. What still remains now says so, and that the restart fix
counts from when the controller first saw the search pending. Item 10 and
routes A and B describe the follow-ups of the review of 2026-10-09.
mesh-admin merged commit 2700ef7096 into main 2026-10-09 10:56:11 +00:00
mesh-admin deleted branch decision/0266-agents-run-under-an-account-of-their-own 2026-10-09 10:56:11 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/hq#225