Commit Graph
14682 Commits
Author SHA1 Message Date
infinito-nexus-updater[bot] 88e265921a update(images): update Docker image versions (web-app-semaphore) 2026-07-11 02:30:06 +00:00
infinito-nexus-updater[bot] 838f78115b update(images): update Docker image versions (web-app-seaweedfs) 2026-07-11 02:30:02 +00:00
infinito-nexus-updater[bot] 0c977f2b4b update(images): update Docker image versions (web-app-prometheus) 2026-07-11 02:29:58 +00:00
infinito-nexus-updater[bot] c29406527c update(images): update Docker image versions (web-app-baserow) 2026-07-11 02:29:53 +00:00
infinito-nexus-updater[bot] 55d7c83088 update(repos): bump git refs to latest semver tags (web-app-bookwyrm) 2026-07-11 02:29:52 +00:00
infinito-nexus-updater[bot] 28c5c8ca06 update(repos): bump git refs to latest semver tags (web-app-bluesky) 2026-07-11 02:29:47 +00:00
kevinveenbirkenbachandClaude Opus 4.8 7ad64c684d chore(aliases): add i8temesi for make test-merge-signed
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:42:03 +02:00
kevinveenbirkenbachandClaude Opus 4.8 63b60b00bb fix(env): parse the group_vars paths SPOT without PyYAML
The new dir handlers pulled utils.cache.yaml into the env build, which
bootstrap runs (make install-system-python) before any Python dependency
exists; on arch and manjaro, whose images ship no preinstalled PyYAML, the
.env generation died with ModuleNotFoundError and broke PKGMGR and the dev
environment jobs. Read the plain KEY: "value" entries with a stdlib line
parser instead; Jinja values and missing keys stay hard errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:26:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bc047de312 feat(git): gate merges on signed incoming commits
A merge commit bypassed every signature check: test-signed only inspects
HEAD and the pre-commit hook does not run for merge commits. Add
scripts/git/assert_merge_signed.sh, which fails when any commit the merge
brings in (HEAD..MERGE_HEAD) reports %G? status N, wire it up as
make test-merge-signed, and register it as a pre-merge-commit hook so
pre-commit install now also installs that hook type.

Fast-forward merges create no commit and skip the hook (use --no-ff to
gate them); conflicted merges fall back to the regular pre-commit and
pre-push gates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:26:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c4f160ab07 docs(agents): spell out the alias hint as a full sentence
Replace the bracket tag with the sentence form so the hint teaches the
shorter alias in place: Speed up by using prompt/cli alias X instead of
what the operator wrote.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3dba48cac9 chore(backup): drop a redundant stdout default and apply shfmt
The pre-deploy snapshot task only evaluates changed_when for executed loop
items, where the script module always sets stdout, so the default('') filter
hid nothing. pre_deploy_snapshot.sh is reindented by shfmt with no logic
change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 62e81f3822 fix(bookwyrm): normalize the proxied username to the stored localname
Django's RemoteUserMiddleware compares request.user.get_username() with
clean_username(remote_user) on every request. The inherited clean_username
returned the oauth2-proxy header verbatim (mixed case, full address) while
BookWyrm stores lowercase localname@DOMAIN, so the comparison never matched:
the middleware logged the session out and re-authenticated on each request,
rotating the session and failing CSRF checks.

Derive the localname once (part before @, lowercased), override
clean_username to return the stored localname@DOMAIN shape the middleware
compares against, and authenticate/provision with the bare localname as
before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 ede6225b2d chore(tests): drop narration comments from the lookup test setups
The three identical Exception-labelled comments over cache_base._reset()
restate what the call does; the reset itself is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 fc00681300 fix(akaunting): give the container a 10m healthcheck start period
The artisan first boot (migrations plus seed) outruns the default
start_period, so the healthcheck reaped the container mid-init and the
deploy died in a restart loop. Same reap-mid-init class and fix as kix
and joomla: extend the grace window; a healthy container still reports
healthy on its first successful probe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e3d33224eb fix(espocrm): gate daemon and websocket behind the boot ready marker
Swarm ignores depends_on, so the daemon and websocket replicas started
running PHP while the first-boot installer was still rebuilding the shared
NFS volume. Any PHP run mid-install leaves NFS silly-rename files in
data/cache that make the installer's rm/rebuild fail, killing the deploy.

