Unify trunk on main: initialization → main #3

Merged
jschoubben merged 95 commits from initialization into main 2026-09-05 01:13:46 +00:00
2 changed files with 53 additions and 0 deletions
Showing only changes of commit c79b83c1bc - Show all commits
+33
View File
@@ -0,0 +1,33 @@
# Three machines, joined one at a time.
#
# The point is not the third machine. It is that adding one changes **every other node's** peer
# list: each existing node has to be told again, or the newcomer is on a network nobody else can
# see. A mesh that only configures the arriving node looks like it worked and is half a network.
#
# So this scenario exists to be raised, then grown — enrol two, push, check; enrol the third,
# push, and check that the first two changed.
scenario: growing-mesh
segments:
hosting:
kind: public
cidr: [192.0.2.0/24]
machines:
anchor:
at: { segment: hosting, address: [192.0.2.10] }
inbound: allow
laptop:
at: { segment: hosting, address: [192.0.2.20] }
inbound: allow
workstation:
at: { segment: hosting, address: [192.0.2.30] }
inbound: allow
images:
- postgres:17-alpine
- cloudamqp/lavinmq:latest
- mesh-control:development
place:
all: [host, runtime]
+20
View File
@@ -55,6 +55,16 @@ export async function buildBaseImage(
log(" installing a container runtime");
await incus(["exec", BUILDER, "--", "pacman", "-Sy", "--noconfirm", "docker"], 600_000);
// And the tools for the private network, for the same reason as the runtime: a sealed
// scenario cannot install them, so a lab that omits them cannot test connectivity at all —
// which is most of what the mesh does between machines.
//
// Installed here and NOT started. What a node runs is the mesh's decision, delivered as a
// declaration; a lab that brought the interface up itself would be testing its own setup
// rather than the mesh's.
log(" installing the tools for the private network");
await incus(["exec", BUILDER, "--", "pacman", "-S", "--noconfirm", "wireguard-tools"], 600_000);
// Trust the documentation ranges as plain-HTTP registries.
//
// A scenario's registry is scenery inside the scenario, serving over HTTP, and a runtime
@@ -70,6 +80,16 @@ export async function buildBaseImage(
await incus(["exec", BUILDER, "--", "systemctl", "enable", "docker"], 60_000);
await incus(["exec", BUILDER, "--", "systemctl", "start", "docker"], 120_000);
// Read back from the tool, not from the package manager (novox/hq 04-ISSUES/007).
const wg = await incusOk(["exec", BUILDER, "--", "wg", "--version"], 60_000);
if (!wg?.trim()) {
throw new BaseImageError(
`wireguard-tools was installed in ${BUILDER} and \`wg\` does not answer. Publishing ` +
`this would give every scenario a machine that cannot join a private network.`,
);
}
log(` ${wg.trim()}`);
// Read back from the runtime, not from the package manager. An installed package is not a
// capability (novox/hq 04-ISSUES/007), and this is the one place to catch that — after
// publishing, every scenario pays for it instead.