diff --git a/03-DESIGN/01-to-be/12-a-module-repository.md b/03-DESIGN/01-to-be/12-a-module-repository.md index f5a23a8..1b2bc67 100644 --- a/03-DESIGN/01-to-be/12-a-module-repository.md +++ b/03-DESIGN/01-to-be/12-a-module-repository.md @@ -133,6 +133,65 @@ answered to the asker and kept nowhere. - **Nothing is published until everything is built.** Half a module in the store, under a digest the mesh never records, is reachable, unreferenced, and indistinguishable from something in use. +## What a module may build, and what it may only borrow + +| kind | is | +|---|---| +| **image** | built from a Dockerfile in this repository | +| **archive** | a directory in this repository, packed | +| **upstream** | an image somebody else built, mirrored into the mesh's own registry | + +**The third exists because a module usually runs software it did not write.** A database module +ships configuration and a provisioner and does not build a database. Naming the upstream reference +directly would need every machine to reach a public registry, and would pin to a tag its owner can +move — which is what pinning exists to prevent +([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)). Mirroring is what the +bootstrap already does by hand; this makes it something a module can say. + +An upstream reference with **no tag or digest is refused**: what gets mirrored would be whatever +`latest` means today, and a module pinned to that is not pinned. + +## A module's own secret + +A database has a superuser password, a broker an administrator, a registry an account. **None of +them is *for* anybody** — they are not the credential a consumer is given, and the mechanism that +hands those out has a consumer in the middle of it. + +So a module says what it needs and where to put it, and the mesh generates one **per node**, +seals it to that machine and reads it no more than it reads any other secret. Per node +deliberately: a module running on three machines has three passwords, where one in the manifest +would put the same secret on every machine that ever runs it, in a file anybody can read, for ever. + +Made once and kept, or a running database would be handed a password it was not started with. +Remade when the machine's sealing key changes. **Declared and not made is refused**, because a +module whose own credential is silently absent starts, fails to authenticate, and the reason is +three layers from the machine reporting it. + +## What one assignment gets you + +A database module, written to see whether it could be: + +``` +directory /var/lib/mesh/postgres +directory /var/lib/mesh/postgres/grants +container the database pinned by digest, mirrored +container the provisioner pinned by digest, mirrored +file the superuser password sealed to this machine +file what its consumers asked for +``` + +**The provisioner watches** rather than being invoked. That is what lets it be a module: run once, +it needs something to run it after every declaration — a timer, or a unit wired to a file. +Watching, it is an ordinary long-running service the host already supervises. It polls rather than +watching the filesystem, because the host writes atomically: the file is replaced, so a watch on +the path stops seeing anything after the first replacement, and a watcher that silently stops +working is worse than a poll. + +Writing it found one thing wrong, and it was the manifest rather than the host: a container +declared `restart-on`, which is a service field, and the host refused it by name. **It is right +to.** A container whose own definition changes is recreated, and a file it mounts is read by the +process inside, which is that image's business. + ## Where artifacts go **The registry the bootstrap already pulls from**, for both images and archives. An OCI registry