Commit Graph
172 Commits
Author SHA1 Message Date
jschoubben b4f3eaf11b Release a whole-file hold once the file is declared written into (hq ADR 0102) 2026-09-22 18:33:45 +02:00
jschoubben bd3fd17ad8 Do not count the machine's own plumbing mounted into a container as found data (hq ADR 0103) 2026-09-22 18:33:29 +02:00
jschoubben a4e4632077 gofmt the store's firewall record 2026-09-22 18:33:13 +02:00
jschoubben 444ad8f3cf Record the forward policies before disabling ufw, so a retried retirement restores them (hq ADR 0100) 2026-09-22 18:33:09 +02:00
jschoubben aef4993d10 Hold an archive, a process's unit and a user found on an adopted node for an untaken module (hq ADR 0103) 2026-09-22 18:32:20 +02:00
jschoubben 491e04fb8f Load the guard before removing the derived filter when a node returns to adopted, and defer the adoption's orphans only on the flip (hq ADR 0103) 2026-09-22 18:30:13 +02:00
jschoubben b531c47486 Refuse an opening ufw would merge into a found rule that does other than a plain allow, and read log types in either place (hq ADR 0103) 2026-09-22 18:29:06 +02:00
jschoubben facf6af46a Add the mesh's members to a list found in a file written into, and take back only those (hq ADR 0102) 2026-09-22 18:27:51 +02:00
jschoubben 48a8f4cf9d Point the builder's package binding at the port given with --packages-port (hq ADR 0100) 2026-09-22 18:16:00 +02:00
jschoubben 4a095df2f9 Let go of a hold whose resource is no longer declared, touching nothing on disk (hq ADR 0100) 2026-09-22 18:14:37 +02:00
jschoubben 824cb60cbb Hold a found directory, a found service's unit, a container that would mount found data, and a step run in a held container on an adopted node (hq ADR 0103) 2026-09-22 18:14:37 +02:00
jschoubben d59d232656 Let a re-run of genesis find the package registry it raised itself under its own name (hq ADR 0100) 2026-09-22 18:08:20 +02:00
jschoubben 078e84c681 Read an adopted or converged node's mode from its state on a re-run of genesis, and refuse a flag that disagrees (hq ADR 0103) 2026-09-22 18:08:02 +02:00
jschoubben 52e139d96f Add no opening a found ufw rule already answers, since ufw takes rules differing only in comment for one, as captured on a lab machine (hq ADR 0103) 2026-09-22 18:06:47 +02:00
jschoubben da65f84c45 Read fail2ban's bans as no firewall, and an iptables-nft reject as a refusal, from rulesets captured on a lab machine (hq ADR 0100) 2026-09-22 18:04:48 +02:00
jschoubben 8e2f75454d Put back the forward policy ufw disable opens when the found firewall is retired, as measured on a lab machine (hq ADR 0100) 2026-09-22 18:03:30 +02:00
jschoubben 588ab71d14 Remove an adopted node's guard and openings last on the flip, and keep them if anything failed (hq ADR 0103) 2026-09-22 18:02:46 +02:00
jschoubben 9033e3da98 Retire the found firewall only on a converged declaration from the mesh, never on a carried apply (hq ADR 0100) 2026-09-22 18:01:49 +02:00
jschoubben c989b57439 Guard the broker's plaintext port too at an adopted genesis: the filter admits it from the private network only (hq ADR 0103) 2026-09-22 18:01:14 +02:00
jschoubben 14b3ffbd40 Guard only packets addressed to this machine, and load the guard before the network and stop it only at shutdown (hq ADR 0103) 2026-09-22 18:00:54 +02:00
jschoubben 0f126d137c Write into a file the machine shares instead of over it, and reload a service that re-reads its configuration instead of restarting it (hq ADR 0102) 2026-09-22 17:48:57 +02:00
jschoubben 6eabed63eb Reload the service manager's units before restarting a service whose files changed, and start the guard before the network as the controller declares it (hq ADR 0100) 2026-09-22 17:38:17 +02:00
jschoubben 3e0e6e6b7e Delete a forwarded opening the way ufw accepts it, and read a fresh machine's resolver as not in use — both measured on a lab machine (hq ADR 0100) 2026-09-22 17:37:01 +02:00
jschoubben 5e3dd3f59c Raise a machine in use adopted: keep its firewall, load no dropping table, guard the mesh's own ports, and take only the mesh's own modules (hq ADR 0100) 2026-09-22 17:32:44 +02:00
jschoubben 4811f176fd Refuse a converged genesis on a machine in use, naming every container and listener counted (hq ADR 0100) 2026-09-22 17:29:32 +02:00
jschoubben 3964d9da0a Take the foundation's ports as genesis inputs, check them free, and hand them to the controller as the node's settings (hq ADR 0100) 2026-09-22 17:28:36 +02:00
jschoubben 770f589401 Report what an adopted node holds, its firewall and what is reachable, and speak unasked when that changes (hq ADR 0100) 2026-09-22 17:22:31 +02:00
jschoubben 3c90d155b3 Converge openings through the firewall an adopted node was found with, and retire it only when the node converges (hq ADR 0100) 2026-09-22 17:19:49 +02:00
jschoubben 3a613113be Keep what an adopted node was found holding until its module is taken, and report it held (hq ADR 0100) 2026-09-22 17:14:04 +02:00
jschoubben fcc447c216 Read a node's adoption from every declaration, so the host knows which modules are untaken (hq ADR 0100) 2026-09-22 17:11:26 +02:00
jschoubben 406a5559b0 An enrolling node signs its request with the identity it just generated, so the mesh can tell it from anyone who knows its public key (novox/hq issue 083) 2026-09-22 14:33:31 +02:00
jschoubben eaebae7b36 Review of 083: the give-up message says to wait out the mesh's hold before asking again; the installer no longer says the token is spent when it may not be 2026-09-22 14:23:20 +02:00
jschoubben c8bbdb2da5 An enrolling node asks again, with the same request, while the mesh says it cannot answer — for as long as the mesh holds the token for it (novox/hq issue 083) 2026-09-22 14:07:25 +02:00
jschoubben 8da78de210 A run-once step names what it reads and runs again when it changed (novox/hq ADR 0099, issue 077) 2026-09-21 23:25:06 +02:00
jschoubben ffe7dbd348 Step 9 without a build is refused, and a test says so 2026-09-21 19:21:04 +02:00
jschoubben 8afbe57814 The pinning line shows the built image's id, not one digit of it 2026-09-21 15:27:13 +02:00
jschoubben 5223169226 Genesis registers the control plane with the manifest its build produced
The control plane's manifest existed twice: at the root of its repository, read
whenever the mesh rebuilds it from source, and as a copy in the catalogue, read by
genesis. Nothing kept them equal, and the first rebuild replaced the mesh's record
with the repository's shape while every later push was refused (novox/hq
04-ISSUES/072). The builder's one-shot result already carries the manifest it built,
artifact resolved to the image; step 3 keeps it and step 9 registers it, re-pinning
the built image's bare id to the reference the registry assigned. The catalogue is
still read for the registry's and the builder's manifests and for phase two.
2026-09-21 15:17:47 +02:00
jschoubben c32eada62b The base filter opens the bus and the registry in the input chain too
A container on the machine dialling a port the machine publishes reaches it
through the runtime's proxy — input, not forward — and the builder could not
reach the broker. The derived ruleset opens the mesh's own ports in both
chains; the base one now does the same.
2026-09-21 12:28:57 +02:00
jschoubben b72b71a989 The host applies the newest declaration, a file may be created once, the foundation filters first
031: a window of unacknowledged declarations is drained to the newest; the
rest are set aside and reported as superseded. 035: a file resource may say
create-once — written when absent, kept untouched when present (ADR 0087).
054: the bundle installs nftables and loads a base ruleset before the store
and broker, in the table the filter module later replaces (ADR 0088).
2026-09-21 12:11:52 +02:00
jschoubben c5c42376c1 The installer delivers any MESH_…_FILE own secret, not only the store's (ADR 0086) 2026-09-21 10:10:33 +02:00
jschoubben d756effc33 The broker-admin marker ends in a newline, and the transcript never says a credential
The verify reads the marker with the shell's read, which fails at end of file
without a line ending; the action ran and its verify said no. And the applier
reports each action with its command line, two of which now carry the real
store and broker passwords — the installer masks the values it made in
everything it says.
2026-09-21 01:32:51 +02:00
jschoubben 70d0f36896 Installer review: secrets are staged privately, and a bundle is 0600 whether or not it existed
From review: the store and broker passwords genesis makes were carried into
the controller through a world-readable file in /tmp, a bundle left at 0644 by
an earlier installer kept that mode while now holding them, a mesh raised by
the old installer would have been handed new passwords its servers do not have,
and the broker-admin action's marker did not depend on the value. Secrets now
stage in a 0700 directory owned by the controller's account; the bundle is
chmod'd; an existing store or broker volume with no credential file is refused
by name; the marker holds the password's fingerprint. Also: one install path
for the store, broker and vault, no error-string matching for the operator
key, and no unreachable fallback for the superuser.
2026-09-21 01:26:35 +02:00
jschoubben 036af3cfdc The export is its own installer step, and the result names the operator files 2026-09-21 01:11:52 +02:00
jschoubben ee0c8b856e Genesis makes the root secrets, the operator key, and installs the vault
The template raises the store with the password 'bootstrap' and the broker
with its image's default administrator, and the installer carried both into
the mesh as accepted secrets — permanent, and not secret (novox/hq issue 071).

