Commit Graph
14682 Commits
Author SHA1 Message Date
infinito-nexus-updater[bot] 2f47588040 update(images): update Docker image versions (web-app-shopware) 2026-09-30 14:59:27 +00:00
infinito-nexus-updater[bot] dbf4133d92 update(images): update Docker image versions (web-app-seaweedfs) 2026-09-30 14:59:22 +00:00
infinito-nexus-updater[bot] d15335dbad update(images): update Docker image versions (web-app-peertube) 2026-09-30 14:59:11 +00:00
infinito-nexus-updater[bot] 802c9dce19 update(images): update Docker image versions (web-app-odoo) 2026-09-30 14:59:05 +00:00
infinito-nexus-updater[bot] c5f97d8321 update(images): update Docker image versions (web-app-matrix) 2026-09-30 14:58:54 +00:00
infinito-nexus-updater[bot] a9e1d9bdf1 update(images): update Docker image versions (web-app-magento) 2026-09-30 14:58:49 +00:00
infinito-nexus-updater[bot] e1e0b4c05c update(images): update Docker image versions (web-app-joomla) 2026-09-30 14:58:44 +00:00
infinito-nexus-updater[bot] 1b4677ddd7 update(images): update Docker image versions (web-app-espocrm) 2026-09-30 14:58:24 +00:00
infinito-nexus-updater[bot] 1e9e1f44b8 update(images): update Docker image versions (web-app-erpnext) 2026-09-30 14:58:20 +00:00
infinito-nexus-updater[bot] a9a3fed195 update(images): update Docker image versions (svc-ai-ollama) 2026-09-30 14:58:08 +00:00
kevinveenbirkenbachandClaude Opus 5.5 a4d38f96d2 fix(agents): stop enabling third-party plugins for every contributor
The committed settings enabled the caveman and ponytail plugins from two
unpinned GitHub marketplaces for everyone who trusts the repository, and
plugin hooks run in the harness, outside the Bash sandbox. The block is
a leftover: since kevinveenbirkenbach/skills@3be5655b44, make
install-skills writes it to .claude/settings.local.json, so enabling the
plugins stays a per-developer choice.

Found while reviewing the settings after Hanno Horrmeyer's report; see
7ed60e1fc2.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:57:31 +02:00
kevinveenbirkenbachandClaude Opus 5.5 5e0bcee6f5 docs(agents): point the Assumption 10 link at its current heading
7ed60e1fc2 renamed the Assumption 10 heading in security.md, and the
link in sandbox.md still used the short #assumption-10 fragment, which
no heading slug matches. It now carries the full slug of the new
heading, the form 4efa892706 on feature/store-i18n uses for the old
one, so that branch's merge resolves the line by keeping main's side.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:57:31 +02:00
kevinveenbirkenbachandClaude Opus 5.5 d3a74eecda fix(web-app-mailu): point the setup link at the docs the role deploys
Mailu retired its 1.7 documentation, so the link answered 404 and
failed the external URL check. 2024.06 is the version meta/services.yml
deploys, so the reader lands on the documentation for the release they
are running; master is Mailu's unreleased trunk.

The line is identical to c333fdef20 on feature/store-i18n, which keeps
that branch's merge into main free of a conflict on it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:57:31 +02:00
kevinveenbirkenbachandClaude Opus 5.5 4e1c8e2de1 fix(agents): deny rm -rf and the host credential files in the sandbox
An external report flagged the Bash(*) allow in the committed
.claude/settings.json. Bash(*) stays: every command still runs inside
the OS sandbox, and deny and ask take precedence over it. Reviewing the
file against its own documentation turned up two real gaps instead.

security.md and settings.md cite an rm -rf* deny rule as the guard
against `rm -rf .` wiping the worktree and .git/, but the rule was lost
in ee30f6d446 when the deny list was rewritten. It is back.

denyRead covered ~/.aws, ~/.config/gcloud, ~/.gnupg and ~/.kube only.
~/.docker/config.json holds registry logins inline, ~/.git-credentials
and ~/.netrc hold plaintext credentials, and the default ~/.ssh/id_*
keys were readable because Assumption 10 kept ~/.ssh open for an
ask-gated git push that has since moved to deny. All nine paths are
denied now. The rest of ~/.ssh stays readable, so SSH fetches keep
known_hosts and authenticate through the agent socket. Sandboxed docker
calls pull anonymously and print a config warning on stderr.