Teach the custom entrypoint a --wait-ready <cmd> mode that blocks until the
existing boot ready marker appears (ESPOCRM_WAIT_READY_TIMEOUT_S, default
1800s, then a loud exit 1) and exec the daemon/websocket commands through
it. After the first boot the marker persists, so the gate is pass-through
on every later start in both compose and swarm.

Also drop an inline comment that leaked into the ESPOCRM_CONFIG_OIDC_FALLBACK
env value; env files have no inline comments, so the setting never read as
plain false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 094c02a69d feat(diagnostics): single SPOT rescue script with CI-uploaded snapshots
Every Ansible rescue: block used to carry ad-hoc per-role failure dumps that
drifted apart and captured different subsets. Replace them all with one
diagnostics script (scripts/system/diagnostics/rescue.sh) that snapshots
containers (full logs plus inspect per container), swarm services (ps plus
logs per service), journal, host resources, runtime info and stats into a
per-run folder and always exits 1 so the deploy still fails. A new lint
enforces the shape: every rescue ends with the script, at most one
nocheck-justified extra task before it (postgres pg_hba dump, xwiki
extension-repo probe), and a nocheck rescue-recovery exemption for the one
block that must genuinely recover: keycloak object updates, where a
cross-node reschedule needs a swarm-wide node re-resolve plus a delegate_to
change that only a rescue can express; its recovery is kept and now also
captures diagnostics before the terminal failure.

The snapshot folder path is a group_vars SPOT: DIR_RESCUE_DIAGNOSTICS and
DIR_VAR_LIB live in group_vars/all/05_paths.yml as plain strings; new env
handlers derive INFINITO_RESCUE_DIAGNOSTICS_DIR and INFINITO_DIR_VAR_LIB
from it for the generated .env, replacing the default.env entries, and the
play-level environment forwards the value to every task host so rescue.sh
needs no second default. CI uploads the folder like the inventory and
playwright artifacts: compose copies it out of the deploy container in
dedicated.sh, swarm captures per node (manager and both workers) into
node-named subfolders.

Deleting the ad-hoc dumps orphaned helper files (postgres inspect_container,
terminator docker_diagnostics, peertube diagnostics, matomo bootstrap debug,
xwiki and openresty rescue includes) and 14 role vars; all removed. Generic
pieces of those dumps (runtime version and info, stats, dmesg oom evidence,
swapon) moved into the SPOT script instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c6d9479d1b fix(matomo): recover the swarm bootstrap from a wedged installer
A flaked installer that created the superuser and site but never reached
the finished step leaves Matomo redirecting every request to CoreUpdater,
so the sidecar probe never passes. The old until-retry only force-restarted
the sidecar between attempts and never reset that partial state, so all
three attempts failed identically and the job died after ~29 minutes
(everything depending on matomo hung with it).

Drive the attempts through a loop over swarm_attempt.yml that, before each
retry, moves the partial config aside (config.ini.php.wedged-<ts>, never
deleted) and clears the cache so the installer runs fresh; the eraseAllTables
step handles leftover tables. The move is gated to the config-absent-at-entry
path and skips the whole attempt once a token is obtained, so a healthy
install is never touched. bootstrap_swarm_poll.sh anchors its token scrape
with --since so a token still buffered from the previous task is not returned
before the restarted installer emits its own, and surfaces a failed move
instead of masking it. The swarm abort message reports the swarm attempt
count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1dc58df31e fix(backup): unify the pre-deploy snapshot into one gated loop
The container and NFS pre-deploy snapshots ran two near-identical role
scripts and two constructor tasks. Merge them into one shared script under
scripts/system/backup/ whose content check handles a file (databases.csv)
or a directory (export base), and drive both from a single looped
constructor task keyed by role, unit, and source. Each iteration keeps its
own group_names gate, its own timeout, and reports changed only when it did
not skip.