Now the installer makes both credentials, once, at the paths the postgres and
lavinmq modules declare as their own secrets, rewrites the produced bundle to
use them (the store reads its password from a file; the broker's default
account is given the new password by an action before anything dials it), and
writes the bundle at 0600 since it now carries them.

Before the first secret is accepted it makes the operator's sealing key beside
the bundle and gives the mesh the public half, so everything minted from there
is sealed to it too (ADR 0085, amended). Phase three adopts the broker as the
lavinmq module beside the store and installs mesh-vault as a foundation module;
the run ends by writing the operator-sealed export beside the key.
2026-09-21 00:12:55 +02:00
jschoubben 1232031fb9 Correct store phrasing — a module gets a database only if it asks
Not "every module's database"; a module requests one via requires
postgres-database. The one server holds the controller's contexts and the
database of each module that asks for one.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 21:20:00 +02:00
jschoubben 9109a8c178 Phase 3.1: adopt the foundation store as the postgres module
InstallStore turns the mesh-store the foundation raised at genesis into the
postgres module, adopted in place: it verifies the module's server names the
same container and the same image the foundation is running (fail-fast on a
drift, rather than tearing down the mesh's store), then registers, builds the
provisioner, and carries the superuser in via secret accept — the mesh cannot
invent a credential that already made the databases (mirroring the control
plane's store-connection delivery, control.go). pinImage generalised to any
module for reuse.

Issue 051 (WBS 3.1). One server holds the controller's contexts and every
module's database.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 21:04:06 +02:00
jschoubben 121367319d Rename mesh-control -> mesh-controller, substrate -> foundation
One name per thing, per the HQ glossary: the module/container/image/binary/repo
becomes mesh-controller, the seat the-controller, and the store+broker pair the
foundation (embedded base bundles, default template and example lock renamed with
their go:embed directives). No behaviour change — a pure vocabulary rename.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 18:40:40 +02:00
jschoubben 01c7730fb3 Genesis raises gitea correctly: host network, honest SQL, matched ROOT_URL
Fixes found raising the package registry end-to-end in the lab: seed gitea's DB
with plain psql statements (no \gexec, no $$ DO-blocks that clash with the
shell); run gitea on the host network so it reaches the substrate store and
answers where the builder looks; set gitea ROOT_URL to the machine's loopback so
npm's stored credential matches the tarball host; keep the pivot's passwords so a
re-run is the same run; create the admin without re-enabling must-change-password.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 14:11:36 +02:00
jschoubben 1a7c9fdac3 gitea runs on the host network at genesis
So it reaches the substrate store's loopback-published postgres and answers where
mesh-bootstrap and the builder look for it.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 10:33:07 +02:00
jschoubben 79863068fc Genesis raises the package registry before it builds the base
The base (mesh-tools) resolves the SDK by version from the mesh's package
registry rather than cloning it from a git URL (hq ADR 0076, issue 053), so the
registry has to answer and the SDK has to be in it before the base build runs.

New steps, before base: seed gitea's database in the substrate store, raise
gitea's server on it, create the admin/org/team and the builder's account, seal
the builder its registry credential, and publish the SDK on a public base. gitea
is adopted as an ordinary module after the base, so its provisioner image can be
built. A minimal Go gitea admin client stands in until that module exists.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
2026-09-16 10:27:11 +02:00