Issue 339: the terminal's settings are derived from what a module serves and which files it trusts; a found directory is its own condition the gate never reads as a fault
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

This commit is contained in:
jochen
2026-10-09 01:24:14 +02:00
parent 5fbd89c062
commit 5d054b722d
@@ -121,16 +121,24 @@ Until the node-engine's follow-up (below) lands, the only trace is that one outc
breaks, carriage returns and NUL. breaks, carriage returns and NUL.
- The spool, `/opt`, the container runtimes' data (`/var/lib/docker`, `/var/lib/containers`, - The spool, `/opt`, the container runtimes' data (`/var/lib/docker`, `/var/lib/containers`,
`/var/lib/containerd`) and any `.ssh` are added to the paths no placement or access may name. `/var/lib/containerd`) and any `.ssh` are added to the paths no placement or access may name.
- **The mesh's trust anchors are the terminal's too**, refused through every verb route exactly as - **What a provider serves, and what a trusted file asks for, is the terminal's too.** A setting overrides any
`places` and `accesses` are: key a provider serves (`Settle`), and what is served is what every consumer connects to and believes:
- step-ca's `root`, `roots` and `path`: the root its consumers are handed, and where they fetch the roots a database's or a registry's port, an object store's scheme, an identity provider's issuer and token path,
and the ACME directory; a model's name. Through the settings verb, any caller could point every consumer at a listener of its own
- the identity provider's `issuer`: the issuer every OIDC consumer checks a login's token against. and collect what they present. The third review found this; the first fix had listed two modules by hand.
The controller now derives the keys a verb may not change from the module's manifest (`TerminalKeys`):
- `places` and `accesses`;
- every key under the module's `serves`, and every setting a served value asks for (`${setting:…}`);
- every setting a file marked `trusted` asks for. `trusted` is a new manifest field on a file: true for a
file that root or a consumer trusts (a logind drop-in, an env file that says which uid a container runs
as, a script run as root), false otherwise. The controller takes it out before the declaration, because
the node-engine parses strictly.
Before this, any caller of the settings verb could replace the internal authority's trust anchor or the `module check` names every file that asks for a setting without saying `trusted`, counts them in a line the
issuer. The catalogue was read on 2026-10-09 for every served fact and every setting a file asks for, and catalogue's merge check can keep, and refuses them from 2026-10-30. On 2026-10-09 that was 5 files in the
these are the ones a consumer trusts. They are named in the controller (`TerminalKeys`), because no manifest catalogue and 13 in the media catalogue. Their `trusted` is set in a catalogue change that can land only
field says "this is trusted" yet. once a controller that takes the field out of the declaration runs: an older one would pass it to the
node-engine, which refuses an unknown field.
- **`mesh-host`, a directory used as found is said:** - **`mesh-host`, a directory used as found is said:**
- a WARNING line in every apply's log; - a WARNING line in every apply's log;
- its module's resource of kind `directory`, stated unhealthy on every look, with its owner, its mode and - its module's resource of kind `directory`, stated unhealthy on every look, with its owner, its mode and
@@ -141,16 +149,31 @@ Until the node-engine's follow-up (below) lands, the only trace is that one outc
**The gate reads it as a wait for a person**, the way it reads a wait for a new login **The gate reads it as a wait for a person**, the way it reads a wait for a new login
([ADR 0254](../../02-DECISIONS/0254-a-wait-for-a-persons-new-login-is-not-a-gates-failure-and-each-module-of-a-send-keeps-its-own-pass.md)). ([ADR 0254](../../02-DECISIONS/0254-a-wait-for-a-persons-new-login-is-not-a-gates-failure-and-each-module-of-a-send-keeps-its-own-pass.md)).
- The node-engine keeps when it first found the directory (`found_at`) across applies. - **Its own condition kind**, `directory-used-as-found`, raised when every unhealthy resource of the module
- A directory found before the send being judged is no fault of that build. The module's gate passes, and on that machine is a directory used as found. It is the operator's to resolve, a warning however long it
its verdict carries the wait: "uses … as found and waits for a person to hand it over". An urgent fix to stays open, never urgent, and cleared on the first statement that no longer says it. If anything else of
that module still reaches every machine. the module is unhealthy beside it, the module's ordinary unhealthy condition is raised instead, with the
- A directory found by that very send was brought by it, so the gate holds the module and, at its bound, directory among its resources.
puts it back. - **The gate never reads that condition as a fault of the build**, in both places it reads conditions:
the module's own (`judgeHealth`) and the machine's (`aboutTheMachine`). This is the same exemption the
relogin kind has, and it holds even when the condition was raised after the send.
- **From the health statement**, the node-engine keeps when it first found the directory (`found_at`)
across applies. A directory found before the send being judged is no fault of that build: the module's
gate passes, and its verdict carries the wait ("uses … as found and waits for a person to hand it over").
An urgent fix to that module still reaches every machine. A test holds this with the condition open and
raised after the send.
- **A directory found by that very send** was brought by it, so the gate holds the module and, at its
bound, puts it back.
- **Not done yet:** found before or after the send is judged by the node-engine's clock against the
controller's. A large clock skew between the two could misjudge it. Comparing by the declaration's
sequence instead is left for later.
- **`mesh-host`, the guard:** the same paths as the controller are added. The container runtime's data root - **`mesh-host`, the guard:** the same paths as the controller are added. The container runtime's data root
is read from its configuration: `data-root` in dockerd's `daemon.json`; `--data-root` (or the older `-g` and is asked of the running runtimes first (`docker info`, `podman info`), and read from their configuration
`--graph`) on its unit's `ExecStart` and in the unit's drop-ins; and `graphroot` in podman's beside that: `data-root` in dockerd's `daemon.json` or a `--config-file`; `--data-root` (or the older `-g`
`storage.conf`. `/var/lib/containerd` is refused as well. Two stores are not read. A containerd configured and `--graph`) on the unit's `ExecStart`, continued over lines, quoted, or through `Environment=` and
`EnvironmentFile=`, in the unit and its drop-ins; and `graphroot` in podman's `storage.conf`, as a basic or
a literal string. The asking and the extra forms are in a further pull request stacked on the first. `/var/lib/containerd` is refused as well. Two stores are not read. A containerd configured
elsewhere is not a runtime this mesh runs. Podman's rootless stores sit below each account's home, where elsewhere is not a runtime this mesh runs. Podman's rootless stores sit below each account's home, where
only that account's directories are placed anyway. An account's `.ssh` is refused as an access or a mount, and as a only that account's directories are placed anyway. An account's `.ssh` is refused as an access or a mount, and as a
directory anywhere but below its own account's home. directory anywhere but below its own account's home.