75 commits: the socialhome role reimplemented against the project it actually
deploys, native-login specs for funkwhale and shopware, a window.open IdP
handoff and a settings-link fallback in the shared persona helpers, a swarm
converge budget that gives up on a terminal task, and a long tail of role
fixes.
Eleven conflicts. The shared persona helpers (keycloak.js, logout.js) take the
incoming structure — they gained real behaviour this branch never had — with
this branch's resolveTimeout convention re-applied over it and
confirmKeycloakLogoutIfPrompted re-attached at every return point; without it
the Keycloak SSO session outlives the logout. playwright.config.js keeps this
branch's version: both sides set actionTimeout, but ours routes through an env
var and 15s is too short behind an onion. socialhome's spec takes the incoming
content — 2dbd6eb10 found the role described the wrong upstream project
entirely — and keeps gotoOnion and expectHstsWhenTls, since demanding HSTS over
a plaintext onion is a false failure. Both READMEs were regenerated rather than
merged by hand.
Three collisions arrived with no conflict marker at all, because each side
changed a different place in a different file:
- group_vars/all/18_swarm.yml declared swarm_stack_converge_retries twice.
Same value, so nothing breaks today; editing the documented one would have
silently changed nothing.
- svc-net-tor and web-app-socialhome both claimed 192.168.74.0/24. Socialhome,
the newer role, moves to 192.168.75.0/24.
- web-app-socialhome/meta/schema.yml arrived as a new file, so ef5ea7cb5's
rename never saw it. Its credential would not have resolved and the role
would have deployed with an unusable administrator account.
The incoming specs also needed this branch's conventions: raw timeouts wrapped,
four page.goto calls routed through gotoOnion, a request.get given an
onion-aware timeout, and 21 roles marked playwright-service-flag over the tor
block this branch added to them.
make quality green on the merge result.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
integration_mastodon's connect returned 401 with
'cURL error 60: unable to get local issuer certificate ... for
https://microblog.infinito.example/api/v1/apps', byte-identical across
attempt and retry. The CA plumbing the repo already injects - the CA
mount, SSL_CERT_FILE, CURL_CA_BUNDLE, php.ini curl.cainfo - cannot reach
that call: OC\Http\Client\Client pins Guzzle's VERIFY to the
certificate manager's own bundle, which defaults to the shipped
resources/config/ca-bundle.crt.
occ security:certificates:import is the only lever that reaches it.
Verified in nextcloud:34: the command is registered as
'security:certificates:import' taking a required path, and
addCertificate() calls createCertificateBundle(), which writes the merged
rootcerts.crt that getAbsoluteBundlePath() then returns. Public TLS keeps
working because the import appends to the shipped bundle. Every
integration_* app talking to an internal host over HTTPS was broken the
same way, not just Mastodon.
Registers the GitLab OAuth application with the scopes the client
actually requests: integration_gitlab/src/utils.js:26 sends
'read_user read_api read_repository', and Doorkeeper's ScopeChecker does
plain string-set containment, so 'api' does not subsume 'read_api' and
consent would have been refused. Also least privilege.
The gitlab spec sampled the URL the page settled on after GitLab's 302,
but GitLab keeps the return path in session[:user_return_to], so that URL
carries no query and the assertion looked for evidence GitLab structurally
does not provide. It now captures the authorize request itself and
additionally asserts redirect_uri points back at this Nextcloud and that
the partner answered below 400.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
New lint test_no_raw_goto.py forbids raw `page.goto(...)` in role playwright specs + persona flows (the gotoOnion wrapper in personas/utils is exempt) so navigation retries transient Tor-transport errors over onion. Migrates every raw call across ~75 roles (343 sites) to `gotoOnion(page, ...)` and teaches gotoOnion to detect relative onion URLs (`isOnionCanonical`). gotoOnion is a behaviour-identical drop-in on clearnet (single attempt, same return). Verified: no-raw-goto lint green, eslint 0 errors, make test green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Provision a GitLab Doorkeeper OAuth application for Nextcloud and wire the
credentials into the integration_gitlab app so the per-user Connect-to-GitLab
flow reaches the partner authorize endpoint.
- provision_oauth_app.rb: create/renew the Doorkeeper app (organization_id set
to satisfy the newer GitLab oauth_applications check constraint), emit
CLIENT_ID/CLIENT_SECRET
- integration_gitlab_provision.yml: run it via gitlab-rails, parse the creds,
store them with occ config:app:set --sensitive (the app stores them encrypted)
- integration_gitlab.yml: probe the partner, read persisted creds, provision
only when the partner is up and not yet coupled
- spec: drive the real per-user OAuth connect and assert the partner
/oauth/authorize carries the provisioned client_id + response_type=code
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addon specs assert the integration is genuinely wired (admin config holds the partner value, host distinct from the app), not just that a page loads. Robust to the live DOM: strict-mode-safe locators (.first()), enabled-signal from the app's own panel (not the lazy apps list), and test.skip (not fail) when an app is disabled (NC-version-incompatible) or its partner role is absent/unconfigured.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>