Commit Graph
14682 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.7 908408ba39 fix(test-swarm): re-disable error modes after sourcing _context.sh
12_collect_diagnostics.sh starts with `set +e` before sourcing
_context.sh, which immediately re-enables `set -euo pipefail` for the
remainder of the script. The first `docker exec ... mount | grep -i nfs`
that finds no nfs mount returned rc=1, pipefail propagated it, and
errexit aborted the script halfway through. GitHub Actions reported a
red tab on the diagnostic step next to the actual failing deploy step.

Move `set +e`/`set +o pipefail`/`set +u` after the source so the
post-failure helper continues through every probe even when individual
commands return non-zero, and the trailing `exit 0` still pins the
script's return code to success.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:18:33 +02:00
kevinveenbirkenbachandClaude Opus 4.7 1931241cc7 refactor(modes): introduce MODE_ASSERT_LOCAL SPOT and migrate preload asserts
Adds MODE_ASSERT_LOCAL to group_vars/all/01_modes.yml:
    MODE_ASSERT_LOCAL: "{{ (MODE_ASSERT | bool) and (IS_STACK_HOST | bool) }}"

The mailu preload-assertion in sys-svc-mail/tasks/01_core.yml previously
fired on every host in `'web-app-mailu' in group_names` with no
MODE_ASSERT gate at all, so swarm workers ran into the assertion every
single CI run even though the preload state lives only on the stack
host. Same shape applies to a dozen other assertions: sys-svc-rdbms
(already double-gated, now collapsed), keycloak's kcadm-driven LDAP /
RBAC / reCAPTCHA / groups-path asserts, the sys-svc-compose handler
validators for compose/swarm config, svc-prx-openresty's 02_assert,
sys-svc-webserver-core's 05_assert, web-app-matomo's bootstrap token
check, web-app-joomla's 05_assert, and the sys-ctl-alm-compose notifier
self-start.

Each asserted state (run_once_<role> flags, kcadm output, openresty
container probes, compose-tree files) lives only on IS_STACK_HOST, so
the new SPOT keeps the assertion semantics intact while skipping the
spurious worker-side failures.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:18:33 +02:00
kevinveenbirkenbachandClaude Opus 4.7 446a41b478 fix(test-swarm): mirror MGR host_vars to workers instead of -e default.yml
Loading default.yml via `-e @"${INFINITO_INVENTORY_VARS_FILE}"` (commit
a3c75bde7) made the dev vars available on workers but at extra-vars
precedence (level 22), which overrode the `set_fact` merge in
tasks/stages/01_constructor.yml that reconciles defaults_oidc with the
inventory-supplied OIDC. Workers and mgr-01 ended up with OIDC =
{CLIENT: {SECRET: ...}} only, so the templates that resolved
OIDC.CLIENT.LOGOUT_URL (sys-front-inj-logout etc.) aborted with "dict
has no attribute 'LOGOUT_URL'".

Mirror the provisioned host_vars/${MGR}.yml to host_vars/${WRK1}.yml and
host_vars/${WRK2}.yml at the end of 05_provision_inventory.sh instead.
Same default.yml source via the existing INFINITO_INVENTORY_VARS_FILE
SPOT, same content on every swarm host, but at host_vars precedence
(level 9) so the role-level merge wins on access. Removes the
now-redundant `-e` line from the workflow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 14:18:32 +02:00
kevinveenbirkenbachandClaude Opus 4.7 9a82748092 fix(conf_template): mark IS_STACK_HOST expr trusted for Ansible 2.19+ templar
Ansible 2.19 introduced a `_trust_check` in the template engine that
silently returns Python-constructed strings unchanged when they lack the
TrustedAsTemplate tag (see ansible/_internal/_templating/_engine.py:288).
`self._templar.template("{{ IS_STACK_HOST | bool }}")` therefore returned
its own input every time, _to_bool rejected the literal, and every
nginx-tree conf_template task aborted on swarm-mgr-01.

Wrap the expression with `ansible.template.trust_as_template` before
handing it to the templar. Adds a unit test that uses `is_trusted_as_template`
to guard against future regressions that drop the tag.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 13:15:54 +02:00
kevinveenbirkenbachandClaude Opus 4.7 670e1a6a9d chore(test-swarm): post-failure helpers always exit 0
12_collect_diagnostics.sh now ends with an explicit `exit 0` so the
diagnostic step never propagates a non-zero rc to GitHub Actions.
zip_swarm_for_upload.sh switches from `set -euo pipefail` to `set +e`
plus a trailing `exit 0` for the same reason. Keeps the workflow's red
tab on the actual failing step instead of doubling up on the post-mortem
collectors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 12:34:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3d0c568bf7 fix(conf_template): rebuild templar from scratch + drop IS_STACK_HOST default
The previous fix (`self._templar.available_variables = task_vars`) was
not enough in the Ansible version the swarm CI ran on: templar.template()
still returned the literal Jinja string and _to_bool rejected it. Build
a fresh Templar(loader, variables=task_vars) so the variable scope is
explicit and version-independent.

Also drop `| default(false)` from the gate expression. IS_STACK_HOST is
defined unconditionally in group_vars/all/18_swarm.yml; the default was
dead code that would silently mask a future regression where the SPOT
gets removed. Without it, an undefined IS_STACK_HOST raises loudly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 12:34:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 e596df9d11 chore: nocheck dnsmasq server= lines + autoformat double-space fixes
Add `# nocheck: hardcoded-dns-resolver` on the two `server=` lines
inside the dnsmasq heredoc in 02_start_swarm_nodes.sh so the
test_no_hardcoded_dns_resolvers lint guard recognises the literals as
intentional (dnsmasq parses `#` as a comment, so the marker is
inert at runtime).

Re-stage three pure-formatting tightenings ansible-lint applied to
existing `template:  # nocheck` lines (double space -> single space)
in sys-daemon, sys-svc-mail-msmtp and web-app-moodle.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 11:48:52 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d3555858ab fix(test-swarm): local dnsmasq on mgr-01 resolves mocked DOMAIN_PRIMARY
The MODE_DEBUG-gated DinD DNS handler in sys-svc-container spawned a
busybox container with `--dns 1.1.1.1` and expected the mocked
infinito.example to resolve to 127.0.0.1, which Cloudflare obviously
cannot do. Run an in-cluster dnsmasq inside mgr-01 instead of patching
the symptom out:

- Stop and mask systemd-resolved so port 53 is free.
- Bootstrap /etc/resolv.conf with 1.1.1.1 so apt-get can fetch dnsmasq.
- Install dnsmasq with bind-dynamic, no-resolv, address=/${INFINITO_DOMAIN}/127.0.0.1
  and 1.1.1.1/8.8.8.8 as upstream forwarders; bind-dynamic catches docker0
  when the Ansible-installed dockerd creates it later.
- Switch /etc/resolv.conf to 127.0.0.1 and verify the chain via
  `getent ahosts ${INFINITO_DOMAIN}` so the script fails fast on misconfig.
- Pin mgr-01's docker0 to 172.17.0.1/16 via daemon.json `bip`, then point
  the swarm.yml networks.internet.dns at that gateway so DinD-spawned
  containers reach dnsmasq via their default route.

Also re-stage three pure-formatting tightenings ansible-lint made to
existing `template:  # nocheck` lines (double space -> single space).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 11:40:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 dc656e711f fix(test-swarm): inject test.<domain> + write /etc/hosts on all nodes
The previous commit's default.yml load turned MODE_DEBUG (and therefore
MODE_ASSERT) on for the swarm CI, which activates the DNS check in
tasks/stages/01_constructor.yml:12 that resolves
test.{{ DOMAIN_PRIMARY }}. The pipeline failed on all four hosts
(mgr-01, wrk-01, wrk-02, nfs-server) because:

1. write_hosts_entries did not emit test.<domain> at all.
2. 02_start_swarm_nodes wrote /etc/hosts only on the manager.

Add test.<domain> to the emitted set and write the resulting block to
mgr + both workers + nfs-server so the assertion succeeds everywhere
the play targets.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 10:57:45 +02:00
kevinveenbirkenbachandClaude Opus 4.7 faeeed08f9 fix(ci): route default-inventory vars-file through INFINITO_INVENTORY_VARS_FILE
The previous commit hardcoded "inventories/development/default.yml" in
the swarm deploy step, which the inventory-vars-file SPOT drift guard
(tests/unit/cli/administration/deploy/development/test_inventory_vars_file_spot.py)
forbids outside the whitelist. Read the path from the env var that
scripts/meta/env/load.sh exports so both the workflow and the deploy
chain consume the same SPOT.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 10:36:11 +02:00
evangelostsak b7f0f81e5b fix(web-app-penpot): move subnet to 192.168.105.192/28 (avoid upstream erpnext collision)
Upstream main added web-app-erpnext on 192.168.105.176/28, which now
collides with web-app-penpot after the rebase. test_unique_subnets /
test_no_overlapping_subnets failed in manual CI (run 27055475680).
Reassign penpot to the next free /28 (192.168.105.192/28).
2026-06-06 09:25:27 +02:00
evangelostsak c5aabd3319 feat(web-app-penpot) Change AUTHOR 2026-06-06 08:22:13 +02:00
evangelostsak 15502403ff fix(web-app-penpot): drop unused spec var + holder image (CI: js-lint + image-mirror)
Manual CI (run 27030584621) failed two branch-caused jobs:

- lint-javascript: no-unused-vars on `expectedBase` in the spec's
  penpotLdapLogin (the LDAP path asserts on /auth/login, not the base
  URL). Remove the dead binding (eslint now 0 errors).
- images-mirror-missing: the `penpot` metadata holder carried
  `image: penpotapp`, so the mirror tried docker.io/library/penpotapp:2.5.4
  (access denied — not a real image). The real images live on the
  frontend/backend/exporter entities; the holder only needs `version`
  (the shared tag). Drop the holder image (matches taiga/openproject).
2026-06-06 08:22:13 +02:00
evangelostsak 76c4cf52b1 fix(tests): restore missing __init__.py after test folder split
An earlier 'refactor(tests): split overflowing folders into thematic
subdirs' commit left 59 directories under tests/ without the __init__.py
package marker that tests/lint/filesystem/test_init_files.py requires,
making the lint suite red independently of any role change. Recreate the
empty markers so the suite passes.
2026-06-06 08:22:13 +02:00
evangelostsak 83ab973dfa feat(web-app-penpot): live-verify OIDC/LDAP + project/asset; JVM CA-trust fix; archive req 235
Deployed Penpot + Keycloak + OpenLDAP end to end and drove the per-role
Playwright suite green against the live stack (8 passed, 2 skipped):
TLS baseline, OIDC (administrator + biber), LDAP (administrator + biber),
project creation, and image asset upload. The two skips are the generic
biber/administrator persona scenarios, declared blocked via
PERSONA_*_BLOCKED (mirroring web-app-taiga): Penpot's in-app "OpenID"
login entry and SPA user-menu logout are not driveable by the generic
persona helper, so both users' real auth is exercised by the dedicated
OIDC + LDAP scenarios.

Fixes found during bring-up:
- OIDC JVM CA trust: the backend command imports the internal CA into a
  writable cacerts copy and points the JVM at it via JAVA_TOOL_OPTIONS.
  with-ca-trust.sh covers OS/NSS/env trust but not the JVM truststore, so
  server-side token/userinfo calls to Keycloak failed with "PKIX path
  building failed". CA path hardcoded (the CA-override double-escapes a $).
- disable-onboarding added to PENPOT_FLAGS so users land on the dashboard.
- Playwright env: ADMIN_EMAIL/BIBER_EMAIL for the LDAP form; alphabetised.

Requirement 235 is fully checked off and archived out of docs/requirements/.
2026-06-06 08:22:13 +02:00
evangelostsak edef635fbb feat(web-app-penpot): add Penpot design platform role (req 235)
Add a new `web-app-penpot` role deploying Penpot's frontend + backend +
exporter containers behind the standard reverse proxy, with shared
svc-db-postgres and a svc-db-redis sidecar. Wires native OIDC (Keycloak)
and LDAP (OpenLDAP) login via PENPOT_FLAGS, CSP/vhost via sys-stk-full,
backup-ready asset volume, marketplace tags, matrix variants
(all-on/all-off/LDAP-only), and a service-gated Playwright spec with
guest/biber/administrator personas plus separate OIDC and LDAP scenarios.

Implements docs/requirements/235-setup-penpot.md. Live-deploy DoD items
(fresh-host deploy, domain reachability, full in-container `make test`)
remain unverified in the sandbox and are left unchecked.
2026-06-06 08:22:13 +02:00
evangelostsak 4757a639b0 revert: clean branch to upstream main state
Remove the entire web-app-penpot role, all associated docs, and all other
changes accumulated on this branch. Working tree now matches origin/main
exactly. Commit history preserved for reference.
2026-06-06 08:22:13 +02:00
evangelostsak 0adeb2eb32 revert(branch-cleanup): restore all non-penpot files to origin/main state
Remove changes to test-e2e-playwright, opencloud/opentalk/wordpress specs,
shellcheck script, integration tests, and utils that were accidentally
committed alongside the web-app-penpot role implementation.

