Chromium never treats plaintext .onion origins as a secure context, so
keycloak-js (PKCE via crypto.subtle) could not run. A custom Playwright
browser fixture launches Firefox with the Tor-Browser prefs
(dom.securecontext.allowlist_onions, origin/mixed-content handling) for
onion targets and keeps Chromium for clearnet; all dashboard specs share
it via the register pattern.
keycloak-js is now vendored from the deployment's own CDN as an ES
module (jsdelivr is unreachable over Tor) with CORS opened on the CDN
proxy. Personas and the oidc-login spec wait for adapter readiness and
navbar settle before driving login/logout, which the async code->token
exchange needs over Tor latency.
Verified: full deploy matrix green (onion 14/14 twice, clearnet pass).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
Ignore Keycloak's third-party-cookie probe (/3p-cookies/, requestStorageAccess) in the console-error assertion — that probe errors by design when 3p cookies are blocked (always over onion) and is Keycloak feature-detection, not a dashboard fault; real dashboard console errors still fail. Fix the iframe-sync race by re-dispatching inside the poll until the CDN-loaded listener is live (over Tor it loads after DOMContentLoaded).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Seven scenario tests carried a trailing
``expectNoUnexpectedDiagnostics(diagnostics, { ignoreMatomoConsoleNoise: true })``
that overlapped the dedicated ``test-no-console-noise.js`` scenario.
The tail was both a hidden Single-Responsibility violation (each test
checked its own concern *plus* console cleanliness) and a latent
race: a test that ran long enough to see Keycloak's silent-check
iframe failure would trip on the unfiltered OIDC noise — the exact
failure that took down ``test-header-navbar-logos.js`` in CI run
26045851566.
Drop the tail from every consumer. ``test-no-console-noise.js`` is
now the sole owner of the diagnostic check (with both
``ignoreMatomoConsoleNoise`` and ``ignoreOidcSilentCheckNoise``
filters enabled), so each remaining test passes or fails for exactly
the reason its name promises.
For two of the seven (``test-iframe-sync.js`` and
``test-simpleicons-cards.js``) ``attachDiagnostics`` was only kept
around for the tail check — it goes too. The other five keep
``diagnostics`` because they still feed its ``.responses`` array to
``waitForResourceResponse``.
7 files, 16 deletions, 0 insertions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Playwright spec split
---------------------
The 747-line ``playwright.spec.js`` monolith is split into a thin
orchestrator + ``_shared.js`` (env, ``beforeEach``, common helpers) +
one ``test-*.js`` per scenario, matching the convention used by
web-app-fediwall/friendica/nextcloud. Each scenario file holds its own
specialised helpers (e.g. the auth/dropdown helpers live in
``test-oidc-login.js``, image-loaded assertions live in
``test-header-navbar-logos.js``); only helpers used by ≥ 2 tests stay
in ``_shared.js``. ``dashboard-card-flow.js`` becomes
``test-tile-reachability.js`` (git-detected rename) — the
``runDashboardCardScenario`` helper had a single consumer, so the
indirection is gone.
SPOT for branding URLs
----------------------
The ``'https:' ~ source if source.startswith('//') else source``
transformation lived inline in ``config.yaml.j2`` and was duplicated in
``playwright.env.j2`` when the logo assertion was added. Three new
SPOTs in ``vars/main.yml``:
- ``DASHBOARD_PLATFORM_LOGO_URL``
- ``DASHBOARD_PLATFORM_FAVICON_URL``
- ``DASHBOARD_COMPANY_LOGO_URL``
Both templates now reference these vars; the inline transformations
and the now-redundant ``{% set ... %}`` lines in ``config.yaml.j2``
are removed. The slurp + parse of the rendered config in
``tasks/01_core.yml`` stays because it covers the host-override case
(``DASHBOARD_CONFIG_INV_PATH`` template may use different branding),
but is now documented as the override-discovery path rather than the
default source of truth.
port-ui 2.0.0 + test alignment
------------------------------
- ``meta/services.yml``: port-ui pinned ``1.2.0 → 2.0.0`` (probe-first
asset resolver, see kevinveenbirkenbach/port-ui#2.0.0).
- ``test-header-navbar-logos.js``: drop the ``asset`` skip-gate (port-ui
>= 2.0.0 embeds the URL directly instead of producing the broken
``/static/<absolute-url>``), replace the shape regex with an
exact-match against the SPOT ``PLATFORM_LOGO_URL`` env var, and add
a favicon assertion that checks the rendered ``<link rel="icon">``
href against the SPOT ``PLATFORM_FAVICON_URL``.
- ``test-cdn-role-stylesheet.js``: keep the ``asset`` skip-gate — that
test exercises ``web-svc-cdn`` which depends on ``web-svc-asset`` as
its file backend, unrelated to the port-ui bug.
- ``playwright.env.j2``: rendered ``ASSET_SERVICE_ENABLED``,
``PLATFORM_LOGO_URL``, ``PLATFORM_FAVICON_URL``, ``COMPANY_LOGO_URL``.
- ``meta/services.yml``: drop the now-stale
``# nocheck: playwright-service-flag`` annotation on the ``asset``
service block.
.claude/settings.json
---------------------
Resort ``permissions.allow`` after the runtime appended
``WebFetch(domain:cloud.veen.world)`` at the end of the array during
the asset-resolver work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>