Thanks to Hanno Horrmeyer for the report.

Reported-by: Hanno Horrmeyer
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:57:30 +02:00
Alejandro Roman c2ed7ce209 fix(stalwart): moved the provision to only keycloak use 2026-09-30 17:10:48 +04:00
Alejandro Roman 6144c85978 fix(stalwart): fixed secrets 2026-09-30 16:00:58 +04:00
Alejandro Roman 90a0f06396 fix(e2e): confirm the mapache password reset inside its dialog 2026-09-29 23:32:36 +04:00
Alejandro Roman 9d184dd914 fix(mailu): replace dead 1.7 docs link 2026-09-29 18:57:00 +04:00
Alejandro Roman 73b2593e47 fix(swarm-stalwart): mapache once and make fixes regarding comments 2026-09-29 18:31:02 +04:00
Alejandro Roman 715abcd56e Merge remote-tracking branch 'upstream/main' into feature/role-stalwart-mail-swarm 2026-09-29 13:43:01 +04:00
evangelostsak 94f2401fab test(mesh): pin one key per host across a rotation
Asserts the hub's two mesh entries carry the same key and that its spoke holds
it. A first attempt matched only the first entry and passed against the bug.
2026-09-29 08:59:23 +02:00
evangelostsak 9feb2c3d2a fix(mesh): keep one key per host through a rotation
A host in two meshes has one private key, so the second mesh must reuse what
the first minted. The lookup prefers the entry of the mesh being written, which
after a rotation is the stale pre-rotation key, so the hub ended up advertising
one key on the swarm plane and another on the data plane while holding the
private half of only one. Its workers could never handshake again.

The run now carries what it decided: a host keyed while planning one mesh keeps
that key for every mesh after it.
2026-09-29 08:59:18 +02:00
evangelostsak a6c9f98d6a fix(mailu): point the setup guide at the live docs
mailu.io/1.7/compose/setup.html is gone; the versioned tree was restructured
and 1.7 predates it. The external suite fails the pipeline on it, which skips
every deploy chunk.
2026-09-29 01:27:22 +02:00
evangelostsak 9a942d77d9 refactor(swarm-test): drop the mesh placement explanation comment 2026-09-29 00:54:30 +02:00
evangelostsak 3cd6860a18 docs(037): the seam rotates the mesh on purpose
Records that the round asks for the rotation rather than inheriting it, so
the two rotation criteria are exercised every round.
2026-09-29 00:51:21 +02:00
evangelostsak eaa54122ac feat(swarm-test): ask for the rotation the round tests
The second write rotates, so the converge, the controller join and the second
pass all run against keys that changed mid-deploy. Also trims the reset
narration.
2026-09-29 00:51:17 +02:00
evangelostsak ea637a85eb feat(swarm-test): rotate the mesh in the seam
write_mesh takes rotate, so the round mints a fresh keypair for every member
between the passes and the converge that follows carries them. The rotation is
asked for rather than inherited from a mirror that happened to wipe the keys,
which is what the requirement's two rotation criteria describe.
2026-09-29 00:51:00 +02:00
evangelostsak 627d77ace2 refactor(swarm-test): trim the extras narration 2026-09-29 00:50:55 +02:00
evangelostsak 2ff34b8972 refactor(constructor): drop the bootstrap explanation comments 2026-09-29 00:50:51 +02:00
evangelostsak 019ba0d1ec refactor(nfs): drop the export's explanation comment 2026-09-29 00:50:51 +02:00
evangelostsak 2837b6aea4 refactor(nfs): drop the probe's explanation comment 2026-09-29 00:50:51 +02:00
evangelostsak 7dd8be1ab5 refactor(mesh): drop the writer's explanation comments 2026-09-29 00:50:45 +02:00
evangelostsak b8a96c2a6f refactor(mesh): drop the prune explanation comment 2026-09-29 00:50:45 +02:00
evangelostsak 3bd54c1ae9 refactor(wireguard): drop the gate's explanation comments 2026-09-29 00:50:45 +02:00
evangelostsak 1b1be2378c refactor(wireguard): drop the rationale comments 2026-09-29 00:50:29 +02:00
evangelostsak 3c1f1a39d6 refactor(nfs): drop the temporary leftover listing
It was there to name the cause when the guard fired on a healthy host. The
cause is settled -- the whole-stream comparison, not the mount -- so the probe
goes back to reporting state alone.
2026-09-29 00:20:32 +02:00
evangelostsak ce99df81cc fix(nfs): list the leftovers with find
shellcheck SC2012: parsing ls output mishandles non-alphanumeric names, and
these are the names an operator has to act on.
2026-09-28 18:30:00 +02:00
evangelostsak 14136cc0f3 fix(nfs): match the tagged state on the controller
Both readers move together: the assert and the when that unmounts a foreign
source. The controller runs locally today, so this keeps the two call sites
reading one contract rather than fixing only the one that broke.
2026-09-28 17:13:24 +02:00
evangelostsak 3c83b0f5d9 fix(nfs): match the tagged state on the client
The mount was present on every node while this assert reported local data:
the second pass reaches them over ssh with a password, which allocates a pty,
and the whole-stream comparison cannot survive that. The failure now carries
what the probe saw.
2026-09-28 17:11:39 +02:00
evangelostsak 5ca7f2a44d fix(nfs): tag the pre-mount state and name what it found
Ansible allocates a pty whenever become needs a password, and a pty merges
stderr into stdout, so a caller matching the whole stream reads login noise as
the answer. The state is tagged so a match is a substring rather than the
whole stream.

The local-data branch also lists what it found, because 'migrate or remove the
local tree manually' is not actionable without it. Temporary: it comes out
once the transport question is settled.
2026-09-28 17:11:34 +02:00
Alejandro Roman a390fea9e9 fix(swarm-stalwart): fix CI issues, cmments mapache 2026-09-28 18:23:16 +04:00
evangelostsak 7634c1ed32 test(mesh): pin the controller's key across a rerun
Without the fix its public half changes on every write, which is what made
the hub re-render and re-key a tunnel nothing had asked to rotate.
2026-09-28 15:44:30 +02:00
evangelostsak 10cb6d979c fix(mesh): keep the controller's key across a rerun
The existing-key lookup walked the inventory hosts, and the controller joins
by name rather than through a group, so it was the one member whose key was
never found and always minted fresh. Every write then changed the hub's peer
list, and the converge re-keyed the swarm tunnel for no reason.

all_hosts already accounts for the controller two lines above; the lookup now
uses it, as the prune already does.
2026-09-28 15:44:13 +02:00
kevinveenbirkenbachandClaude Opus 5.5 5bd4f778c3 ci(deploy): serialize identical deploy rows again, keyed on every axis
9850d5afa0 disabled the job-level deploy group because it blocked the
queue and kept jobs from being cancelled. Both causes are addressed:

- Cancelling: the chunks that call this workflow guarded with always(),
  so a cancelled run kept its deploy jobs alive and they kept holding
  their groups. Since a5f00ca777 the chunks guard with !cancelled() and
  die with the run, which releases the group.
- Blocking: the key held only mode, tor, apps and variant, so rows that
  differ in distro or filesystem waited on each other across branches.
  The key now carries every axis the matrix generator emits, the same
  set artifact_slug identifies a deployment by: mode, tor, distro,
  filesystem, apps and variant. Two runs now only meet on an exactly
  identical deployment. A sample matrix of eighteen rows had every axis
  set and no duplicate key within the run.

queue: max keeps the second identical row queued instead of replacing
the waiting one; GitHub accepted the key in all 200 runs of August,
and scripts/lint/action.sh already ignores actionlint's unknown-key
report for it.

No resource shared per row was found in the deploy path: jobs push no
images, write nothing through the API and use no actions/cache, and
hosted runners are isolated. The serialization is the cross-branch
ordering ae9d7c2fd3 introduced, not the protection of a resource.