The shared script also reaches the fresh-host skip loudly: systemctl
list-unit-files exits non-zero when the version glob matches nothing, so the
listing now sits in an if instead of a bare command substitution that
aborted the snapshot under set -euo pipefail (the compose test-development
failure). The volume e2e test starts the unit through an if and dumps the
unit journal on failure so the real start error surfaces.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 867ab9e17d fix(image): source install-script paths from default.env, harden apt key download
The pull_request_target image build ran main's push.sh (which does not pass
the install-script build args) against the PR Dockerfile, so all five distro
builds died with 'INFINITO_PYTHON_INSTALL_SCRIPT: parameter null or not set'.
Drop those three ARGs and source the paths straight from default.env inside
the install RUN (default.env is already in the build context), keeping one
SPOT and removing the cross-branch build-arg coupling.

apt_repo.sh no longer swallows a failed key download: download_file returns
curl's status and retries transient failures, and install_key aborts when the
key download fails or lands empty, instead of installing an empty keyring that
later makes apt reject the repo as unsigned (the suitecrm node's DNS blip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:04:05 +02:00
Alejandro Roman d70d8581ad fix CI isssues 2026-07-11 01:08:42 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1a908a6e5b perf(tests): parallelize suites, hoist fixtures, gate ansible-lint
Run the python suites through pytest-xdist when pytest is importable
(id-level collection parity with unittest discover verified per suite;
serial unittest stays the fallback), with -rP so warnings printed by
passing tests, like the update annotations, still reach the log. run.sh
self-provisions the dev extras through scripts/install/dev-extras.sh,
which stamps inside the venv and skips read-only venvs; make onboard
pre-warms the same path in the running container.

Hoist per-test cache resets and roles scans to setUpClass in the lookup
and resolvable suites (a per-test fingerprint-memo reset closes an
id()-reuse cache-poisoning flake the hoist exposed), inject generation
names into the nfs backup script test instead of sleeping, and narrow
ansible-lint scope to real ansible content. ansible-lint additionally
sits behind a content fingerprint gate that skips the run when nothing
it walks has changed; without a usable git (container bind mounts) the
gate disables itself and the full run remains.

Drop the import-linter layer and ignore for the deleted deps module;
the contract now locks compose -> common -> env. Measured on the host:
unit 101s to 20s, integration 90s to 24s, lint tests 43s to 19s,
repeated ansible-lint 53s to 0.4s.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:20:46 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9b4d002052 update(images): bump docker image versions and repository refs
Bump every outdated image pin and repository ref to latest except
web-app-nextcloud (kept on 33-fpm-alpine). Covers keycloak, gitlab (6
services), matrix, opentalk, jira, confluence, espocrm, magento
opensearch, elasticsearch, rabbitmq, qdrant, ollama, seaweedfs,
semaphore, wordpress, taiga, bluesky (image + social-app ref), bookwyrm
ref, roulette-wheel, simpleicons, registry cache/docker, and the
svc-runner base image. Includes major jumps (elasticsearch 9, rabbitmq
4, opensearch 3, espocrm 10, registry 3, node 26, ubuntu 26.10) that
are pin-only and still need a deploy validation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:57:45 +02:00
kevinveenbirkenbachandClaude Opus 4.8 f76bfcf531 refactor(svc-bkp-volume-2-local): rename role from svc-bkp-container-2-local
Rename the role, its test tree, the primary entity key
(volume-2-local), the derived vars (BKP_VOLUME_2_LOCAL_*,
SYS_SERVICE_BACKUP_VOLUME_2_LOCAL), the run-once fact, and every
group_names consumer flag, include path, doc, and lint reference. The
container_backup service key and the on-disk backup-docker-to-local
tree keep their names: both are contracts with existing consumer
entries, snapshot trees, and the baudolo pull tooling.

Operators must rename the svc-bkp-container-2-local inventory group and
disable the previous versioned units on already-provisioned hosts; the
pre-deploy snapshot glob derives its base from the new role name and
will not find them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:52:02 +02:00
kevinveenbirkenbachandClaude Opus 4.8 10b25b4f00 chore(agents): enable caveman and ponytail plugins project-wide
make install-skills now registers the caveman and ponytail marketplaces
and enables both plugins in the project settings, so their SessionStart
hooks auto-activate token-compressed communication (caveman) and
minimal-code mode (ponytail) for every agent session in this repository.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 939a386247 fix(package-cache): persist rotated Nexus admin password
Store the rotated admin password inside the container (umask 077) during
bootstrap and read it back on later runs, instead of assuming the
configured INFINITO_CACHE_PACKAGE_ADMIN_PASSWORD still matches; fall back
to the configured value when the stored file is missing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 adb8bcf696 feat(svc-bkp-nfs-2-local): scheduled differential NFS export backup
Add a systemd-driven rsync --link-dest backup of the NFS export into the
baudolo-compatible local snapshot tree, plus a pre-deploy snapshot hook in
the constructor. A missing export fails the nightly unit loudly, a failed
rsync removes its incomplete generation so it cannot poison the next
--link-dest, and rsync exit 24 from the live export is tolerated.

Both pre-deploy snapshot scripts (container and nfs) now resolve the
previous deploy's unit through a version glob, so the snapshot still runs
after a project version bump. The user-backup ssh wrapper whitelists the
new backup-nfs-to-local type for downstream pulls. The nfs-server role
declares the backup as a dynamic consumer with true/false pinning
variants; svc-bkp-container-2-local drops its variants.yml because
non-subject closure members resolve foreign round indices against it and
leak its companion pins into other rounds.

Unit tests execute the real script against tempdirs and prove hardlink
deduplication by inode, history isolation, delete semantics, loud failure
on a missing source, and cleanup of incomplete generations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 f08d71534a feat(tooling): operator alias, shortcut, skill, cheat and onboard system
Add the i8* terminal aliases (make install-alias) and ai8* agent
conversation shortcuts (docs/.../agents/alias.md), move skill
distribution to the external INFINITO_SKILLS_REPOSITORY (make
install-skills), and add make cheat, make alias and make onboard. Introduce
custom.env operator overrides (win over defaults and handlers) and pin
INFINITO_ALIAS_MD / INFINITO_ALIAS_REPOSITORY / INFINITO_SKILLS_REPOSITORY
in default.env. Drop the in-repo skills-lock.json and its update-skills CI
job. AGENTS.md instructs agents to suggest the matching cli/prompt alias
when an operator writes something an alias covers. Lints enforce alias
sorting, i8/ai8 prefixes, no consonant clusters, full make-target
coverage, and terminal/agent shortcut non-overlap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1b7744e75f fix(kix): give the backend a 10m healthcheck start period
Cold starts exceed the image default; compose up marked the backend
unhealthy before init finished (same pattern as joomla/mediawiki).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 51ac26154e fix(seaweedfs): escape sidecar shell dollars for stack deploy
docker stack deploy interpolates $pid and $((i+1)) out of the sidecar
bootstrap, crash-looping it with a busybox syntax error; $$ renders as a
literal dollar under both compose and stack.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 664993f819 fix(n8n): run owner bootstrap once per cluster and accept already-setup
Both workers raced POST /rest/owner/setup; the loser spun 31 retries on
400 'Instance owner already setup'. Hoist run_once via apply and assert
200/201 or an already-setup body.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 16d0b871cc fix(gitea): retry app.ini db patches across swarm task replacement
The swarm reconciler may replace the gitea task container between
resolve-container-id and the exec; each retry re-resolves the id inline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 99ed66d716 fix(svc-runner): publish no dev-stack ports in nested DooD deploys
- compose/noports.override.yml drops every published port via !override
- compose_file_args appends it when INFINITO_PUBLISH_PORTS=false
- runner instances set the flag; default true keeps other flows unchanged
- central yaml loader + ansible-lint config accept compose merge tags

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 925a51b826 fix(bkp-test): make the restore drill robust against real stack layouts
- resolve compose projects from container labels + explicit --project
- down --remove-orphans so override-file services do not survive
- retry the up phase across three rounds for slow cold starts
- flag crash-looping no-healthcheck containers via RestartCount recheck
- drop the unused BKP_TEST_COMPOSE_DIR env

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:43:34 +02:00
Alejandro Roman a12feb9120 fixes alert 2026-07-10 09:39:05 +02:00
Alejandro Roman 8b96666320 fixes CI issues with mailu 2026-07-10 09:16:50 +02:00
kevinveenbirkenbach c8ad42b62b Merge branch 'main' into feature/svc-net-tor 2026-07-10 01:58:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a4f423da70 build(deps): replace python-ldap with pure-python ldap3 for the Tor credential test
python-ldap is the only project dependency that compiles a C extension,
and its sdist build (Python.h, OpenLDAP/SASL headers) broke the image
build since it was added. The svc-db-openldap Tor credential test is its
sole consumer, so it now binds via ldap3 instead, keeping pyproject
compile-free like psycopg2-binary and PyMySQL. The Ansible ldap_* module
prerequisite handling inside the openldap role is untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 01:57:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 f8c016b294 fix(test-e2e-playwright): give onion targets a realistic navigation budget
gotoOnion hard-coded a 60s page.goto timeout, so a cold full-page load
over freshly built Tor circuits aborted before the onion answered and
the deploy gate flaked. The deploy now passes an onion-aware
PLAYWRIGHT_NAVIGATION_TIMEOUT (180s onion / 60s clearnet) plus a larger
onion per-test budget (600s), and gotoOnion honors the env instead of
the hard-coded ceiling. Fast loads are unaffected; only slow onion
navigations may use the larger budget.

Verified: full deploy matrix green with zero page.goto timeouts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 01:56:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 edb96e9ae3 feat(dashboard): make keycloak-js login work over Tor onion
Chromium never treats plaintext .onion origins as a secure context, so
keycloak-js (PKCE via crypto.subtle) could not run. A custom Playwright
browser fixture launches Firefox with the Tor-Browser prefs
(dom.securecontext.allowlist_onions, origin/mixed-content handling) for
onion targets and keeps Chromium for clearnet; all dashboard specs share
it via the register pattern.

keycloak-js is now vendored from the deployment's own CDN as an ES
module (jsdelivr is unreachable over Tor) with CORS opened on the CDN
proxy. Personas and the oidc-login spec wait for adapter readiness and
navbar settle before driving login/logout, which the async code->token
exchange needs over Tor latency.

Verified: full deploy matrix green (onion 14/14 twice, clearnet pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 01:55:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bd37f1855b fix(ci): resolve package install script from default.env in env bootstrap
01_install.sh runs before python3 exists, so load.sh is skipped and
INFINITO_PACKAGE_INSTALL_SCRIPT was unset; grep it from default.env like
scripts/install/package.sh already does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 00:39:35 +02:00
kevinveenbirkenbachandClaude Opus 4.8 0e15d5c9b8 refactor(bkp-test): restore drill cycles compose projects
- compose down/up per project via container/compose wrappers
- BKP_TEST_COMPOSE_DIR from DIR_COMPOSITIONS in test.env
- crash-loop detection for containers without healthcheck
- drop raw-docker nocheck headers

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 00:32:05 +02:00
kevinveenbirkenbachandClaude Opus 4.8 b533863559 fix(env): keep the .env generation stdlib-only for fresh-host bootstrap
The nfs SPOT loaders pulled PyYAML into the .env generation, which bootstraps fresh hosts BEFORE python dependencies exist: the import crashed cli.meta.env, load.sh produced an empty environment and make install-system-python died on the required-var guard (environment/manjaro and pkgmgr/centos CI jobs). The loaders now line-parse the services.yml SPOTs via the stdlib-backed cached reader and the mapping path constant. The client's protocol version field becomes nfs_version, since services.yml reserves version for image tags (schema lint), and the image discovery casts versions defensively.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:54:33 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8519642373 refactor(storage): SPOT the nfs export base and client version in their roles
storage.nfs shrinks to the deployment-specific server address: export_base moves into svc-storage-nfs-server's services.yml (the server dictates where exports root) and the mount protocol version into svc-storage-nfs-client's services.yml (the client owns how it mounts). Both are read through utils.storage.nfs loaders by the nfs lookups, the env handler and 00_topology, eliminating the unrendered-variables class for these values; the group_vars assert shrinks accordingly and the swarm test extras stop restating role defaults.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:54:32 +02:00
kevinveenbirkenbachandClaude Opus 4.8 17b533ee4b chore(csp): suppress url reachability checks on jsdelivr CSP origins
cdn.jsdelivr.net started answering HTTP 400 on its bare root, failing the external URL test for every CSP origin entry. The origins are CSP sources, not document links; suppress the check per line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 41fc7336e0 feat(svc-bkp-container-2-local): add the backup/restore CLI e2e test
test-e2e-cli now drills the whole backup chain: the sync pass waits for the backup unit to terminate (failed state hard-fails), verifies the stored generation (files/ or non-empty sql payload), then runs the disaster drill - stop every container except the runner's own compose project, wipe each volume the generation can restore, replay it via baudolo-restore files, replay the sql dumps per engine with --empty (semicolon csv, cluster dumps visibly skipped), and require every container healthy again (oneshot exit-0 tolerated, swarm nodes skip the drill). The async pass requires two differential generations, triggering one extra run when needed. Database seeding runs synchronous and throttled until baudolo-seed gains file locking; the baudolo invocation uses the full --dump-only-sql flag instead of an argparse prefix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 22268974fc feat(services): let providers opt out of the loader preload
Registering svc-bkp-container-2-local as the container_backup provider made the constructor's service-loader preload it in the server bucket, ahead of mailu (web-app bucket) - but its alarm chain (sys-ctl-alm-email -> sys-svc-mail) hard-asserts the mailu no-reply token, and run_after cannot legally cross buckets. A provider can now declare preload: false: it stays resolvable in the registry (consumer flags, closures, variants) while ordered_primary_service_entries skips it, leaving the existing constructor group pass (which runs after the full preload) as its load path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 fe6233392b feat(svc-bkp-container-2-local): snapshot the pre-deploy state before any mutation
MODE_BACKUP's pre-deploy backup ran at the role's constructor slot, after the shared-service preload and the db-engine group had already mutated the host. The run is now decoupled from the role load: the constructor starts the backup unit the PREVIOUS deploy installed, right before the shared-service preload, via a role-shipped script that skips cleanly when the unit does not exist yet or databases.csv is empty. A failing snapshot aborts the deploy before any mutation. The role pins instant flush and handler restarts off (baudolo stops containers; a mid-deploy start would be destructive) - remaining run paths are the snapshot, the timer and the CI final flush.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 ab53a8b847 feat(lint): recognize hadolint directives and nocheck-based raw-docker opt-outs
The comment lint learns hadolint as a directive class so 'hadolint ignore=' lines survive comment audits, and the compose raw-docker lint drops its path whitelist in favor of the same '# nocheck: raw-docker' head/inline suppression the docker variant already honors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9f8aa6e9b6 refactor(env): SPOT the install scripts and derive the nfs export base from group_vars
INFINITO_PYTHON_INSTALL_SCRIPT and INFINITO_DOCKER_CLI_INSTALL_SCRIPT join the default.env SPOT: the Dockerfile consumes them as required args (:? in the RUN as last defense), all three image builders (compose.yml, build.sh, push.sh) pass them hard-required, the shell consumers read the SPOT via default.env grep and the Makefile via BASH_ENV. INFINITO_SWARM_NFS_EXPORT_BASE is no longer a static default: a new env handler derives it from the deploy SPOT group_vars/all/15_storage.yml, 00_topology greps that file (and the STATE_SUBDIR constant) directly, and the swarm test extras stop restating the group_vars value. Stale hadolint directives are restored and recognised; leftover narration comments in the touched files are dropped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c0cd5c59eb fix(stages): keep systemd timers masked until after the CLI tests
The terminator armed every timer before test-e2e-cli ran, so scheduled units could fire mid-test: the hourly container-health check would see the restore drill's deliberately stopped containers and its OnFailure repair would restart them mid-wipe, the 22:00 docker prune would delete them outright, and the backup/cleanup timers could mutate the generation store the test is asserting on. The unlock now runs as the destructor's last step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:04:40 +02:00