Commit Graph
242 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 e387adf749 test(playwright): make the guest persona resilient over onion
Use gotoOnion for the landing navigation so a transient Tor-circuit failure (ERR_SOCKS_CONNECTION_FAILED / ERR_TIMED_OUT) is retried on a fresh circuit instead of failing the test — a longer timeout alone cannot recover a failed circuit. Budget the test timeout via resolveTimeout. The never-authenticated assertion is unchanged; clearnet behaviour is identical (single goto attempt, resolveTimeout is identity).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 11:00:46 +02:00
kevinveenbirkenbachandClaude Opus 4.8 82606ef2af test(playwright): onion transport + secure-context test primitives
env.js gains gotoOnion (retries transient Tor-circuit errors on page.goto, clearnet unchanged) and isOnionCanonical (detect a .onion canonical). playwright.config.js marks .onion origins as a secure context via --unsafely-treat-insecure-origin-as-secure, emulating real Tor Browser (RFC 7686) so Clear-Site-Data logout and the Storage Access API behave as in production over onion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:47:39 +02:00
kevinveenbirkenbachandClaude Opus 4.8 35dee215c8 test(playwright): route all timeouts through resolveTimeout for onion-compat
Add the global TIMEOUT_FACTOR and a shared timeouts.js helper: resolveTimeout(base) scales by TIMEOUT_FACTOR and, over a .onion target, an extra multiplier, so Tor's per-request latency no longer trips hard-coded timeouts. Migrate every raw timeout in the specs (timeout:/timeout=/setTimeout/waitForTimeout) to resolveTimeout, stage the helper in all three staging paths, and add test_no_raw_timeouts to forbid raw numeric timeouts. Clearnet behaviour is unchanged (factor 1: resolveTimeout(N) === N).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 10:38:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c2fa2da88e style: apply make autoformat (whitespace only)
Indentation/whitespace normalization emitted by make autoformat across role meta/services.yml, meta/variants.yml and a task file. No semantic changes (verified: git diff --ignore-all-space is empty for every file). Kept separate from the Tor egress-router feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 08:22:01 +02:00
kevinveenbirkenbachandClaude Opus 4.8 897abcc28c feat(test-harness): route Tor tests via the SOCKS SPOT + secure the CLI stage
test-e2e-cli renders test.env at 0600 in a 0700 stage dir and always removes the stage tree (it holds base64 DB credentials). test-e2e-playwright + the e2e scripts resolve the node SOCKS from the single spot: playwright via lookup('tor_socks', 'host.docker.internal'), onion.sh takes it as a required arg, rerun-spec.sh composes it from INFINITO_TOR_SOCKS_PORT — no 9050 literal or backup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 23:53:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3f7face0aa feat(test-e2e-playwright): route .onion apps through Tor + defaults->vars refactor
Per-app PLAYWRIGHT_PROXY: an app whose canonical URL is a .onion (services.tor primary/exclusive) has its browser routed through the node Tor SOCKS proxy (socks5://host.docker.internal:9050); clearnet apps stay direct. A SOCKS readiness gate probes the hidden service and skips (not fails) the app's run when Tor cannot reach it. TEST_E2E_PLAYWRIGHT_PROXY is removed since the per-app logic supersedes the global knob. Non-overridable tuning constants moved defaults->vars (UPPERCASE); only genuinely overridable knobs (only_roles/skip_roles/keep/VARIANT_INDEX) remain in defaults.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 23:53:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 266a37d965 feat(svc-net-tor): onion mail/SSH ports + TLS-off compat (CA CN, HSTS, msmtp)
- svc-net-tor: expose SSH (22) + Mailu SMTP/submission/IMAP (25/465/587/143/993)
  as HiddenServicePorts on the node onion (TOR_ONION_SSH_ENABLED, 19_tor.yml).
- email lookup: relay plaintext (tls off, port 25) for .onion mail domains —
  no public TLS cert for a .onion; onion transport is already authenticated.
- CA root CN: drop the " Root CA" suffix when a 62-char v3 onion + suffix would
  overflow the X.509 commonName 64-char cap (02_tls.yml).
- Playwright onion compat: HSTS is HTTPS-only (RFC 6797), absent on the http
  onion vhost. New shared helper expectHstsWhenTls() gates the assertion on the
  reached scheme; wired into web-svc-cdn spec.
- rerun-spec.sh: route the inner-loop browser through the Tor SOCKS proxy when
  the staged env targets a .onion, mirroring the deploy-time runner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 16:39:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e6538e4f61 feat(svc-net-tor): Tor onion-service provider (full onion node)
Turn a NAT/edge node into a full Tor v3 onion node: DOMAIN_PRIMARY
becomes the node's .onion, so the whole stack (web, SSO, LDAP, CA)
resolves onion domains and is reachable over Tor without a public IP,
port forwarding, VPS or DynDNS.

- utils/tor_onion.py: offline v3 key mint (address + HiddenServiceDir
  key files), verified against a known key->address test vector.
- cli .../inventory/onion: `init-env` pre-mints the node onion, writes
  INFINITO_DOMAIN(+_RE) into .env and authoritative key files into
  .onion-identity/hs (idempotent). The onion is a deploy-time input;
  no in-deploy random minting (that would not match the pre-set domain).
- roles/svc-net-tor: Tor sidecar (Debian-built, network_mode: host),
  installs the minted keys, torrc with one node HiddenService + a SOCKS
  proxy restricted to loopback/DiD ranges. files/test.sh probes every
  served onion domain over the Tor SOCKS.
- tls: .onion -> TLS off (onion v3 crypto is the transport auth; LE
  cannot sign .onion) + app-level flavor override.
- harness/DNS: coredns resolves the onion zone via INFINITO_DOMAIN;
  skip the clearnet DNS sanity check for onion; raise nginx
  server_names_hash_bucket_size to 128 for long onion server_names.
- test-e2e-playwright: gated browser SOCKS proxy (PLAYWRIGHT_PROXY) +
  navigation/action timeouts so specs reach .onion over Tor and fail
  fast; the onion node points it at the Tor SOCKS.
- docs/requirements/031: full design.

Verified: dashboard + SSO (Keycloak) + 9 apps reachable over Tor
(HTTP 200 through the node hidden service). make test green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:38:11 +02:00
kevinveenbirkenbachandClaude Opus 4.8 96aa7784b6 feat(sys-svc-compose): scale all task timeouts via TIMEOUT_FACTOR lookup
Add a 'timeout' lookup plugin that returns round(base * TIMEOUT_FACTOR)
(group_vars default 1, so value-identical to the old literals). One knob
in group_vars stretches every wait in the stack for a slow uplink:
TIMEOUT_FACTOR: 2 doubles them all.

- plugins/lookup/timeout.py + unit tests (identity, factor scaling,
  string coercion, error paths).
- group_vars/all/17_resource.yml: TIMEOUT_FACTOR: 1.
- Convert all 34 literal 'timeout:' task keywords / module args across 25
  task+handler files to "{{ lookup('timeout', <base>) | int }}".
- tests/lint/repository/yaml/test_timeout_uses_lookup.py enforces the
  lookup in every task/handler timeout (opt-out: # nocheck: timeout-lookup).
- swarm.yml pre-deploy build handler: add the missing timeout (same
  network-build hang vector as compose.yml's Build compose).
- Drop 13 pre-existing narration comments in the touched files (comment
  lint enforces whole-file on any edited file).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 13:57:30 +02:00
kevinveenbirkenbachandClaude Opus 4.8 674d26de3a feat(lint/role-readme): derive Credits author from meta author SPOT
Role README Credits now name galaxy_info.author (plain bold or wrapped
in a Markdown link), matched byte-for-byte against the role's own
meta/main.yml, instead of a hard-coded maintainer name. Regenerate all
245 role README Credits blocks to the new 'Implemented by ...' format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 16:47:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e11bf6f31b refactor(lint): drop caveat/workaround comment markers
Remove caveat and workaround from the comment-lint marker vocabulary and delete
the comments that used them across the tree. Move test_comments_valid's own
git-safe.directory note from a marked comment into the function docstring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:54:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 23d1447566 refactor(ansible): add path_absolute lookup, replace playbook_dir joins
Introduce plugins/lookup/path_absolute.py as the single source for the
repo-root anchor: lookup('path_absolute', 'roles/...') returns an absolute
path under playbook_dir, joining every term. Replace all hand-built
playbook_dir path constructions across .yml/.yaml and .j2 templates with it:

  [playbook_dir, '<rel>'] | path_join   -> lookup('path_absolute', '<rel>')
  playbook_dir ~ '/<rel>'               -> lookup('path_absolute', '<rel>')
  {{ playbook_dir }}/<rel>              -> lookup('path_absolute', '<rel>')

Unrelated repo_path symbols in cli/meta/roles/applications/resolution and the
single bare discover_playwright_roles(playbook_dir) call are left untouched.

Add tests/lint/ansible/test_playbook_dir_via_lookup.py: fails the build if any
of the three construction forms reappears in .yml/.yaml/.j2, pointing callers
at the lookup. Unit test covers the plugin.

Touching these files pulled their pre-existing narration comments into
test_comments_valid scope; clean them (delete restatement/banners, keep real
trip-wires as Workaround/Upstream/Invariant markers). Drop caution, important
and pitfall from the comment-lint marker vocabulary and remove the comments
that used them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 20:36:57 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cddb0dc59b feat(lint): require emoji-prefixed task/step/job names + convert existing
Add tests/lint/repository/test_name_emoji_and_length.py: every Ansible task
name and GitHub Actions workflow/job/step name must start with an emoji (first
char not 0-9/A-Za-z) and be <= 80 chars.

- emit emoji names at the source: cli/build/include generator now writes
  "🔧 setup <app>" / "🚿 flush handlers after <app>" so generated
  tasks/groups/*-roles.yml satisfy the convention too
- convert existing task/step/job/workflow names to emoji-prefixed, choosing a
  task-fitting icon per action (📦 install, ✅ ensure, 🔍 probe, 🥾 bootstrap,
  🚀 deploy, 🧩 service-module load, ⬇️ checkout, 📂 include-routines, ...)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 22:45:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 36ebf34b64 Merge branch 'main' into feature/swarm-nfs
Resolve 69 conflicts across ~70 files: union main's image-version bumps and new service fields (bond, resource limits) with the swarm branch's default_placement / NFS / IS_STACK_HOST config; retire the three per-deploy-type test workflows main still edited (consolidated into compose+swarm); adopt main's run-once 01_core dispatchers while re-applying each role's swarm guard. Fix the post-merge lint surfaced by main's stricter rules: bond + resource-budget keys, container-exec stack-host gating + resolver routing, leaky/dead proxy vars, suitecrm once-flag, xwiki variant nocheck, nextcloud oversized-block to gated include, matrix-mdad capped at 3g. make autoformat clean, make test green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:13:55 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cf765ee00c refactor: single /var/lib SPOT + swarm Playwright artifact upload
SPOT: declare the var-lib base once in default.env as INFINITO_DIR_VAR_LIB; the env build derives INFINITO_PLAYWRIGHT_REPORTS_BASE_DIR from it; reference it everywhere (utils/paths.py, scripts via ${...:?}, tests, the dev inventory's DIR_VAR_LIB injection) instead of hardcoding the literal. group_vars keeps the literal default; the env-lookup lives in the dev inventory per the no-ansible-env-lookups lint rule. pull_specific_host.py --folder is now required and the role passes {{ DIR_BACKUPS }}.

Swarm e2e: collect_playwright_reports.sh docker-cp's the reports off the manager plus a workflow upload step, so swarm Playwright traces reach CI artifacts (was compose-only).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:01:09 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6d417aa9a4 fix(test-e2e-playwright): keep reports on e2e timeout via a Playwright globalTimeout
The Ansible task timeout hard-kills the Playwright sidecar at TEST_E2E_PLAYWRIGHT_RUN_TIMEOUT, discarding every junit/html/trace and aborting the play before the archive step. Set Playwright's own globalTimeout a buffer (60s) below that cap so it self-terminates with reports, the task returns rc\!=0 instead of being killed, and the diagnostics get archived for the next run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:01:09 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4698c65ce0 fix(test-e2e-playwright): bound networkidle waits with a 15s timeout
Unbounded `page.waitForLoadState("networkidle")` in the shared admin/seaweedfs
personas and the dashboard simpleicons-card test waited the long default before
the existing `.catch` swallowed it, so apps that never go network-idle
(websocket/long-poll: mailu admin, matomo) made the Playwright run exceed its
1200s task timeout. The result was already discarded, so capping each wait at
15s only bounds it; it matches the timeout already used elsewhere
(web-app-mailu playwright.spec.js, pihole, bluesky).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:31:35 +02:00
kevinveenbirkenbach 70a327046d Merge remote-tracking branch 'origin/main' into feature/026-unified-addon-syntax 2026-06-24 04:54:24 +02:00
infinito-nexus-updater[bot] 24d0644500 update(images): update Docker image versions 2026-06-24 04:54:09 +02:00
kevinveenbirkenbach cb29f29b28 Merge branch 'main' into feature/swarm-nfs 2026-06-24 03:46:12 +02:00
infinito-nexus-updater[bot] d13dc474ef update(images): update Docker image versions 2026-06-24 03:46:08 +02:00
kevinveenbirkenbach 21e484bf30 Merge origin/main into feature/026-unified-addon-syntax
Resolve conflicts: keep 026's bond/field/addon additions (services.yml, variants.yml,
yourls leaky-proxy fix, nextcloud per-file addons), take main's 027 integration-matrix
(generated artifact). Verified: all 44 main inline-plugins are covered by meta/addons/.
2026-06-21 06:32:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8fb1af2345 fix(test-e2e-playwright): widen in-app logout dropdown render wait to 1.5s
The universal-logout helper clicked the account-menu trigger and waited only 750ms for the dropdown to render its items. OpenProject's Angular SPA renders them slower under deploy load, so the logout control was missed (flaky biber universal-logout, recovered only on retry). Bump the post-click wait to 1500ms. Verified in-container: both universal-logout specs pass, no regression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:08 +02:00
kevinveenbirkenbachandClaude Opus 4.8 d2f5efa7fe feat(test-e2e-playwright): parallel workers via plugin + tunable timeouts; split role vars by precedence
Add plugins/lookup/playwright_workers.py computing a conservative parallel-worker count (CPU/RAM-derived, app-under-test concurrency-capped, reduced on CI) and wire test_e2e_playwright_workers + test_e2e_playwright_fully_parallel + test_e2e_playwright_test_timeout into playwright.config.js (read from env) and 02_run_one.yml (passed via -e). fullyParallel stays false so parallelism is file-level only and intra-file ordering assumptions stay safe. Raise run_timeout to 3600 for addon-heavy roles (nextcloud ~50 specs).

Split the role's variables by Ansible precedence and intent: derived/fixed constants live in vars/main.yml (UPPERCASE, high precedence, not operator-tuned), operator-tunable knobs live in defaults/main.yml (lowercase, overridable). VARIANT_INDEX stays UPPERCASE with a single definition. Update references across tasks/templates/inventory/docs accordingly. Includes a unit test for playwright_workers and an autoformat pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 06:03:06 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8e92f15f6a test(addons): require a Playwright spec for every addon; add 87 per-addon specs
Add tests/lint/ansible/services/test_addons_playwright_spec.py requiring roles/<role>/files/playwright/addons/<id>.spec.js for EVERY addon of EVERY role — no mechanism auto-exempt and no # nocheck escape. Ship the 87 per-addon specs (gated via skipUnlessAddonEnabled so they skip cleanly when the addon is disabled in the current variant), the test-e2e-playwright addon-gating harness (addon-gating.js, playwright.config.js, recursive 02_run_one.yml), the shared odoo helper, and the ADDON_<ID>_ENABLED flags in the six playwright.env.j2 templates. Relax test_env_file_schema to skip Jinja-templated keys in the ADDON loop. Doc updates (suppression.md, requirements/026) follow in a separate commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:16:54 +02:00
kevinveenbirkenbachandClaude Opus 4.8 51c3d41ede Merge origin/main into feature/swarm-nfs
Reconcile main's object-store feature and pre-swarm deploy tasks with the branch's compose/networks/volumes SPOT and swarm lints.

objstore (seaweedfs/minio): standalone compose + embedded service templates migrated to the container_image/container_volumes/container_networks/compose_volumes/compose_networks/depends_on lookups; meta/volumes.yml on the canonical dict schema with s3.json and nginx.conf as type:config; embedded services made swarm-compatible via compose_only/compose_restart.

deploy tasks (erpnext, opentalk, seaweedfs, shopware, snipe-it, wordpress, yourls): container exec routed through the container_address resolver and gated on IS_STACK_HOST, shell module plus stack_host_template, no chdir or compose-verb forms.

Also removed orphaned vars, restored MAILU_INSTANCE_DIR, freed the seaweedfs subnet (192.168.206.0/24), stripped literal quotes from the nextcloud/bookwyrm env templates, and routed main's objstore compose_volumes tests through dir_var_lib.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 21:08:49 +02:00
kevinveenbirkenbachandClaude Opus 4.8 43eb831de0 fix(e2e): run Playwright with --network host in swarm
In swarm the apps are reachable via the node host-mode proxy ports; share the node network namespace so the Playwright container resolves the canonical domains via the node dnsmasq and reaches them, instead of the compose --add-host host.docker.internal path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 19:49:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 97a43feb5f fix(e2e): tolerate networkidle timeout in CSP injection check
Realtime apps (websockets/polling) keep the connection busy so page.goto never reaches networkidle; the asset loads the assertion checks are captured during navigation regardless, so swallow the navigation timeout instead of failing the spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 19:49:18 +02:00
kevinveenbirkenbach 3fb0e393c3 Merge pull request #316 from kevinveenbirkenbach/fix/ci-deploy-server-failures
CI deploy/test fixes + SeaweedFS S3 object-store integration + addon requirements
2026-06-17 15:40:15 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c4c8672b5a fix(test-e2e-playwright): count native-login success as admin-persona auth proof
No-SSO roles authenticate via their own username/password form. The admin persona only treated a completed Keycloak round-trip as proof of reaching an authenticated surface, so a role like Snipe-IT — whose only logout control sits inside a collapsed account dropdown the visible-marker poll never sees — failed the gate even after a successful native login.

Track native-login success symmetrically: a real password form was found and submitted (loginAttempted), the form is gone afterwards, and the page parked on the role's canonical domain. The loginAttempted guard prevents a form-less public landing on the canonical domain from passing the gate without authentication. Also strip the verbose mid-code comments from the persona helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:30:45 +02:00
kevinveenbirkenbachandClaude Opus 4.8 98d1b23db7 fix(test-e2e-playwright): submit native admin login via Enter; stop matching account as an auth marker
OpenProject's /login renders a header Sign-in toggle plus a duplicate pulldown form, so a generic Sign-in button click hits the toggle and never submits the credentials. Press Enter on the password field to post the enclosing form (the button click stays as a fallback). Also drop the bare account token from the admin auth marker so an unauthenticated Create-a-new-account link no longer masks a failed login as no-logout-control.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:44 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6cf8e3cb30 fix(test-e2e-playwright): add a no-SSO native-login fallback to the admin persona
When SSO is disabled the OIDC step is a no-op, so drive the role's own username/password form with :visible selectors (skips hidden anti-autofill decoys such as snipe-it's password_fake) and a path-walk over /login,/admin/,/admin. The landing-page probe waits 10s; per-path probes 5s so a slow form at / is not abandoned. Fixes no-SSO admin journeys (snipe-it, yourls, openproject).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:42 +02:00
kevinveenbirkenbachandClaude Opus 4.8 41f12cb42c fix(test-e2e-playwright): seaweedfs check requires a NEW object key by default; opt-in mtime for single-slot consumers
Background workers (PeerTube transcode, Pixelfed media jobs) rewrite existing objects during the poll window, so accepting any changed mtime made those consumers false-green. Default is now a new key only (the original count-growth semantics); single-slot consumers that overwrite one fixed key in place (fider tenant logo) pass expectInPlaceOverwrite to also accept a changed mtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:42 +02:00
kevinveenbirkenbachandClaude Opus 4.8 5c19cf48a6 fix(test-e2e-playwright): add a native username/password login fallback to the admin persona for no-SSO variants (snipe-it)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:41 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e8d7c2f0d3 test(test-e2e-playwright): make the SeaweedFS storage-check poll deadline configurable (pollDeadlineMs, default 60s) so slow async-S3 movers can extend it
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3b60b36fb2 fix(web-app-peertube): repair the SeaweedFS object-store e2e test for PeerTube v8.2.1
The test timed out: the publish-button locator no longer matched the v8.2.1
manage-video wizard, and the inline 78-byte MP4 stub was structurally invalid,
so PeerTube rejected the upload as "Video file unreadable" and left the Save
button disabled.

- test-seaweedfs.js: target the v8.2.1 save control (.save-button > button),
  upload PeerTube's real video_short.mp4 fixture, and assert a version-tolerant
  saved marker.
- add fixture roles/web-app-peertube/files/playwright/fixtures/video_short.mp4.
- test-e2e-playwright: stage role-local files/playwright/fixtures/ next to the
  tests (the *.js glob ships neither binaries nor subdirectories), so specs load
  a fixture via path.join(__dirname, "fixtures", <name>).
- docs: document the fixtures/ folder and the per-scenario test-*.js split in the
  playwright spec contract and the runner README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:36 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1fa5161dd2 feat(web-app-nextcloud): provision on SeaweedFS S3 object store + consumer e2e test
Render the S3 objectstore config (templates/config/objectstore.config.php.j2) into NC's config dir before install, gated on objstore.enabled — NC cannot switch an already-installed instance to objectstore primary storage, so it must be present at install time.

Add the SeaweedFS consumer storage Playwright test (files/playwright/test-seaweedfs.js, playwright.env.j2 SEAWEEDFS_* vars, spec wiring; drop the playwright-service-flag nocheck for the seaweedfs service) plus the shared runSeaweedfsStorageCheck helper (admin logs into the Filer once, counts bucket objects via the Filer JSON listing, asserts growth) and the seaweedfs-consumer integration lint.

web-app-seaweedfs: bind weed to 0.0.0.0 (-ip.bind) so the multi-homed gateway is reachable by consumers that resolve the service name to its IP on the shared network.

nextcloud_install: classify 'was not found on the appstore' as unavailable (skippable, non-fatal) so a plugin without a release for the pinned NC version does not abort the whole deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 11:30:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 febd345ce5 fix(test-e2e-playwright): count native-login success as admin-persona auth proof
No-SSO roles authenticate via their own username/password form. The admin persona only treated a completed Keycloak round-trip as proof of reaching an authenticated surface, so a role like Snipe-IT — whose only logout control sits inside a collapsed account dropdown the visible-marker poll never sees — failed the gate even after a successful native login.

Track native-login success symmetrically: a real password form was found and submitted (loginAttempted), the form is gone afterwards, and the page parked on the role's canonical domain. The loginAttempted guard prevents a form-less public landing on the canonical domain from passing the gate without authentication. Also strip the verbose mid-code comments from the persona helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:31:34 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e7b5860b5b fix(test-e2e-playwright): submit native admin login via Enter; stop matching account as an auth marker
OpenProject's /login renders a header Sign-in toggle plus a duplicate pulldown form, so a generic Sign-in button click hits the toggle and never submits the credentials. Press Enter on the password field to post the enclosing form (the button click stays as a fallback). Also drop the bare account token from the admin auth marker so an unauthenticated Create-a-new-account link no longer masks a failed login as no-logout-control.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 15:47:23 +02:00
infinito-nexus-updater[bot] bc0a521a69 update(images): update Docker image versions 2026-06-16 09:40:25 +00:00
kevinveenbirkenbachandClaude Opus 4.8 d4f43a43de fix(test-e2e-playwright): add a no-SSO native-login fallback to the admin persona
When SSO is disabled the OIDC step is a no-op, so drive the role's own username/password form with :visible selectors (skips hidden anti-autofill decoys such as snipe-it's password_fake) and a path-walk over /login,/admin/,/admin. The landing-page probe waits 10s; per-path probes 5s so a slow form at / is not abandoned. Fixes no-SSO admin journeys (snipe-it, yourls, openproject).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 01:58:01 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4cdfde8eef fix(test-e2e-playwright): seaweedfs check requires a NEW object key by default; opt-in mtime for single-slot consumers
Background workers (PeerTube transcode, Pixelfed media jobs) rewrite existing objects during the poll window, so accepting any changed mtime made those consumers false-green. Default is now a new key only (the original count-growth semantics); single-slot consumers that overwrite one fixed key in place (fider tenant logo) pass expectInPlaceOverwrite to also accept a changed mtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 01:58:00 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a24c93c3d2 fix(test-e2e-playwright): add a native username/password login fallback to the admin persona for no-SSO variants (snipe-it)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 02:42:47 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bec512d251 test(test-e2e-playwright): make the SeaweedFS storage-check poll deadline configurable (pollDeadlineMs, default 60s) so slow async-S3 movers can extend it
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 01:14:28 +02:00
kevinveenbirkenbachandClaude Opus 4.7 c61c68e903 test(lint): forbid >3-child blocks + ≥3-task same-when runs; refactor 5 roles
Adds two structural ansible lints under tests/lint/ansible/structure/:

- ansible-block-oversized: forbid `- block:` constructs with more than
  3 direct child tasks. Big block bodies hide intent, accumulate
  unrelated guards on the wrapper, and signal that the body wants to
  be its own include_tasks sub-file. Extraction keeps the parent
  scannable; the sub-file MAY carry the `# include-gated:
  when: …` header marker so swarm-compat lints exempt it.

- ansible-repeated-when-run: forbid 3+ consecutive sibling tasks
  carrying the SAME `when:` expression. Copy-pasted guards drift,
  silently disable each other over time, and read worse than a single
  `- name: …` + `when: <expr>` + `block:` wrapper. Per-line opt-out
  for runs where wrapping would alter semantics (cross-task register
  dependencies).

Both lints use the line-based scanner pattern from existing
tests/lint/ansible/jinja/* + `is_suppressed_at` from
utils.annotations.suppress for the per-line nocheck markers.

Refactors five roles into compliance:

- svc-prx-openresty/tasks/02_assert.yml: heavy rescue body extracted
  to 02a_assert_rescue_debug.yml.
- test-e2e-playwright/tasks/01_setup.yml: 3 install-needed siblings
  wrapped in a single when-block.
- web-app-erpnext/tasks/02_bench_bootstrap.yml: 3 site-probe-failed
  siblings wrapped likewise.
- web-app-odoo/tasks/02_install_modules.yml: 3 OIDC-enabled siblings
  wrapped. tasks/03_oidc.yml: dropped redundant single-task wrapper
  block (the original wrapper carried name only and would have
  required extraction for size — inlining the 23 tasks at file root
  keeps the file purpose-narrow and removes one layer of indirection).
- web-app-xwiki/tasks/04_extensions.yml: large block body + rescue
  body both extracted to 04a_extensions_rescue.yml +
  04b_extensions_execute.yml.

Mixed-scope offenders (web-app-keycloak/tasks/{02_manager_ops,05a,
assert/05_ldap,update/05_ldap_shared,02a} and
web-app-matomo/tasks/{03_manager_ops,05_bootstrap,05a}) deliberately
stay unstaged; they ship with their respective swarm-aware
restructure commits where they belong by topic, not bundled with the
structural-lint cleanup.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 19:08:46 +02:00
kevinveenbirkenbachandClaude Opus 4.8 70ad33bc13 fix(web-app-peertube): repair the SeaweedFS object-store e2e test for PeerTube v8.2.1
The test timed out: the publish-button locator no longer matched the v8.2.1
manage-video wizard, and the inline 78-byte MP4 stub was structurally invalid,
so PeerTube rejected the upload as "Video file unreadable" and left the Save
button disabled.

- test-seaweedfs.js: target the v8.2.1 save control (.save-button > button),
  upload PeerTube's real video_short.mp4 fixture, and assert a version-tolerant
  saved marker.
- add fixture roles/web-app-peertube/files/playwright/fixtures/video_short.mp4.
- test-e2e-playwright: stage role-local files/playwright/fixtures/ next to the
  tests (the *.js glob ships neither binaries nor subdirectories), so specs load
  a fixture via path.join(__dirname, "fixtures", <name>).
- docs: document the fixtures/ folder and the per-scenario test-*.js split in the
  playwright spec contract and the runner README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 14:07:03 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c86ab1e37b feat(web-app-nextcloud): provision on SeaweedFS S3 object store + consumer e2e test
Render the S3 objectstore config (templates/config/objectstore.config.php.j2) into NC's config dir before install, gated on objstore.enabled — NC cannot switch an already-installed instance to objectstore primary storage, so it must be present at install time.

Add the SeaweedFS consumer storage Playwright test (files/playwright/test-seaweedfs.js, playwright.env.j2 SEAWEEDFS_* vars, spec wiring; drop the playwright-service-flag nocheck for the seaweedfs service) plus the shared runSeaweedfsStorageCheck helper (admin logs into the Filer once, counts bucket objects via the Filer JSON listing, asserts growth) and the seaweedfs-consumer integration lint.

web-app-seaweedfs: bind weed to 0.0.0.0 (-ip.bind) so the multi-homed gateway is reachable by consumers that resolve the service name to its IP on the shared network.

nextcloud_install: classify 'was not found on the appstore' as unavailable (skippable, non-fatal) so a plugin without a release for the pinned NC version does not abort the whole deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 20:17:34 +02:00
kevinveenbirkenbachandClaude Opus 4.7 05f6a97bd8 refactor(stack_host_template): generalise IS_STACK_HOST template wrapper across the codebase
Renames the local action plugin from `conf_template` to
`stack_host_template` so the name carries the actual semantics
(IS_STACK_HOST gate, not nginx config), broadens the lint guard to
every bare `template:` task, and migrates every consumer found in the
audit.

Plugin / tests / lint:
  * plugins/action/conf_template.py -> plugins/action/stack_host_template.py
    (drop nginx-specific docstring; trust_as_template gate unchanged)
  * test_conf_template.py            -> test_stack_host_template.py
  * test_conf_template_migration.py  -> test_stack_host_template_migration.py
    Scope expanded from `.conf.j2` to every `template:` task; marker
    renamed to `nocheck: stack-host-template`.

Migrations (~50 tasks now using stack_host_template:):
  * sys-svc-compose/04_files.yml: compose.yml, .env, Dockerfile,
    compose.override (every per-app compose-tree file)
  * web-app-keycloak: sso_proxy upstream-config (fixes the friendica
    CI failure that prompted this refactor) + realm-import
  * web-app-taiga, web-app-matrix, web-app-opentalk, web-app-pgadmin,
    web-app-moodle, web-app-listmonk, web-app-littlejs, web-app-fediwall,
    web-app-wordpress, web-app-discourse, web-app-bigbluebutton,
    web-app-jenkins, web-app-jitsi, web-app-mobilizon, web-app-suitecrm,
    web-app-decidim, web-app-dashboard, web-app-nextcloud, web-app-xwiki,
    web-app-mailu, web-app-magento, web-app-odoo, web-app-prometheus,
    web-app-matrix, web-app-peertube, web-app-mailu (+ existing `conf_template:`
    callers updated to the new name)
  * sys-front-tls, svc-db-openldap, sys-svc-webserver-core,
    sys-svc-rdbms (dedicated DB env + initdb), sys-front-inj-css,
    sys-front-inj-dashboard, sys-front-inj-all, sys-stk-front-proxy,
    web-svc-cdn-css, web-svc-xmpp, web-svc-legal, web-svc-simpleicons,
    web-opt-rdr-domains

Nochecks (per-host or already-structurally-stack-host):
  * sys-svc-mail-smtp/postfix, sys-svc-sshd, sys-svc-container/daemon.json
  * sys-timer, sys-service, sys-svc-mail-msmtp, sys-svc-journalctl,
    sys-daemon, sys-svc-compose/utils/_render_one_template (delegate_to
    stack host with peer slurp dance)
  * dev-locales, dev-nix, desk-*, user, user-backup, user-workstation
  * svc-storage-nfs-server/exports, test-e2e-playwright stage dirs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 15:45:38 +02:00
kevinveenbirkenbachandClaude Opus 4.7 9d8a4155a2 fix(test-e2e-playwright): stat repo paths on controller, not on STACK_HOST
The role's block-level `delegate_to: STACK_HOST` made five `stat:` tasks
run on the manager, which has no repo checkout — `playbook_dir`-based
paths always returned `exists=false` and the subsequent `fail:` tasks
aborted runs like web-app-baserow / web-app-akaunting with
"Missing Playwright env template". Override delegate_to to localhost on
each repo-path stat so the existence check runs where the files
actually live; CA-cert stats keep their STACK_HOST scope because those
files belong to the host.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 20:57:59 +02:00
kevinveenbirkenbachandClaude Opus 4.7 fdf0fed9c4 fix(test-e2e-playwright): delegate to STACK_HOST instead of IS_STACK_HOST gate
The IS_STACK_HOST gate in main.yml never blocked workers because
test-e2e-playwright does not set its own application_id, so DEPLOYMENT_MODE
fell through to 'compose' and IS_STACK_HOST evaluated true on every host.
Workers then ran 02_run_one.yml and crashed on the CA cert check because
the cert only exists on the manager.

Replace with block: + delegate_to: STACK_HOST + run_once: true so the
orchestration runs once on the primary manager regardless of which hosts
are in the play.

Also rename SWARM_PRIMARY_MANAGER -> STACK_HOST repo-wide to match the
existing IS_STACK_HOST symmetry and drop the swarm-specific terminology
(the variable falls back to inventory_hostname in compose mode).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 17:07:20 +02:00