The module said MESH_BROKER_ADDRESS=${machine:at}:5671, and that cannot work in either
direction.
At genesis it does not resolve at all. `at` is a machine's name on the PRIVATE network,
and the mesh only holds one for a node that has an overlay placement and resolves the
networking module — neither of which exists when the control plane is installed, which
is step 9 of ten, long before anything has been placed anywhere. mesh-control refuses a
${machine:} key it does not hold rather than writing the literal through, so the push
would have stopped with "this machine says name".
And afterwards it would be the wrong address anyway. This value is what every enrolment
token tells a joining node to dial. A machine that has not enrolled is not on the
overlay, so an overlay name is precisely the one thing it cannot reach.
It is the substrate's own fact — the address the broker advertises, decided by whoever
wrote the bundle, which the mesh did not make and cannot invent. So it arrives the way
the store connections beside it arrive: an own-secret the installer delivers with
`secret accept`, read out of the bundle it produced. mesh-bootstrap already does this for
every variable the module fills from a secret; this one simply joins them.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
Its image is FROM scratch and runs as 65534. The host writes a sealed own-secret 0600,
owned by root, which is right — but the module then bind-mounted those three files into
the container and told the process to open them. It cannot:
$ docker run --rm -v <0600 root file>:/run/secrets/inventory:ro \
-e MESH_STORE_INVENTORY_FILE=/run/secrets/inventory mesh-control:development status
MESH_STORE_INVENTORY_FILE names /run/secrets/inventory ... and it cannot be read:
open /run/secrets/inventory: permission denied
Measured on a workstation, not reasoned about. Every other module in this catalogue gets
away with the same mount because its runtime container runs as root; this one does not,
and genesis (novox/hq ADR 0067) would have stopped at step 9 with a control-plane module
that starts and cannot open a context.
The connections go through the env file this module already has instead. That file is
mode 0600 and is read by the container runtime's client, which is root — the same reason
the broker's URL has always reached the process this way. It also sidesteps the inode
that a file bind mount pins (290be37, step-ca): --env-file is read afresh at create, and
restart-on names it.
The own-secrets stay exactly as they were, because the installer delivers the substrate's
real connection strings into them with `secret accept` before the first push — the mesh
did not make those credentials and cannot invent them.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
novox/hq ADR 0067 pivots genesis through a temporary control plane and then
reinstalls the control plane as an ordinary module pinned to a digest the mesh's
own registry assigned. That record notes the one thing missing: a control-plane
module manifest, which did not exist.
It could not be written honestly before now. The control plane read its store
connection from MESH_STORE_<CONTEXT>, that connection string carries a password,
and a manifest can put a sealed value into a file's `content` but has nothing
that substitutes into a container's `env`. So the manifest could carry the
password in the clear, or omit the setting. mesh-control now also accepts
MESH_STORE_<CONTEXT>_FILE, which is how every other module here is given secret
material, and the manifest follows.
What the substrate bundle gives the control-plane container today, and where
each part has gone:
MESH_STORE_INVENTORY own-secret `inventory`, mounted, named by _FILE
MESH_STORE_IDENTITY own-secret `identity`, mounted, named by _FILE
MESH_STORE_LICENCES own-secret `licences`, mounted, named by _FILE
MESH_BROKER_AMQP own-secret `broker`, through an env-file hole
MESH_BROKER_MANAGEMENT own-secret `broker-management`, likewise
MESH_BROKER_ADDRESS ${machine:at}:5671 in that same env-file
MESH_BROKER_CERTIFICATE plain env; the path is not a secret
network host, args ["serve"], the broker's TLS volume unchanged
The two broker URLs go through an env-file rather than a file of their own
because mesh-control has no MESH_BROKER_AMQP_FILE. That is the same fault one
layer over, and the same remedy would fix it; it is out of this change's scope
and is written down rather than papered over.
None of these values is in the manifest. Each is an own-secret the operator
supplies with `secret accept` — the mesh cannot invent a connection string — and
the container restarts when any of them changes.
The module claims `the-control-plane` at mesh scope, which the bundle has no way
to say: two control planes writing one inventory is a fault worth refusing at
assignment. It carries no `listens`, because `serve` dials the broker and binds
nothing. The image is the catalogue's placeholder digest for a mesh-built image,
which the installer replaces with what the registry assigned.
Checked with the real parser: all 67 manifests through catalogue.ParseManifest
and every module's CheckIdentity against all four node names — 0 problems — and
this manifest rendered through Resolution.Declaration, so the ${secret:…} names,
${machine:at}, the restart-on ids and the image pin are exercised rather than
merely parsed. Slug `control`: mesh_shanks_control is 19 of the 20 an S3 access
key keeps.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF