diff --git a/02-DECISIONS/0066-public-routing-is-name-agnostic.md b/02-DECISIONS/0066-public-routing-is-name-agnostic.md index ce711fd..61d6364 100644 --- a/02-DECISIONS/0066-public-routing-is-name-agnostic.md +++ b/02-DECISIONS/0066-public-routing-is-name-agnostic.md @@ -1,5 +1,5 @@ --- -topic: routing and names +topic: the tiers status: proposed date: 2026-09-09 deciders: jochen diff --git a/02-DECISIONS/0067-genesis-is-a-pivot.md b/02-DECISIONS/0067-genesis-is-a-pivot.md index 4b9dceb..ee2a355 100644 --- a/02-DECISIONS/0067-genesis-is-a-pivot.md +++ b/02-DECISIONS/0067-genesis-is-a-pivot.md @@ -1,4 +1,5 @@ --- +topic: the tiers status: proposed date: 2026-09-10 deciders: jochen @@ -121,7 +122,8 @@ machine auditable. An installer connects to plenty. Same tier, same delivery, di - [ADR 0006 — the substrate and the control plane](0006-the-substrate-and-the-control-plane.md), which pinned images by digest and named what a first node fetches. -- [ADR 0041 — the host depends on nothing that must be installed first](0041-the-host-depends-on-nothing.md), - the tier 0 property this keeps true by not putting the installer inside the host. +- [ADR 0005 — the node host](0005-the-node-host.md), which makes tier 0 the one thing installed by + hand and the only thing that changes a machine — the property this keeps true by shipping the + installer beside the host rather than inside it. - [`04-ISSUES/029`](../04-ISSUES/029-the-artifact-store-cannot-be-delivered-by-the-artifact-store/00-report.md), the same cycle one layer down, and the rule that a registry module is named and never built. diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 5a81355..f4b2847 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -98,6 +98,8 @@ python3 00-META/checks/index.py fail if stale - **0031** — [The control plane authenticates nobody, so identity is a module](0031-the-control-plane-authenticates-nobody.md) - **0033** — [The substrate is a store and a broker](0033-the-substrate-is-a-store-and-a-broker.md) - **0036** — [Bootstrap ends at a usable mesh, and the first credential comes from a person](0036-bootstrap-ends-at-a-usable-mesh.md) +- **0066** — [Public routing is name-agnostic, its names are resolved inside the mesh, and an internal authority can certify them](0066-public-routing-is-name-agnostic.md) *(proposed)* +- **0067** — [Genesis is a pivot: a temporary control plane installs the registry that makes it permanent](0067-genesis-is-a-pivot.md) *(proposed)* ### What runs on them, and how it gets there @@ -121,6 +123,7 @@ python3 00-META/checks/index.py fail if stale - **0050** — [Model access is vendor-agnostic, and a vendor is an adapter](0050-model-access-is-vendor-agnostic.md) - **0051** — [Shared data is the operator's, and a module is granted access to it](0051-shared-data-is-the-operators.md) - **0052** — [An init step is a container run once to completion, gating what follows](0052-a-step-that-runs-once-before-a-container.md) +- **0053** — [A scheduled step is a container run on a recurring schedule](0053-a-step-that-runs-on-a-schedule.md) ### How it is built @@ -149,4 +152,9 @@ python3 00-META/checks/index.py fail if stale - **0032** — [The local account owns the mesh; a surface delegates to a module](0032-the-local-account-owns-the-mesh.md) *(superseded)* - **0034** — [The local account owns the mesh, and a web application's login is not that](0034-the-local-account-owns-the-mesh.md) +### Unfiled + +- **0054** — [Model usage is a vendor-neutral record, produced by the adapter, at two grains](0054-model-usage-is-recorded-at-two-grains.md) — `topic:` is 'model access', which is not one of building it, checking it, how we work, the mesh, the tiers, what runs on it +- **0055** — [Model access is answered by a licence, or by a node that hosts the model](0055-model-access-is-answered-by-a-licence-or-a-node.md) — `topic:` is 'model access', which is not one of building it, checking it, how we work, the mesh, the tiers, what runs on it + diff --git a/04-ISSUES/041-a-sealed-credential-ends-up-in-the-process-environment/00-report.md b/04-ISSUES/041-a-sealed-credential-ends-up-in-the-process-environment/00-report.md new file mode 100644 index 0000000..2e6088a --- /dev/null +++ b/04-ISSUES/041-a-sealed-credential-ends-up-in-the-process-environment/00-report.md @@ -0,0 +1,58 @@ +--- +status: open +opened: 2026-09-10 +located-in: [] +fixed-by: +amended-design: +--- + +# 041 — A credential the mesh took care to seal ends up in the process environment + +## Symptom + +The mesh generates a module's own secret, **seals it to the machine and discards the plaintext** — +it cannot read the value back even if asked. The host unseals it into a file the module names, at +`0600`. + +Then the module hands it to its container as an environment variable, and the runtime puts it +where anything on that machine that can talk to the runtime can read it: `docker inspect` prints +it, and `/proc//environ` holds it for the life of the process. + +Observed while making the control plane an ordinary module. Its **store** connections were moved to +files, read by a `…_FILE` variable naming the path. Its **broker** credentials have no such variable, +so they are still delivered through an env-file — which the runtime turns into exactly the +environment above. Same credential handling, same machine, two different exposures, decided by +whether the program that reads it happens to accept a path. + +## Why this matters + +**The care taken elsewhere is what makes this stand out.** Sealing to a machine and discarding the +plaintext is expensive and deliberate: it exists so that a credential is readable only where it is +used. Handing that same value to the runtime as an environment variable gives it back to anything +that can run `inspect` — and `inspect` is a routine operation. It lands in support output, in +captured logs, in a screenshot of a terminal, and in any tooling that dumps container state. + +**It is not a module's mistake.** Nothing in the manifest format is being misused: placing a secret +into an env-file with `${secret:…}` is a supported shape and other modules use it. So each module is +correct on its own, and the property — *a sealed credential is not readable by everything on the +machine* — holds or fails per variable, by accident of what each program accepts. + +**And the two halves now disagree inside one module.** The control plane reads its store connection +from a file and its broker credential from the environment. A reader cannot tell from the manifest +which secrets are protected from `inspect` and which are not, because the manifest looks the same +either way. + +## Open questions + +- Should every program the mesh runs accept a path for anything secret — a `…_FILE` twin as a + convention rather than a thing each program decides? That is a small change in several programs + and a large one in what the manifest can promise. +- Should the manifest layer **refuse** `${secret:…}` inside a container's `env`, or inside an + `env-file`, once a path-shaped alternative exists? A rule nothing enforces is the shape this + repository keeps finding. +- Is there a case where the environment is genuinely the only channel — a program that cannot be + changed and reads no file? If so, what should the mesh say about that module, out loud, rather + than treating it as equivalent? +- What is the actual reach of the exposure on a node — which identities can talk to the container + runtime, and is that set smaller than "anything running as the operator"? The answer decides + whether this is a hardening item or something sharper.