Commit Graph
204 Commits
Author SHA1 Message Date
jschoubben 7352c846dd A module is told its port in a container's environment too (hq issue 088)
${port:…} answered only inside a file's content, and the one place a module
routinely writes its own address is a container's `env` — where the literal is
wrong on every node whose assignment differs from the manifest's number, and
wrong again on a node given that port as a setting (ADR 0100). Nothing checked
it: the value is a string like any other, and it fails at runtime, on one node.

Filled by the control plane, like a bound value: a port is not secret, so there
is nothing for the host to be the only witness of and it learns no new field.
That is the line ADR 0086 draws — its objection is to a secret being in an
environment at all, not to who fills one in — so a port crosses it and a
credential still does not. Same guard as before: a port the module never said it
listens on is refused, now naming the container and the variable.

The env map is the catalogue's, shared by every node running the module, and the
resource around it is a shallow copy, so a filled value goes into a fresh map —
otherwise the first node composed writes its own port into the manifest and
every node after it is told that one.

Inert on the catalogue as it stands: ${port:…} is written in one other place in
it, a file. Renamed off _files, which this no longer is.
2026-09-22 22:36:28 +02:00
jschoubben 729537e745 Tie the builder's carried binding to what the forge serves, and hold at shut
The builder carries a binding because at genesis nothing provides
`package-registry` to resolve one from; once the forge is a module the same
consumer is told what the forge serves. Nothing held the two to the same number,
so the catalogue could drift into dialling one port before the forge is assigned
and another after.

And `at` is now protected, for the reason it had to be: a setting that moves it
points the builder, and the registry password it sends, at a host somebody else
chose.

novox/hq 04-ISSUES/085
2026-09-22 21:56:51 +02:00
jschoubben 0e413e3e7a Hold the forge's port to the same rule as every other provider's
The package registry was the one foundation port not resolved from what its
module serves. Nothing in the controller had to change for it — `ports` on the
forge moves its container, what it serves and what consumers are told, and the
builder's carried binding is settable like any other mergeable file — but
nothing said so, which is how it came to be special in the first place.

Two tests over the catalogue's own manifests: the forge's port is given on a
node and reaches what it serves, and the builder's carried binding takes the
port from the node while keeping who the binding is with.