A TODO asks a CI deploy to confirm that a cancel drops queued jobs
from the group and that an identical row of a second run queues
behind it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 12:52:40 +02:00
kevinveenbirkenbachandClaude Opus 5.5 f58713843f ci(deploy): fail fast on pull request runs
On pull_request and pull_request_target the deploy and workspace
matrices now run fail-fast: the first failed row cancels its siblings
in that matrix. A deploy chunk holds around sixty rows, and hosted
runner slots have been the bottleneck, with PR jobs waiting from twenty
minutes to twenty-one hours for a runner. Once one row is red the PR is
red regardless, so the remaining rows only hold slots other runs need.

Push, workflow_dispatch and cron runs keep fail-fast off: main and the
manual sweeps are where the full failure picture is wanted.

The expression reads github.event_name, which inside a reusable
workflow is the caller's event, so both calls see the PR event of the
entry workflow. A red chunk already stops the later ones through
chunk_gate, and done reports the run red. Cancelled rows still run
their always() upload steps, and the failed-run retrigger selects
cancelled roles by default, so a follow-up rerun covers them.

CodeQL keeps fail-fast off: one failing language would cancel the
analysis of the others and lose findings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 12:52:40 +02:00
evangelostsak ba4b8cd6f5 test(credentials): cover the kept subtree
The destination keeps its own block and still takes the rotated values around
it; a destination without that block takes the source's.
2026-09-28 11:46:01 +02:00
evangelostsak db774b6190 fix(swarm-test): keep the mesh out of the credential mirror
The mirror wiped each host's mesh block, so the write that follows minted a
fresh keypair for everyone and the converge re-keyed tunnels the deploy was
already running services over. The NFS state mount rides the data mesh and is
soft in CI, so a re-handshake dropped it; the second pass then found local
data under /var/lib/infinito and refused to mount over it.

Production never mirrors host_vars and mounts hard, so this only removes a
scenario the harness invented for itself.
2026-09-28 11:45:49 +02:00
evangelostsak 56cfdca4ff feat(credentials): let the mirror keep per-host material
The mirror copies one host's file over every other so a rotation reaches all
of them, which is right for a shared secret and wrong for anything a
generator writes per host: the copy hands every node the source's identity.

--mirror-keep names the subtrees that belong to the destination and are put
back after the copy. Absent, the mirror behaves exactly as before.
2026-09-28 11:45:34 +02:00
kevinveenbirkenbachandClaude Opus 5.5 a5f00ca777 fix(ci): let a cancel reap jobs guarded by always()
Closing a PR left "Cancel: PR Runs on Close" (run 36385268627) on
pending for hours. The canceller joins the PR orchestrator's
concurrency group, so GitHub cancelled the orchestrator run within a
second. But a cancel re-evaluates the job-level if: of every live job
and spares each one whose condition still holds. The deploy chunks
started with always(), which always holds: test-workspace died at
06:11:59, while Chunk 0 kept deploying and its ~60 queued matrix jobs
kept waiting for runners. The group stays occupied until the occupant
is terminal, so the canceller parked behind the very run it had
already cancelled.

The chunks, test-runner-smoke, the fork-prereqs gate and the release
job now guard with !cancelled(). Outside a cancel it matches always():
they still run after a failed or skipped need. On a cancel it turns
false and the job is cancelled with the run.

done and report-main-failures keep always(). They exist to report a
cancelled run, and a done skipped on cancel would count as a passing
required check.

The new lint walks every workflow whose concurrency cancels in
progress, plus everything it calls transitively, and rejects a
job-level always() outside that allowlist. It found the release job,
which a line-based grep had missed. It also fails when an allowlisted
job stops needing the exemption, and when its scope no longer reaches
the deploy workflows, so it cannot go silently empty. Against the
pre-fix tree it reports all six offenders.

Behaviour change: manually cancelling a release run now stops the
retag too. cron-release-highest re-dispatches the release.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 09:07:24 +02:00
evangelostsak f91f9bccdf test(swarm-test): cover the transport switch
A node is pointed at its mesh address; the controller keeps the connection it
runs the play with. The step had no test, and this entry has now bitten twice.
2026-09-28 08:52:50 +02:00