Only roles/web-app-penpot/ and docs/requirements/006-setup-penpot.md
should differ from main on this branch.
2026-06-06 08:22:13 +02:00
evangelostsak d57c0aca2d feat(web-app-penpot): complete role setup with playwright e2e tests
- Move playwright spec to roles/web-app-penpot/files/playwright/ (standard location)
- Fix APP_BASE_URL: use normalizeUrl() to strip dotenv_quote double-quotes
- Gate biber/admin tests with safeSkipUnlessEnabled('oidc') (penpot requires OIDC)
- Add meta/variants.yml with all-true, all-false, LDAP-only variants
- Fix templates: use container_depends_on lookup, correct LDAP group vars
- Align services.yml: javascript service static false with nocheck comment
- Update playwright.env.j2: OIDC_SERVICE_ENABLED env var for service gate
- All make test targets pass (lint, test-unit, test-integration, test-lint, test-external)
2026-06-06 08:22:13 +02:00
evangelostsak 609d3cc10e fix(ci): unblock penpot deploy and user secrets 2026-06-06 08:22:13 +02:00
evangelostsak 8e3c3eb0f2 fix(web-app-penpot): resolve metadata collisions 2026-06-06 08:22:13 +02:00
evangelostsak 7d6a835b9b fix(web-app-penpot): update backend http port from 8071 to 8074 2026-06-06 08:22:13 +02:00
evangelostsak 6f6d7c1d17 fix(web-app-penpot): fix subnet collision (use .80/28) and merge duplicate penpot service key with lifecycle:beta 2026-06-06 08:22:13 +02:00
evangelostsak 8b362fa216 fix(web-app-penpot): rename service key frontend→penpot to match entity name for sys-stk-full port resolution 2026-06-06 08:22:13 +02:00
evangelostsak 93b9a4ca1f fix(web-app-penpot): restore csp.flags nesting in server meta 2026-06-06 08:22:13 +02:00
evangelostsak 827bffc10f fix(web-app-penpot): add networks.local.subnet to meta/server.yml (req-009) 2026-06-06 08:22:13 +02:00
evangelostsak 820388bd95 Add initial integration tests for ports 2026-06-06 08:22:13 +02:00
evangelostsak c2f5a31d32 Refactor Penpot configuration to align service paths in main.yml 2026-06-06 08:22:13 +02:00
evangelostsak 67cc30a5d6 Remove administrator user configuration from Penpot web app 2026-06-06 08:22:13 +02:00
evangelostsak 54f5859f51 Add proxy configuration for Penpot web app 2026-06-06 08:22:13 +02:00
evangelostsak 3d69c905b5 Add JVM_OPTS configuration for Penpot backend 2026-06-06 08:22:13 +02:00
evangelostsak c15c61c671 Update Penpot service configurations in compose.yml.j2 for frontend, backend, exporter, and redis 2026-06-06 08:22:13 +02:00
evangelostsak ac9dfa299e Remove schema for Penpot secret key credentials 2026-06-06 08:22:13 +02:00
evangelostsak 1995944eca Add assets volume configuration for Penpot web app 2026-06-06 08:22:13 +02:00
evangelostsak 482486e6ae Add administrator user configuration to users.yml for Penpot web app 2026-06-06 08:22:12 +02:00
evangelostsak fcb42554ed Add services configuration for Penpot web app 2026-06-06 08:22:12 +02:00
evangelostsak fc4fd1a480 Add Content Security Policy configuration for Penpot web app 2026-06-06 08:22:12 +02:00
evangelostsak 68fe820eb2 Add schema for Penpot secret key credentials 2026-06-06 08:22:12 +02:00
evangelostsak b5b2d2efdf Remove obsolete license and repository fields from main.yml for web app Penpot 2026-06-06 08:22:12 +02:00
evangelostsak ae9c3b485b Add logo configuration to info.yml for web app Penpot 2026-06-06 08:22:12 +02:00
evangelostsak 9cca005256 Remove obsolete Penpot configuration file to streamline project structure 2026-06-06 08:22:12 +02:00
evangelostsak b8eb3e5128 Refactor README to enhance clarity and organization of the Purpose section and update formatting for consistency 2026-06-06 08:22:12 +02:00
evangelostsak 713d495dd0 Add schema for Penpot secret key credentials 2026-06-06 08:22:12 +02:00
evangelostsak ba28a31e55 Remove Penpot pre-test health gate; rely on Playwright in-test OIDC retries 2026-06-06 08:22:12 +02:00
evangelostsak 3dafad7577 Retry Penpot OIDC sign-in in Playwright spec to tolerate transient first-entry restart 2026-06-06 08:22:12 +02:00
evangelostsak c2ffe56a68 Add health check for Penpot API before Playwright tests to ensure backend readiness 2026-06-06 08:22:12 +02:00
evangelostsak d2ce6b00b7 Revert "Restore clear-on-success in Playwright to handle retries during test execution"
This reverts commit 5bcd969b23f69ed8e2e8cc0fd7b9051c243031e1.
2026-06-06 08:22:12 +02:00
evangelostsak 8beaa3e03c Restore clear-on-success in Playwright to handle retries during test execution 2026-06-06 08:22:12 +02:00
evangelostsak d2906a9f63 fix(web-app-penpot): clear Playwright failures on role success 2026-06-06 08:22:12 +02:00
evangelostsak 5e8f7e4f6a fix(test-e2e-playwright): remove clearing of failure state on success for retries 2026-06-06 08:22:12 +02:00