The handshake gate already waits on every peer a non-hub interface holds.
The MTU probe and the path MTU targets now follow the dialled peers too, which
for a spoke is still its hub and in a full mesh is every peer.
Covers the declarations read from every host, the refusal of differing ones,
every peer pinned to its /32, no hub anywhere, the host of one mesh holding no
peer of the other, and a second run leaving every file alone.
The swarm output is byte-identical: the dev layout and the three-mesh example,
each with and without a controller, produced the same host_vars, wg.conf and
stdout before and after, with deterministic keys.
Under a svc-swarm-manager host the declarations stay the hub's own. Without
one, every host may declare the meshes, and hosts declaring different ones are
refused rather than merged, because a member would otherwise render a mesh
its peers do not know.
With no hub every joined host is a member, addressed from the same offsets a
spoke takes, and each host is primary on the first declared mesh it joined.
A topology may carry no hub. Its meshes then peer every member with every
other one, which is what a Compose deployment of several hosts needs: there
is no manager to route through.
A spoke dials its hub and does not listen, the hub listens and dials nobody,
and a member of a full mesh, which is neither a hub nor peered with one,
listens and dials every peer. The role reads these instead of testing is_hub
inline, so a full mesh needs no field the swarm inventory does not carry.
Compose hosts of one inventory join full meshes that each role opts into
through its networks.meshes, with no swarm manager and nothing hardcoded into
a role. The vpn axis decides per CI row, on a role's smallest variant only,
and a CLI test proves the shape on three throwaway hosts: I and II reach each
other, II and III reach each other, I and III do not.
Ticked with evidence from the local lab and the fork's CI runs: both VPNs
including the backup host, swarm advertising on the mesh, the prologue and
both passes over the mesh, key rotation converging, the mesh-off arm, the
axis rotation, pin and title, the measured MTU, nothing naming a mesh, the
three-mesh example, the role installing its own tooling, the NFS mount over
the mesh, the controller reaching the hosts it deploys over, the gate, and
swarm control, overlay and NFS carried over the mesh.
Dropped: rotating over a live mesh connection, which the prologue avoids by
rotating before the transport moves; the role being inert in compose, which
the backup host now contradicts; the failing-mount half of the NFS
criterion; and the port-reachability criterion with its claim in the user
story.
With nothing left open, make requirements-archive moved its heading into the
README and deleted the file.
Swarm always runs it, a compose host owning a mesh address runs it, a
compose host without one stays untouched, and an entry another host owns,
as the lab's credential reset leaves behind, does not count.
WIREGUARD_ENABLED followed the deployment mode alone. A swarm's backup host
is deployed in its own play, which resolves to compose mode, so the role was
included there and skipped: the hub listed it as a data peer and no tunnel
ever answered for it.
The layer now runs in swarm, as before, and on any host that owns a mesh
address the CLI wrote for it, read through the mesh_address lookup. A
compose host without a mesh stays untouched.
Proven on the local swarm lab (svc-dns-unbound, development layout): the
backup host brought up data at 10.100.1.12, passed the handshake and MTU
gate against the hub, the hub saw both data peers handshake, the backup host
reached a worker on the swarm mesh through the manager, and the drill and
both passes stayed green.
`make quality-high` on main (fea6f31d9f) rewrote two files in its
autoformat step:
- roles/sys-service/handlers/refresh_systemctl_service.yml: the
handler's `when` was wrapped by hand; the formatter wraps it at line
width. Both forms parse to the same YAML.
- tests/unit/python/roles/web-app-nextcloud/test_onlyoffice_check_deadline.py:
two over-long assertIn calls that ruff format splits.
A second autoformat run leaves the tree unchanged, so main is stable
under the formatter again.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On the Fedora, CentOS Stream and Manjaro workspace jobs install-lint
ran `puppeteer browsers install chrome-headless-shell --install-deps`
as root, and puppeteer rejected it with "apt-get does not seem to be
available". The installer only warned ("optional lint tool"), so
install-lint passed while mmdc had no browser.
--install-deps is now passed only where apt-get exists. Everywhere else
the libraries `ldd` reports missing are installed by soname: dnf and
yum through the RPM provide `<soname>()(64bit)`, pacman through the
first package `pacman -F usr/lib/<soname>` names (libgbm.so.1 is owned
by both mesa and mesa-amber, which conflict). browser_installed() also
requires every library to resolve, so the install-lint stamp stays
stale until the browser can actually load.
A failed npm install, a missing mmdc, a failed or timed-out browser
download and unresolved libraries now raise instead of warning.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Manjaro workspace job failed test-unit-ruby with "cannot load such
file -- minitest". Debian vendors minitest in libruby, but Arch ships it
as ruby-minitest and Fedora and CentOS Stream as rubygem-minitest, none
of which ruby pulls in. ensure_ruby_present now probes
`require "minitest"` and installs the distro package when the probe
fails, then fails loudly if minitest is still missing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Fedora and CentOS Stream workspace jobs failed TLS to pypi.org,
registry.npmjs.org and repo.packagist.org (CERTIFICATE_VERIFY_FAILED,
curl error 7). package-frontend/ca.sh put the frontend CA into the Arch
anchor dir /etc/ca-certificates/trust-source/anchors, which p11-kit on
the RedHat family never reads.
Probing for the anchor dir does not fix it: with-ca-trust.sh creates
both /etc/pki/ca-trust/source/anchors and
/etc/ca-certificates/trust-source/anchors on every update-ca-trust host,
so the probe in registry-ca.sh already picks the RedHat dir on a reused
Arch runner. Both scripts now install into both dirs, rebuild only when
one of them changed, and take CA_ROOT so unit tests run them against a
fake root.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
curl reads backslash escapes inside a quoted config value, so a password
with `"` or `\` reached the PDS altered (`a"b` as `admin:a`, `a\b` as
`admin:ab`). The sed step now escapes both characters before it builds
the `user` line.
Addresses the CodeRabbit review on #961.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
No conflicts across 121 incoming commits. The one file both sides changed is
tasks/stages/01_constructor.yml: upstream parks an applications carrier for
the swarm bootstrap roles after the add_host tasks, and keys the carrier on
the tokens file as well. This branch's mesh bootstrap opens and drops its own
block-scoped carrier before that point, so both keep working as written.
Upstream also brings ruff 0.17.0, distro-derived env keys, a scoped act outer
teardown, the stalwart relay rule, the onion apex redirect and image and
version updates; ruff 0.17 reformats nothing on this branch.