From 1ad9959b16c812c3dfe06dc10a53a99b7ba2a7f2 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 9 Oct 2026 12:01:45 +0200 Subject: [PATCH] ADR 0272: say how the socket keeps ADR 0004, answer the operator and agent accounts only, and keep the bus request out of the SDK (ADR 0039) --- ...nly-where-no-agent-runs-as-its-operator.md | 60 +++++++++++++------ .../01-diagnosis.md | 4 +- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md b/02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md index 172377fd..f6e0b67d 100644 --- a/02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md +++ b/02-DECISIONS/0272-the-operator-reaches-the-controller-with-mesh-cli-on-every-node-and-a-node-is-the-terminal-only-where-no-agent-runs-as-its-operator.md @@ -105,7 +105,7 @@ only: a script, `sudo`, a cron line and any document meant to work everywhere sa `mesh-cli ` takes the controller's own command line, in the words the controller's commands and their refusals already use: `mesh-cli settings set zsh '{"execute":"withhold"}' --node ` is `settings set zsh … --node ` asked of the controller. It is run as the operator's own account, without -`sudo`: root is not the operator's account, and is answered as any other account (§4). +`sudo`: root is not the operator's account, and is refused (§4). `mesh-cli` holds no credential and reads no file of the mesh. It does one thing: it asks the node-engine on its own machine over a local socket, and prints what comes back. A process that carries `MESH_VERB` (a verb's own process) @@ -129,6 +129,13 @@ The node-engine serves a socket every local account may connect to. For each con The node-engine is trusted for its own node. Root on a node could claim any account there; root on a node that is the terminal is already the operator's, and §4 makes no other node the terminal. +**This is no listening control surface** in [ADR 0004](0004-a-node-and-how-it-joins.md)'s sense, and that record's +rule stands. The socket is a file under the node-engine's runtime directory with no network address, so nothing +dials it from another machine. Nothing sent to it acts on the node: the node-engine runs nothing it receives and +changes nothing; it adds what the kernel says and sends the request out over its own link, to a controller that +judges it like any other caller. Only the node's operator account and its agent account are answered, and both +already reach the mesh's verbs through the mesh MCP server (§4). + ### 4. The controller judges, and runs the line A line from node N, vouched as account A, **runs as the controller's terminal** when A is N's operator account @@ -141,11 +148,16 @@ A line from node N, vouched as account A, **runs as the controller's terminal** The controller runs it as it runs a verb's line, in a fresh process of its own binary with its own environment, but without `MESH_VERB`, and records the caller as *A through mesh-cli on N*. -**Every other line is an ordinary call.** It goes through exactly what the `command` verb does with a line: its -refusals today, and its list of reads once ADR 0266 §7 builds one. It runs with `MESH_VERB=mesh-cli`, so every -terminal-only change is refused with the controller's own reason. The answer adds one sentence saying why this -account on this node is not the terminal: an agent account, root, an account that is not the operator's, or a node -whose agents may run as its operator. +**A line from the node's operator account or its agent account that is not the terminal is an ordinary +call.** It goes through exactly what the `command` verb does with a line: its refusals today, and its list of +reads once ADR 0266 §7 builds one. It runs with `MESH_VERB=mesh-cli`, so every terminal-only change is refused +with the controller's own reason. The answer adds one sentence saying why this account on this node is not the +terminal: it is the agent account, or the node's agents may run as its operator. These two accounts already +reach the mesh's verbs through the mesh MCP server, so this widens nothing. + +**A line from any other account is refused**, root and every service account included, and the answer says +which account asked and that `mesh-cli` answers the node's operator and agent accounts only. Run as yourself, +not under `sudo`. **The control-node rule is no wider than today.** On the control-node the operator's account holds `sudo`, and until ADR 0266 is switched on so do the agents running as it: either could run the controller's binary as root @@ -159,18 +171,25 @@ and why or why not. `mesh-cli` prints the two streams and exits with the status. message is cut there and the cut is said; it is never silently short. Standard input is not carried: a command that reads it gets nothing and fails saying so. Streaming the output and carrying the input are later steps. -### 6. What is shared lives in the SDK +### 6. What is shared, and where it lives -The socket's path, the program's request and answer, and the request on the bus with its subject are one package -of the SDK (`mesh-sdk`), imported by `mesh-cli`, the node-engine and the controller. None of them keeps its own -copy. The list of what is terminal-only is not shared: it stays in the controller, its one judge, and `mesh-cli` -shows the controller's words. +- **The local protocol is the SDK's.** The socket's path and the program's request and answer are one package of + the Go SDK (`mesh-sdk`), imported by `mesh-cli` and by the node-engine. It is a local protocol a module's + program speaks to its node's runtime, which is what the SDK holds + ([ADR 0039](0039-what-the-sdk-holds-and-refuses.md), as [ADR 0188](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md) + reads it). +- **The bus request is the node-engine's and the controller's**, in their own link code, with a test on each side + holding the field names, as for the engine's health statement. A transport lives in no SDK (ADR 0188's note on + ADR 0039). +- **The list of what is terminal-only is not shared.** It stays in the controller, its one judge, and `mesh-cli` + shows the controller's words. ### 7. In what order it is built 1. **Phase 1.** The SDK package; the node-engine's socket and its request; the controller's answer, with the control-node as the terminal for its operator account; the `mesh-cli` module on every node. From then on the - operator types `nox …` on the control-node, and gets the ordinary calls on every other node. + operator types `nox …` on the control-node, and gets the ordinary calls on every other node. An agent account + is answered as soon as a node names one (ADR 0266 §1), whichever phase is live. 2. **Phase 2.** The agent-account route of §4 on a node other than the control-node, once ADR 0266 runs there (on the operator's own machines after the follow-up decision ADR 0266 names). 3. **Later.** Streamed output and standard input; a second factor for a node whose agents must share the @@ -190,21 +209,24 @@ shows the controller's words. operator, the operator's account is not the terminal, so this reaches nothing terminal-only there. - The alias hides any other `nox` in interactive zsh (Arch's `python-nox` installs `/usr/bin/nox`); `command nox` still reaches it. -- The node-engine gains a listener every local account may reach. It accepts one line per connection, bounded in - size and in time, and runs nothing itself. +- The node-engine gains a local socket every account on the machine may reach. It accepts one line per + connection, bounded in size and in time, runs nothing itself, and is never reachable from another machine + (ADR 0004 stands, §3). - The controller's own binary is still never on `PATH`. A record that says to type `mesh-controller ` at the terminal means `mesh-cli ` on the control-node from this record on. ## How it is checked -- **The SDK:** the request and the answer survive a round trip, and the subject names the node. +- **The SDK:** the request and the answer survive a round trip, and a request over the bound is refused. +- **The bus request:** a test in the node-engine and one in the controller hold the same field names. - **The node-engine:** a test connects to the socket as the test's own process and the request carries that process's user id and account; a connection whose credentials cannot be read is refused, never sent as anyone; a line over the bound is refused. - **The controller:** tests hold that a line from the control-node's operator account runs without `MESH_VERB`; - that a line from any other account, or from another node without a judged agent account, runs with - `MESH_VERB=mesh-cli` and a terminal-only change is refused with the reason; that a judgement older than - fifteen minutes is not one; and that an ordinary line meets every refusal of the `command` verb. + that a line from the agent account, or from another node's operator account without a judged agent account, + runs with `MESH_VERB=mesh-cli` and a terminal-only change is refused with the reason; that a line from any + other account, root included, is refused and runs nothing; that a judgement older than fifteen minutes is not + one; and that an ordinary line meets every refusal of the `command` verb. - **The catalogue:** the module's check passes, its archive places one file, and its shell contribution is the alias. - **Live, at acceptance (the operator's view):** on the control-node, in the operator's own shell, @@ -218,7 +240,9 @@ shows the controller's words. - [Issue 339](../04-ISSUES/339-a-verb-can-place-a-directory-at-the-machines-own/00-report.md), [issue 340](../04-ISSUES/340-an-agent-can-plant-a-hook-in-every-agent-session-on-the-mesh/00-report.md): what is terminal-only, and how a verb is told from the terminal. +- [ADR 0004](0004-a-node-and-how-it-joins.md): a node has no listening control surface. - [ADR 0181](0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md): the operator account. +- [ADR 0039](0039-what-the-sdk-holds-and-refuses.md), [ADR 0188](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md): what the SDK holds. - [ADR 0204](0204-a-module-contributes-shell-code-to-the-login-shell-in-named-slots.md): shell contributions. - [ADR 0267](0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md): a module builds from its own source. diff --git a/04-ISSUES/343-the-controllers-terminal-has-no-command/01-diagnosis.md b/04-ISSUES/343-the-controllers-terminal-has-no-command/01-diagnosis.md index 22e038ec..24c039fb 100644 --- a/04-ISSUES/343-the-controllers-terminal-has-no-command/01-diagnosis.md +++ b/04-ISSUES/343-the-controllers-terminal-has-no-command/01-diagnosis.md @@ -51,9 +51,9 @@ is reached. Four repositories, in the order they merge: -1. **mesh-sdk:** the socket's path, the program's request and answer, the bus request and its subject. +1. **mesh-sdk:** the socket's path and the program's request and answer, the local protocol (ADR 0039). 2. **`mesh-host`:** the node-engine serves the socket, reads `SO_PEERCRED`, names the account, and asks the - controller on `mesh.control..cli`. + controller on `mesh.control..cli`; the bus request is its own link code. 3. **mesh-controller:** the serving controller answers `mesh.control.*.cli`, judges the terminal (ADR 0272 §4), and runs the line through `runVerb`'s path, without `MESH_VERB` for the terminal and with `MESH_VERB=mesh-cli` otherwise, after the `command` verb's refusals.