novox/hq 04-ISSUES/085
2026-09-22 21:40:08 +02:00
jschoubben fad8b30e43 Say that the guard names the runtime's bridges where the filter names their addresses (hq ADR 0103) 2026-09-22 19:51:10 +02:00
jschoubben 379f459498 Hold the filter module to reloading its rules and restarting only on its units (hq ADR 0102) 2026-09-22 19:47:43 +02:00
jschoubben 2cf8739a84 Clear the whole account an adopted node gave when it converges (hq ADR 0100) 2026-09-22 19:45:35 +02:00
jschoubben 87ecc9326e Refuse a port given for the whole mesh where it is set, not at every node's composition (hq ADR 0100) 2026-09-22 19:45:35 +02:00
jschoubben 0f3eedd163 Do not guard a port this node is told to open to everyone (hq ADR 0103) 2026-09-22 19:44:35 +02:00
jschoubben dd6aad4a2f Give a machine port only to a port a module's container publishes, which is the only one the mesh can move (hq ADR 0038) 2026-09-22 19:44:35 +02:00
jschoubben 65187d4de0 Wait for a held node without pinning a pool connection, and give up after a bounded wait naming it (hq ADR 0100) 2026-09-22 18:31:10 +02:00
jschoubben cc47330884 Reload the guard on its table rather than restart it, so a change leaves no port unguarded (hq ADR 0103) 2026-09-22 18:27:27 +02:00
jschoubben 689c2c6d33 Hold a node from composing to sending, so a push composed before converge or adopt is never sent after it (hq ADR 0100) 2026-09-22 18:10:04 +02:00
jschoubben 1eff586a40 Hold the filter module to replacing the stock unit's flushing stop (hq ADR 0100) 2026-09-22 18:06:15 +02:00
jschoubben 4bb19c9e40 Give a machine port one holder: refuse ssh's, another module's and a doubled one, and release the assignment a given port replaces (hq ADR 0100) 2026-09-22 18:05:31 +02:00
jschoubben ade6b2bfb6 Declare nftables before the guard's table, so a node joining adopted without nft can load it (hq ADR 0103) 2026-09-22 17:59:32 +02:00
jschoubben a2dfaaf4d1 Guard only packets addressed to this machine, and order the guard's unit before the network and against shutdown (hq ADR 0103) 2026-09-22 17:59:09 +02:00
jschoubben a82bfb41f2 Leave an IPv6 loopback mapping out of what a container publishes, reading ports from the end (hq ADR 0100) 2026-09-22 17:58:50 +02:00
jschoubben 8db66e9532 Derive the guard from taken modules only: their published private-network ports and their manifests' guards (hq ADR 0103) 2026-09-22 17:58:37 +02:00
jschoubben 28b7fb81ba Write the registry's trust into the runtime's file and reload the runtime instead of restarting it; prefix reload-on like restart-on (hq ADR 0102) 2026-09-22 17:51:38 +02:00
jschoubben c93128d82f Hold the catalogue's store, broker and filter manifests to what adoption needs of them (hq ADR 0100) 2026-09-22 17:33:09 +02:00
jschoubben dbf62b5212 Read the foundation's ports from each node's settings, wherever a port is used (hq ADR 0100) 2026-09-22 17:31:07 +02:00
jschoubben 1ea84f8b8f Take a module, converge a node after a preview, and return it to adopted, from the command line and the API (hq ADR 0100) 2026-09-22 17:27:35 +02:00
jschoubben 28894fa5bd Keep what an adopted node reports holding, the firewall it found and what is reachable on it (hq ADR 0100) 2026-09-22 17:23:09 +02:00
jschoubben c3b1617693 Declare openings and a refusal-only guard on an adopted node in place of the filter (hq ADR 0100) 2026-09-22 17:21:44 +02:00
jschoubben a86a6c2974 Carry an adopted node's mode and taken modules in every declaration, from one marshaller (hq ADR 0100) 2026-09-22 17:17:54 +02:00
jschoubben 1c32af6a22 Record whether a node is adopted and which modules were taken on it (hq ADR 0100) 2026-09-22 17:14:05 +02:00
jschoubben 4f3b4e6014 Review of 083: an upgrade handled during shutdown is left for the broker; an enrolment cut short by shutdown is told to try again; a refused redelivery says what it probably is 2026-09-22 14:39:15 +02:00
jschoubben 32b8af6a9b The enrolment proof's message has a known answer, repeated in the host's test 2026-09-22 14:33:33 +02:00
jschoubben 4567fa666c Review of 083: finishing an enrolment whose token was spent takes proof of the key's private half, a live lease and a first delivery — a public key alone cannot replay a spent token; shutdown leaves held messages for the broker; identical builds supersede; what is held leaves room in the prefetch 2026-09-22 14:33:13 +02:00
jschoubben a3b7e830c8 Review of 083: a message the store cannot take is held and retried on a ticker, not slept on, so enrolments are answered meanwhile; a newer one per subject supersedes; the password is replaced after the spend; the same presenter may finish after a lost answer; upgrades retry only on the store 2026-09-22 14:23:03 +02:00
jschoubben 1a41b88ed3 Nothing the control queue carries is lost while the store restarts: an enrolment claims its token and spends it last, and is asked to try again; build results, upgrades and catch-ups are handed back, bounded (novox/hq issue 083) 2026-09-22 14:06:28 +02:00
jschoubben 3fd0c37d22 Review of 082: a store killed mid-conversation is an outage and a wrong password is not; one report holds the queue at most two minutes, then is let go loudly; shutdown does not wait out the pause 2026-09-22 13:34:04 +02:00
jschoubben 047830a6b5 A report the store cannot take yet is handed back to the broker, not acknowledged and lost (novox/hq issue 082) 2026-09-22 13:25:13 +02:00
jschoubben 8152665298 The facts write the suffix the control plane composed the names with, handed down rather than written twice (review of issue 079); the fixture is keyed as production keys it 2026-09-22 01:27:50 +02:00
jschoubben b529c49cff A machine's names are not suffixed twice: the facts take the internal names the control plane hands them (novox/hq issue 079) 2026-09-22 01:13:28 +02:00
jschoubben 0d1f2a4152 Review: module issue's pre-check factored and tested; a pair delivery for a requirement the module keeps no secret for is refused; builder issue's usage says the module comes first 2026-09-21 23:58:36 +02:00
jschoubben 35c5c2bb9b secret accept is refused for a name the module does not declare, and a pair delivery for a requirement or local it has not got (novox/hq issue 078) 2026-09-21 23:31:06 +02:00
jschoubben e4da83496f A run-once step may name what it reads: the pair run-once + restart-on is no longer refused (novox/hq ADR 0099) 2026-09-21 23:31:06 +02:00
jschoubben b3486270d1 The control plane's recipe starts FROM the base its manifest declares, and an undeclared base is refused
The mesh's own images declare theirs now, so the refusal ADR 0097 deferred is live.
The builder's own image and the examples take arguments with defaults; make builds
them, not the mesh.
2026-09-21 22:16:10 +02:00
jschoubben 9f3790dcda Review: one local name is still a local name; a local name is unique; recovery knows it; recipes read as instructions; a tag before a digest; ask fails at once when nothing serves
A secrets object with one local name delivered no file. Two requirements could share
a local name. secret recover and the export could not tell two locals apart. The
recipe check missed continued lines and read heredoc bodies as bases. repo:tag@digest
kept the tag in the repository. ask now publishes mandatory, so a tool nothing serves
is said at once rather than after the wait.
2026-09-21 21:03:22 +02:00
jschoubben e81f352979 An undeclared COPY --from is refused; an undeclared FROM is said, not yet refused
The mesh's own images start FROM a public base — the control plane's, the builder's,
the tool runtime's — and refusing those refuses genesis. They declare their bases
next; until then the base is named every build, with the remedy.
2026-09-21 20:48:00 +02:00
jschoubben 6f6e1244d4 A build declares the vendor image it stands on, and a recipe fetches nothing undeclared
build.on takes {arg, image@sha256:…} beside {arg, module, artifact}: the image is
copied into the mesh's registry before the build (ADR 0096) and the recipe reads the
copy from the argument. A FROM or COPY --from naming a registry image the manifest
did not declare is refused before the build, naming it and the remedy; stages,
declared arguments and scratch are not fetches (novox/hq 04-ISSUES/064, ADR 0097).
2026-09-21 20:45:36 +02:00
jschoubben 412599de9a An upstream image is copied between registries, never through a machine's image store
A published image is an index over several architectures; pulled, the runtime's
store keeps the index and refuses to push one platform out of it. The builder now
reads the index and every manifest it names over the registry API, with the
anonymous bearer token the public hub hands out, moves each blob by digest into the
mesh's registry, puts the manifests and then the index under the module's repository,
and pins the index. Genesis, with no registry to copy into, keeps the pull
(novox/hq 04-ISSUES/046, ADR 0096).
2026-09-21 20:42:30 +02:00
jschoubben 5049d201c6 A provider keeps one grant file per holder, with the local name in its id and path
The lab's vault refused a declaration naming two files with one identity: the
two secrets of one consumer. The holder's suffix is in the resource id and the path now.
2026-09-21 20:41:19 +02:00
jschoubben 3e5c010c5e A need is kept once per provision, consumer, local name and provider
Two consumers of one same-node provision produced two raw needs and, fanned out per
consumer, four — the same credential twice for each. Harmless, since a pair is one
row however often it is asked for, and wrong all the same.
2026-09-21 20:38:01 +02:00
jschoubben 76773dfbf5 Several secrets expand where the consumer is known, not on the first module to mention the provision
The lab's two-secrets consumer was given one credential and no file: the expansion
ran on the resolver's walk over names, on whichever module mentioned the provision
first, and the per-consumer pass copied that. It expands in that pass now, and a
test has two consumers of one provision, one keeping one file and one keeping two.
2026-09-21 20:36:19 +02:00
jschoubben 973cda5d76 ask: the control plane calls a module's tool and prints its answer
A module serves tools under an account scoped to exactly that, and nothing else in
the mesh held an account that could ask one. The control plane does: ask publishes
on the RPC exchange with a private reply queue bound under its own name, checks the
correlation, prints the answer, and exits non-zero for a tool that answered with an
error or a module that never answered (novox/hq 04-ISSUES/049, ADR 0095).
2026-09-21 20:34:03 +02:00
jschoubben 6ae4ae1dba A module may hold several secrets from one provider, each a pair of its own
secrets: maps a requirement to several files under local names. Each local name is
its own need, its own pair credential (the pair is keyed on it: migration 0027),
its own file on the consumer, its own holder at the provider (the identity with the
local name after it) and rotates apart from the others. The plain shape is
unchanged and every existing row is the credential it was (novox/hq 04-ISSUES/069,
ADR 0094).
2026-09-21 20:28:16 +02:00
jschoubben 53a79a17a1 Review: a failure is the same by resource id, not by the host's words; bound files and /run/docker.sock are declared
The host's error text may carry a duration or a counter, and a resource looping on
it would never have read as stuck. The previous row is read and compared here.
Stuck needs a start to say. A container may mount the file a binding lands in; the
runtime socket is declared under both of its spellings; the catalogue-wide test
takes MESH_CATALOG.
2026-09-21 19:23:02 +02:00
jschoubben 396e05bb65 An operator delivers a pair credential, and the mesh never replaces it
secret accept grows --provider: the value is sealed to the consumer's node, the
provider's node and the operator's key, and the pair records origin 'accepted'.
An accepted pair is not remade when a key changes (the mesh does not hold the
value; the read is refused naming the remedy) and rotate refuses it (accepting a
new value is the rotation). The vault's third species has its entry
(novox/hq 04-ISSUES/070, ADR 0092).
2026-09-21 17:50:41 +02:00