Commit Graph
14682 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.7 948a6d6664 feat(swarm-pilot): bootstrap apt-cacher-ng on swarm-lab to cut node setup time
Adds a single apt-cacher-ng container (sameersbn/apt-cacher-ng:3.7.4-20220421)
on the swarm-lab network and routes every node's apt traffic through it via
/etc/apt/apt.conf.d/01-cacher. With four nodes provisioning the same
infinito-nexus.deb deps in parallel (~200 MB / node), the cache turns the
second-through-fourth fetch into a hot serve from the local proxy.

The workflow restores ${{ runner.temp }}/apt-cacher-ng across runs via
actions/cache@v4 (keyed on packaging/debian/control), so on warm GHA runs
the cache is also populated for the first node — driving bootstrap from
~11 min toward sub-3 min once the cache is hot. The cache restore step is
guarded by `if: \!env.ACT` so act runs still exercise the cold path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 22:24:46 +02:00
kevinveenbirkenbachandClaude Opus 4.7 35cb7a6d89 feat(scripts/tests/act): pass workflow inputs via ACT_INPUTS
ACT_INPUTS="key=value [key2=value2]" expands to repeated --input flags so
make act-workflow can drive workflow_dispatch-style inputs without falling
back to a manual act invocation. Needed for the swarm pilot, where the
discover job's `whitelist` input gates the per-app matrix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 22:24:45 +02:00
kevinveenbirkenbach a20ab3ca22 Merge branch 'main' into feature/web-app-erpnext 2026-06-02 22:23:30 +02:00
kevinveenbirkenbachandClaude Opus 4.7 23c4a33412 fix(web-app-erpnext): move subnet to 192.168.105.176/28 to avoid web-app-jitsi clash
The 192.168.105.160/28 slot is also claimed by the open web-app-jitsi PR
(#287). CI's network-uniqueness lint catches the overlap once both branches
are checked together. Move to .176/28 (next free slot in the 105.x band).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 22:23:10 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a5429e5f97 diag(swarm-pilot): add docker logs to systemd-ready failure output
`docker exec journalctl` fails when the container is already dead (which
is the actual failure mode: jrei/systemd-ubuntu:24.04 exits with code 255
~0.4s after start on the current GHA runner image). `docker logs` works
on stopped containers and surfaces what systemd printed before it gave up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 21:41:13 +02:00
kevinveenbirkenbachandClaude Opus 4.7 7ce8d9ab5b feat(svc-docker-registry): cluster-local registry for swarm image distribution
Adds a manager-pinned, NFS-backed `registry:2` service plus a transparent
retag/push/rewrite step so swarm workers can pull custom-built images from a
local registry, replacing the `docker save | docker load` pilot crutch.

Mechanism: after `compose build`, the new `swarm_registry_push.py` reads the
rendered compose.yml, retags each service that declares both `build:` and
`image:` with `<manager>:5000/<image>`, pushes the retag, and rewrites the
`image:` field in place. Subsequent `docker stack deploy --resolve-image
never` then references the registry-qualified name, so workers pull from the
cluster-local registry over HTTP via `insecure-registries`.

No per-role changes required — the rewrite is centralized in
sys-svc-compose handlers and skips services without a `build:` directive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 21:41:12 +02:00
kevinveenbirkenbachandClaude Opus 4.7 014fa54ad3 feat(web-app-erpnext): ship ERPNext role with OIDC SSO, LDAP, outbound mail
Implements requirement docs/requirements/024-web-app-erpnext.md.

Stack (per frappe_docker v15 single-image multi-role pattern):
- configurator (one-shot bench set-config: db_host/port, three redis URLs
  split by DB number 0/1/2 for cache/queue/socketio, socketio_port, host_name
  HTTPS)
- backend (gunicorn), frontend (nginx-entrypoint.sh), websocket (socketio),
  scheduler, queue-short (--queue short,default), queue-long
  (--queue long,default,short)

Central-service consumer pattern (Decision #7):
- ERPNEXT_DB_ROOT_PASSWORD branches on services.mariadb.shared: central
  svc-db-mariadb root pw when true, per-role MariaDB consumer pw when false
- Redis via in-compose `redis` alias, 3-DB-number split for Frappe's logical
  buses
- Explicit erpnext_assets volume mount on every container (image's
  VOLUME ['sites/assets'] otherwise creates anonymous volumes that fail the
  hlth-volumes check)

Bench bootstrap (Decision #9):
- bench new-site --install-app erpnext with 30-min hard timeout
- Post-install restart of all long-lived Frappe containers (otherwise the
  cached app set serves HTTP 500 on /login)
- TCP-port readiness probe (HTTP would 404 pre-site)
- API-bot user seed + setup_complete=1 via apply_api_bot.py

OIDC (Decisions #4 + #5):
- redirect_uris filter auto-includes ERPNext in the shared Keycloak client
- Social Login Key wired via apply_oidc_settings.py with
  social_login_provider=Keycloak (delete+recreate due to set_only_once),
  custom_base_url=1, relative authorize/token/userinfo paths,
  auth_url_data={response_type:code,scope:openid}, login_via_keycloak
  redirect path
- Group-to-Frappe-role mapping persisted as a frappe.db default; per-login
  reconciliation hook deferred to follow-up (documented in README)

LDAP (V3): LDAP Settings doctype applied via apply_ldap_source.py. End-to-end
LDAP login (auto-create Frappe user from LDAP bind) deferred to follow-up;
LDAP-login Playwright specs intentionally absent in v1 (documented).

Email (Decision #8, outbound only): outbound Email Account applied via
apply_email_account.py using db_insert/db_update to bypass Frappe's
deploy-time SMTP socket validation. IMAP inbound deferred to follow-up.

Variant matrix (Decision #11): V1 sso+ldap, V2 all-false, V3 ldap-only.
Three variants verified end-to-end via
`make compose-deploy mode=reinstall apps=web-app-erpnext full_cycle=true
purge=true` — 6 PLAY RECAPs, all failed=0, all Playwright runs
passed-or-skipped with no failures.

Playwright specs: test-landing, test-csp-headers, test-login-administrator
(OIDC), test-login-biber (OIDC), test-login-native-administrator
(break-glass local login, always runs), test-guest-persona. _shared.js
exposes signInViaErpnextOidc + signInViaErpnextLocal.

Repo-wide lint addition: tests/lint/ansible/modules/test_task_name_length.py
caps Ansible task `name:` strings at 120 chars (opt-out via
`# nocheck: name-length`). Fixed two pre-existing violations in
web-app-keycloak/tasks/update/ldap/per_app_mapper_one.yml.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:01:38 +02:00
kevinveenbirkenbachandClaude Opus 4.7 e8a120f898 docs(requirements): add 024 web-app-erpnext with OIDC SSO
New requirement for a `web-app-erpnext` role that integrates ERPNext
(Frappe Framework) into Infinito.Nexus with OIDC-direct SSO against
Keycloak, reusing central `svc-db-mariadb` and `svc-db-redis` (three
Redis logical roles split by DB number 0/1/2 for cache/queue/socketio).

Captures 13 proposed design decisions for operator review before
implementation: upstream `frappe/erpnext` image pinning, central-service
reuse (Decision #7), wizard-bypass `bench` bootstrap (Decision #9),
Keycloak-group → Frappe-role reconciliation (Decision #5), Mailu IMAP
inbound + SMTP outbound (Decision #8), and the standard
V1/V2/V3 variant matrix (Decision #11) mirroring web-app-kix /
web-app-zammad. Out of scope for v1: multi-site / multi-tenant Frappe
(Decision #12).

Modeled on the layout precedents from web-app-odoo (ERP shape,
dual HTTP + WebSocket vhost) and web-app-zammad (central-service
reuse pattern, three-variant matrix).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:01:37 +02:00
kevinveenbirkenbachandClaude Opus 4.7 5aa3bca656 feat(svc-db-{postgres,openldap}): mark as stateful so they survive swarm deploy
Both DBs now follow the svc-db-mariadb pattern (service_is_stateful: true).
sys-svc-container/templates/deploy.yml.j2 already gates the deploy: block
on the flag; the DB then runs as a plain compose container pinned to the
manager via group membership instead of being scheduled as a swarm
service (which would corrupt the volume on a worker replica).

Unlocks the swarm-test matrix for every postgres/openldap-consuming app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 20:34:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 6dbc635105 fix(swarm-pilot): raise systemd-ready timeout 60s -> 180s with diagnostics
The previous 60s window flaked on GHA matrix runs because jrei/systemd-ubuntu:24.04 cold-starts D-Bus + targets slowly under parallel load. 03_start_swarm_nodes.sh additionally let downstream steps run against a non-ready node instead of failing.

Both scripts now exit non-zero with journalctl + State diagnostics on timeout. Override via SWARM_PILOT_SYSTEMD_TIMEOUT for local debug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 20:21:04 +02:00
kevinveenbirkenbachandClaude Opus 4.7 e5457d47df fix(ci/lint-ansible): install ansible.posix collection for host-mode lint
The lint-ansible workflow runs ansible-lint with INFINITO_LINT_RUNNER=host
(outside the compose stack container). roles/svc-storage-nfs-client uses
ansible.posix.mount for the NFS probe-mount; the host runner could not
resolve the module so the syntax-check failed CI while local make lint
passed (the container already had the collection via galaxy bootstrap).

Adding ansible.posix to requirements.galaxy.yml installs it everywhere
the existing ansible-galaxy install step runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 19:55:10 +02:00
kevinveenbirkenbachandClaude Opus 4.7 93b361113c refactor(web-app-zammad): align with swarm+NFS chain post-merge
- meta/volumes.yml: declare zammad_storage + zammad_search named volumes
- vars/main.yml: ZAMMAD_STORAGE_VOLUME / ZAMMAD_SEARCH_VOLUME constants reading from meta
- compose.yml.j2: extra_volumes uses the constants instead of empty dicts
- tasks/01_core.yml: 4 host-rendered init files (auto_wizard.json, zz_omniauth_allow_get.rb, telegram_helper_stub.rb, zz_oidc_group_role_mapping.rb) migrate from inline template: tasks to the central render_replicated_templates.yml helper so the bind-mounted host paths resolve on every swarm peer

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 19:42:22 +02:00
kevinveenbirkenbach 43b614ec26 Merge branch 'main' into feature/swarm-nfs
# Conflicts:
#	roles/dev-nix/tasks/02_non_arch_installer.yml
2026-06-02 19:30:12 +02:00
kevinveenbirkenbachandClaude Opus 4.7 83eee2d3c5 refactor(swarm): rename swarm-nfs workflow + parameterize pilot per app
Mirror the test-deploy-server iteration scaffold: discover + matrix on
the same app list (INFINITO_DEPLOY_TYPE=server), one swarm-deploy run
per app. Pilot scripts derive per-app context from APP_ID + role meta
(ENTITY, SERVICE_NAME, DB_DEP, CUSTOM_IMAGE_REPO, PRIMARY_NFS_VOLUME)
so they adapt to roles other than mediawiki.

- .github/workflows/test-deploy-swarm-nfs.yml -> test-deploy-swarm.yml
- scripts/tests/deploy/swarm-nfs-pilot/ -> scripts/tests/deploy/swarm/
- new _context.sh helper sourced by 07/08/11–16
- 07_provision_inventory + 08_extend_inventory + 11_deploy build their
  --include list from DB_DEP + APP_ID
- 12_wait_converge skips DB readiness when DB_DEP=none
- 13_seed_content seeds NFS marker only when meta/volumes.yml carries an
  nfs-flagged volume
- 14_drain_worker skips custom-image distribution when role has no
  build context
- 15_assert_state asserts marker survival only when an NFS volume exists
- ci-orchestrator wires the renamed job + passes whitelist through
- naming-pattern alignment across test-deploy-{server,universal,workstation,swarm}

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 19:23:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 5adf3011fe refactor(swarm-nfs): generalize swarm+NFS chain across all roles
Migrate the mediawiki-specific swarm patterns into shared sys-svc-compose
helpers so every role inherits swarm + NFS portability:

- meta/volumes.yml: dict schema with mandatory name|path + optional nfs
  block (uid/gid/mode); 47 roles migrated, 48 lookup consumers updated to
  volumes.<key>.{name,path}
- sys-svc-compose helpers: finalize.yml (flush + post_deploy),
  post_deploy.yml (swarm-resolve + DB-healthy-wait), nfs_prep.yml
  (pre-create NFS subdirs), swarm/resolve_self.yml (canonical
  <ENTITY>_CONTAINER fact), render_replicated_templates.yml +
  _render_one_template.yml (template render + swarm-peer replication,
  per-entry notify, fileglob support)
- 15 roles migrated to render_replicated_templates.yml helper
  (mediawiki, prometheus, kix, friendica, dashboard, nextcloud,
  suitecrm, matrix, flowise, openldap)
- 5 new lint tests pin the architecture: volumes schema, compose chain,
  volume-constants-are-lookups, template-render-centralization,
  meta-no-role-var-refs
- ROLE_FILE_TEMPL_COMPOSE SPOT constant + 7 tests migrated to use it
- Handler test scanner extended to detect nested notify in
  vars: role_templates: lists

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:57:35 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3c07721303 feat(swarm-nfs): bootstrap Docker Swarm + NFS-backed shared volumes (#023)
Adds the svc-docker-swarm, svc-docker-swarm-manager, svc-storage-nfs-server
and svc-storage-nfs-client roles, the compose_volumes filter NFS support,
the test-deploy-swarm-nfs CI workflow with its swarm-nfs-pilot script set,
and the deploy_mode-aware compose/swarm wiring across mediawiki, mariadb
and sys-svc-* helpers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:57:34 +02:00
kevinveenbirkenbach da58d93bde Merge pull request #286 from infinito-nexus/update/docker-image-versions-20260529-0fa0da1
update(images): update Docker image versions
2026-06-01 20:14:14 +02:00
kevinveenbirkenbach b9f6041804 Update services.yml 2026-06-01 20:11:50 +02:00
kevinveenbirkenbach d07dacf2f3 Update Friendica version to 2026.01 2026-06-01 20:11:02 +02:00
kevinveenbirkenbach 601e931ae7 Merge pull request #287 from kevinveenbirkenbach/feature/web-app-jitsi
feat(web-app-jitsi): Jitsi Meet role with oauth2-proxy + LDAP variants
2026-06-01 15:34:20 +02:00
kevinveenbirkenbach a7fbca5b09 Merge branch 'main' into feature/web-app-jitsi 2026-06-01 15:33:30 +02:00
kevinveenbirkenbach 85b9524cc2 Merge pull request #288 from infinito-nexus/dependabot/npm_and_yarn/eslint-10.4.1
chore(deps-dev): bump eslint from 10.4.0 to 10.4.1
2026-06-01 11:42:05 +02:00
kevinveenbirkenbach e423504919 Merge branch 'main' into update/docker-image-versions-20260529-0fa0da1 2026-06-01 11:35:28 +02:00
kevinveenbirkenbach 4a2beaa3e7 Release version 9.1.0 v9.1.0 2026-06-01 11:29:42 +02:00
kevinveenbirkenbach 794d28500e Merge pull request #269 from kevinveenbirkenbach/feature/web-app-zammad
feat(web-app-zammad): Zammad helpdesk role with OIDC SSO
2026-06-01 11:16:10 +02:00
dependabot[bot] c1215d3106 chore(deps-dev): bump eslint from 10.4.0 to 10.4.1
Bumps [eslint](https://github.com/eslint/eslint) from 10.4.0 to 10.4.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.4.0...v10.4.1)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.4.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-01 02:41:17 +00:00
kevinveenbirkenbachandClaude Opus 4.7 fc39718599 chore: sync .dockerignore with .gitignore after .claude/hooks addition
`make setup` regenerates `.dockerignore` from `.gitignore` on every run.
The earlier commit that added `.claude/hooks` to `.gitignore` did not
re-emit the matching `.dockerignore`, so each CI invocation rewrote the
file — and the `pre-commit` framework reported `make test` as failed
("files were modified by this hook"), even though every test target
passed. Land the synced output here so the diff stays empty on a clean
deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 00:15:22 +02:00
kevinveenbirkenbachandClaude Opus 4.7 6482e8eddf chore: sync .dockerignore with .gitignore after .claude/hooks addition
`make setup` regenerates `.dockerignore` from `.gitignore` on every run.
The earlier commit that added `.claude/hooks` to `.gitignore` did not
re-emit the matching `.dockerignore`, so each CI invocation rewrote the
file — and the `pre-commit` framework reported `make test` as failed
("files were modified by this hook"), even though every test target
passed. Land the synced output here so the diff stays empty on a clean
deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 00:15:12 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d5da1c116e fix(sys-svc-mail-msmtp,sys-ctl-hlth-msmtp): make health-check resilient on minimal images
CI run 26721196005 failed at:

  TASK [sys-service : sys-service | Fail after shared service diagnostics]
  msg: Unable to start service hlth-msmtp.9.0.2.infinito.nexus.service.

Two breakages in the start sequence:

1. `sys-ctl-hlth-msmtp/files/script.sh` called `hostname` in `$(...)`.
   The CI deploy containers ship without that binary, so `set -eu`
   aborted before msmtp ever saw stdin. Fall back to `${HOSTNAME:-...}`
   then `uname -n` then a literal "unknown".

2. `sys-svc-mail-msmtp/templates/msmtprc.conf.j2` hard-coded the trust
   file path per RedHat family — the file was missing on the deploy
   image and msmtp aborted with `Error while reading file. exit=66`.
   Probe a candidate list at deploy time (`SYS_SVC_MAIL_MSMTP_CA_BUNDLE_CANDIDATES`),
   pick the first existing path, surface it as
   `sys_svc_mail_msmtp_ca_bundle`, and install `ca-certificates`
   ahead of the probe.

`make test` 5/5 green (186 OK).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 22:35:12 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3a3fd67180 fix(sys-svc-mail-msmtp,sys-ctl-hlth-msmtp): make health-check resilient on minimal images
CI run 26721196005 failed at:

  TASK [sys-service : sys-service | Fail after shared service diagnostics]
  msg: Unable to start service hlth-msmtp.9.0.2.infinito.nexus.service.

Two breakages in the start sequence:

1. `sys-ctl-hlth-msmtp/files/script.sh` called `hostname` in `$(...)`.
   The CI deploy containers ship without that binary, so `set -eu`
   aborted before msmtp ever saw stdin. Fall back to `${HOSTNAME:-...}`
   then `uname -n` then a literal "unknown".

2. `sys-svc-mail-msmtp/templates/msmtprc.conf.j2` hard-coded the trust
   file path per RedHat family — the file was missing on the deploy
   image and msmtp aborted with `Error while reading file. exit=66`.
   Probe a candidate list at deploy time (`SYS_SVC_MAIL_MSMTP_CA_BUNDLE_CANDIDATES`),
   pick the first existing path, surface it as
   `sys_svc_mail_msmtp_ca_bundle`, and install `ca-certificates`
   ahead of the probe.

`make test` 5/5 green (186 OK).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 22:30:53 +02:00
kevinveenbirkenbachandClaude Opus 4.7 033495d42f fix(dev-nix): guard nixbld set_fact against getent fail_key: false None values
Cherry-pick of bdc5945bc from feature/web-app-zammad, retargeted at
roles/dev-nix/tasks/02a_nix_install_only.yml (the include_tasks
companion file that 201670975 introduced on this branch).

Same root cause + fix as on the zammad branch:

  TASK [dev-nix : Set build group override for Nix installer when nixbld exists]
  Error while resolving value for 'dev_nix_installer_build_group_id':
  object of type 'NoneType' has no attribute 1

`getent` with `fail_key: false` inserts the key with a `None` value
when the entry is missing, so the membership test `'nixbld' in
ansible_facts.getent_group` evaluates True but `getent_group.nixbld[1]`
crashes on None. The guard now explicitly checks the value with
`is not none` for both `nixbld` (group) and `nixbld1` (passwd).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:51:13 +02:00
kevinveenbirkenbachandClaude Opus 4.7 f27e6337ee fix(dev-nix): guard nixbld set_fact against getent fail_key: false None values
CI run 26643336674 (feature/web-app-zammad) failed at:

  TASK [dev-nix : Set build group override for Nix installer when nixbld exists]
  Error while resolving value for 'dev_nix_installer_build_group_id':
  object of type 'NoneType' has no attribute 1

Root cause: `getent` with `fail_key: false` does NOT drop the key when
the entry is missing — it inserts the key with a `None` value. The
existing `when:` guard `'nixbld' in ansible_facts.getent_group`
therefore evaluates True (the membership test only checks the key, not
the value), and `getent_group.nixbld[1]` then crashes when the value
is None.

Fix: replace the membership check with an explicit `is not none`
assertion for both `nixbld` (group entry) and `nixbld1` (passwd entry).
A short comment above each `when:` block names the trap so the next
reader does not re-introduce the membership-only check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:43:25 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d9a6006da1 style(web-app-zammad): collapse column-aligned whitespace to autoformat
Pure whitespace reflow applied by `make autoformat` — column-aligned
mapping values were collapsed to single-space alignment so the files
match the project-wide YAML formatter output. No behavior change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:43:24 +02:00
kevinveenbirkenbachandClaude Opus 4.7 03ced5c4e1 refactor(web-app-jitsi): split monolithic playwright.spec.js into _shared + test-*.js modules
Matches the zammad layout: `_shared.js` centralises env decode, the
`reachJitsiPrejoin` / `openJitsiSettingsPanel` helpers, the persona
runners, and the `beforeEach` viewport / cookie reset.
`playwright.spec.js` shrinks to a bootstrap that loads `_shared` and
require()s each scenario module's `register(shared)` hook. Each
`test-*.js` owns one persona scenario:

- test-landing.js          — canonical landing + CSP header baseline
- test-guest-persona.js    — guest auth chain (never authenticated)
- test-login-biber.js      — biber OIDC → join room → logout
- test-login-administrator.js — administrator OIDC → settings → logout
- test-login-via-ldap.js   — biber + administrator LDAP-bound scenarios

No spec-level behaviour change: lint-playwright lists the same six
tests and `make test` stays 5/5 green (186 OK).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 20:07:45 +02:00
kevinveenbirkenbachandClaude Opus 4.7 655e6df0ae fix(web-app-jitsi): satisfy make-test lints (PORT_BANDS, env quote, variants coverage)
Follow-up to the initial web-app-jitsi commit. `make test` flagged 11
contract violations on the newly-added role; each is addressed here.

- group_vars/all/08_networks.yml: declare PORT_BANDS.public.media
  (10000–10099) so the JVB media plane port (UDP/10000) falls in band.
- roles/web-app-jitsi/templates/env.j2: pipe every Jicofo/JVB/Jigasi/Jibri
  XMPP password through `| dotenv_quote`.
- roles/web-app-jitsi/meta/services.yml: make `email` flag dynamic
  (`'web-app-mailu' in group_names`) and add `# nocheck: dynamic-flag`
  + `# nocheck: playwright-service-flag` above `javascript:` (gated on
  sso.enabled, not on group_names; runtime DOM patch, no probe-able
  surface flag).
- roles/web-app-jitsi/meta/variants.yml: re-add explicit
  email.enabled / email.shared pins per variant (variant-coverage rule
  requires every dynamic flag to have both true- and false-pinning
  variants).
- roles/web-app-jitsi/meta/schema.yml: drop unused jwt_app_secret
  credential.
- roles/web-app-jitsi/vars/main.yml: drop unreferenced JITSI_HOSTNAME,
  JITSI_WEB_PROTOCOL, JITSI_JWT_APP_SECRET.
- roles/web-app-jitsi/templates/playwright.env.j2: drop unused
  ADMIN_EMAIL / JITSI_BASE_URL / OIDC_ISSUER_URL keys and collapse the
  PERSONA_*_BLOCKED comment block to one line per key (env-file schema
  rule allows at most one comment line above an entry).
- roles/web-app-jitsi/README.md: replace the dead
  jitsi-contrib/prosody-plugins/tree/main/token_lobby URL with the
  repository root.

Final result: `make test` 5/5 targets ✅ (186 tests OK),
`make autoformat` clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:57:06 +02:00
kevinveenbirkenbachandClaude Opus 4.7 201670975d refactor(dev-nix): factor Nix install steps into include_tasks to satisfy when-block lints
Two pre-existing lint failures on main (introduced in 45eea2892) blocked
`make test` from going green:

- test_excessive_repeated_when_in_tasks_files flagged the four
  `when: dev_nix_binary_path_before | length == 0` repeats across
  Purge / getent group / getent passwd / Run-installer tasks.
- test_blocks_with_when_and_sections_have_max_three_tasks rejects any
  `block:` carrying a block-level `when:` and more than 3 tasks per
  section, because the block-level `when:` does NOT skip parse-time
  resolution of inner tasks.

Final shape: the six install tasks live in
`02a_nix_install_only.yml` and are pulled in via a single
`include_tasks` guarded by the original `when:`. When the binary is
already present, Ansible never opens the included file at all.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:54:45 +02:00
kevinveenbirkenbachandClaude Opus 4.7 7ddb4453b5 style(web-app-zammad): collapse column-aligned whitespace to autoformat
Pure whitespace reflow applied by `make autoformat` — column-aligned
mapping values were collapsed to single-space alignment so the files
match the project-wide YAML formatter output. No behavior change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:54:30 +02:00
kevinveenbirkenbachandClaude Opus 4.7 4dcb1e866e feat(web-app-jitsi): add Jitsi Meet role with oauth2-proxy + LDAP variants
Adds the four-container Jitsi Meet stack (web, prosody, jicofo, jvb) with a
3-variant matrix: V1 oauth2-proxy gate + Keycloak LDAP federation, V2
no-auth anonymous, V3 direct prosody mod_auth_ldap2 against svc-db-openldap.

Auth model is oauth2-proxy at the reverse proxy because Jitsi has no
native OIDC adapter — JWT-via-Keycloak would require a custom token
server outside this repo. The role injects a fixed-position
`[data-injected-logout]` button via templates/javascript.js.j2 so the
no-built-in-logout React SPA satisfies the persona contract's
no-direct-URL logout rule. V2/V3 declare PERSONA_BIBER_BLOCKED /
PERSONA_ADMINISTRATOR_BLOCKED because the shared persona helpers only
model the OIDC redirect chain.

Final FULL-matrix `mode=reinstall full_cycle=true` run green across all
three variants (V1: 6/6 pass, V2/V3: 2 pass + 4 blocked skips).

Also lands utils/parse_trace.py — a small zipfile helper used during
the iteration to extract URL traces from playwright .trace bundles.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 12:20:11 +02:00
infinito-nexus-updater[bot] 0184e2cab2 update(images): update Docker image versions 2026-05-29 16:48:13 +00:00
kevinveenbirkenbach 2868cb9a5b Merge pull request #285 from kevinveenbirkenbach/fix/web-app-bookwyrm
Fix/web app bookwyrm
2026-05-29 18:21:06 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a52d2e626f refactor(dev-nix): extract official-installer branch to 03_install_official.yml
Adding the purge task pushed dev-nix/tasks/02_non_arch_installer.yml
to 4 tasks gated by `when: dev_nix_binary_path_before | length == 0`,
tripping tests.integration.roles.when.test_duplication.

A `block:` would satisfy that lint but exceeds the project convention
of max 3 entries per block. Move the six install-branch tasks (purge,
nixbld group+uid probes, override set_facts, installer run) into a
dedicated tasks/03_install_official.yml and call it once via
include_tasks with the original guard `when:` on the include.

Behavior unchanged; inner tasks no longer re-evaluate the binary-path
condition each call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:32:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 45eea2892f fix(dev-nix): purge stale nixbld users blocking Nix installer
The Nix 2.32.4 installer allocates build users ascending from
NIX_FIRST_BUILD_UID. The pkgmgr-centos:stable base image ships
nixbld1..nixbld32 with descending UIDs (RHEL `useradd -r` default:
nixbld1=997, nixbld2=996, ...) and no nix binary, so the role
detects no install, runs the installer, which then aborts on
"nixbld2 already exists, but with the UID '996'".

Add purge_stale_nixbld.sh, called via ansible.builtin.script
before the installer. Three guards must all hold to purge:
  1. No nix binary in candidate paths.
  2. nixbld2 UID < nixbld1 UID (broken descending layout).
  3. /nix/store does not exist (no live store to orphan).

Idempotent. Distro-agnostic at the script level: Debian/Ubuntu stay
[UNCHANGED] because guard 2 fails (nixbld users absent); Arch never
hits this code path. Production hosts with /nix/store present but
nixbld users get [FAIL] (rc=1) instead of silent destruction.

Fixes the 31/32 test-deploy-server / test-deploy-universal failures
observed in run 26634712613.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:09:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 b3541d873a docs(requirements): add 023 - Docker Swarm with NFS-backed shared volumes
Defines the v1 scope for multi-node Docker Swarm support: group-based
trigger (svc-docker-swarm + svc-docker-swarm-manager), three new roles
(svc-docker-swarm, svc-storage-nfs-server, svc-storage-nfs-client),
per-volume NFS opt-in (DB volumes stay local + pinned), overlay
networks with default encryption, and openresty kept as the swarm-mode
edge (pinned to manager, L7 LB via tasks.<service> upstream blocks) to
preserve the sys-front-inj-* injection pipeline unchanged. Pilot role
is web-app-mediawiki, validated by a 3-node DinD CI workflow whose
inventory is bootstrapped via the canonical inventory provision CLI.
Procedure block follows the autonomous-run pattern from 014.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 15:33:16 +02:00
kevinveenbirkenbach 84ca98e107 Merge branch 'main' into feature/web-app-zammad 2026-05-29 13:29:24 +02:00
kevinveenbirkenbachandClaude Opus 4.7 deb9a00e00 ci(workflows): move weekly schedules to Saturday 00:00 UTC
Consolidate update, security-codeql, and images-cleanup-ci onto the same
Saturday slot (`0 0 * * 6`). Drop stale cron comments.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 13:22:26 +02:00
kevinveenbirkenbachandClaude Opus 4.7 144f89482a refactor(web-app-zammad): finish services.sso sweep in variants + playwright
Completes the oidc → services.sso migration started in a3b585cfa:
- meta/variants.yml: rename oidc: keys to sso: in all three variants
  (V1, V2, V3) so dynamic-flag coverage matches the new services.yml
  shape and variant-services-match accepts the references
- templates/playwright.env.j2: emit SSO_SERVICE_ENABLED (sourced from
  services.sso.enabled) instead of OIDC_SERVICE_ENABLED, matching the
  unified env-key contract that fider/decidim already follow
- files/playwright/{_shared,test-login-*,test-rest-api-ticket-create,
  test-ticket-create-as-customer}.js: gate via isServiceEnabled("sso")
  / skipUnlessServiceEnabled("sso") so service-gating registers the
  service the SSO_SERVICE_ENABLED key exposes

`make test` now passes end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 13:12:05 +02:00
kevinveenbirkenbachandClaude Opus 4.7 278d5a1b48 refactor(web-app-zammad): sweep to unified services.sso schema
Migrates the role from the pre-v9.0.0 legacy oidc/oauth2 top-level
service blocks to the unified services.sso shape with flavor: oidc.
Drops the playwright.spec.js require for the test-alias-domain module
that was deleted in 82491791e, and removes the README link to the
TODO.md file dropped in c48386eee. Archives the in-flight 022 zammad
requirement doc into the README index since the role itself is now
landed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 13:12:05 +02:00
kevinveenbirkenbach 43ba34e6dc Merge branch 'main' into feature/web-app-zammad 2026-05-29 13:12:05 +02:00
kevinveenbirkenbach 6ccf37a446 Release version 9.0.2 2026-05-29 13:12:04 +02:00
kevinveenbirkenbach 9be620a73e Merge remote-tracking branch 'origin/main' into fix/web-app-bookwyrm 2026-05-29 12:51:28 +02:00