Files
computer-playbook/roles/web-app-matrix/templates/playwright.env.j2
kevinveenbirkenbachandClaude Opus 5.5 9b88fccfc6 fix(web-app-matrix): wire Jitsi, Element Call and Heisenbridge in the ansible flavor
An earlier commit on this branch turned the three off because the ansible flavor ran
them without a published port, proxy entry, domain or certificate. They
now stay on and are wired end to end.

Element Call: MDAD's LiveKit server and JWT service get their own
entities in meta/services.yml with resource limits, local ports and a
public media port (TCP and UDP). The runner container publishes them
through container_ports, and the Synapse vhost proxies /livekit-server/
(websocket) and /livekit-jwt-service/ to them. The JWT service checks
each OpenID token against the user's homeserver over federation, and
federation was not reachable in this flavor: Synapse served it only on
a plain-HTTP listener that the runner published directly on 8448.
Synapse now serves the client and federation resources on one listener,
OpenResty serves the Synapse vhost on 443 and as default_server on the
federation port, the direct 8448 publish is gone, and the role writes
/.well-known/matrix/server as the compose flavor does. With a
self-signed CA the JWT container mounts the CA bundle as Synapse does.

Jitsi: a new services.jitsi entity follows the shared-service contract.
It is enabled in the ansible flavor off tor nodes. When web-app-jitsi is
in the inventory, Element points at that shared Jitsi and MDAD's own
Jitsi stays off. Otherwise MDAD runs its own Jitsi on jitsi.<domain>
with a front-proxy vhost, its web port published to the runner and its
videobridge on a public UDP port. The entity lists the jitsi domain, so
the web health probe skips it whenever Matrix does not serve it. The
jitsi_*_container_network overrides were dropped: MDAD reads none of
them, Jitsi always ran on its own network. Variant 0 covers the shared
case, variant 1 the internal one. On an onion-primary deploy both call
stacks stay off, so Element never advertises a clearnet call surface.
MDAD's Prosody keeps an account's first password, so after a credential
rotation jicofo failed SASL with the new one. The role now derives the
jicofo and videobridge passwords from the macaroon secret and recreates
both accounts on every deploy.

Heisenbridge stays on by default. It runs in the nested host network,
where MDAD's container-name URLs do not resolve, so its homeserver URL
and the appservice URL in its registration point at 127.0.0.1.

A bootstrap that a previous deploy left failed (for example after a
Docker Hub rate limit) is now reset and restarted, so a mode=update
deploy converges instead of failing on the stale unit state.

Playwright proves each path: the RTC spec fetches a LiveKit token from
the JWT service and opens the SFU signalling websocket, the Jitsi spec
checks Element's preferred domain and joins a conference (signing in
through Keycloak first when the shared Jitsi sits behind SSO), and the
Heisenbridge spec opens a DM with the bot and waits for its answer to
"help".

Closes #1165

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 17:16:20 +02:00

75 lines
3.6 KiB
Bash

ADMIN_PASSWORD={{ MATRIX_ADMINISTRATOR_PASSWORD | dotenv_quote }}
ADMIN_USERNAME={{ MATRIX_ADMINISTRATOR_USERNAME | dotenv_quote }}
APP_BASE_URL={{ lookup('tls', application_id, 'url.base') | dotenv_quote }}
BIBER_PASSWORD={{ lookup('users', 'biber').password | dotenv_quote }}
BIBER_USERNAME={{ lookup('users', 'biber').username | dotenv_quote }}
BRIDGES_SERVICE_ENABLED={{ (MATRIX_BRIDGE.values() | list | select | list | length > 0) | string | lower }}
CANONICAL_DOMAIN={{ lookup('domains', application_id).element | dotenv_quote }}
ELEMENT_BASE_URL={{ lookup('canonical_url', application_id, 'element') | dotenv_quote }}
ELEMENT_CALL_SERVICE_ENABLED={{ MATRIX_CONFERENCING_ELEMENT_CALL | string | lower }}
# nocheck: playwright-service-gate — covered by sys-svc-mail integration tests, not the persona surface
EMAIL_SERVICE_ENABLED={{ lookup('config', application_id, 'services.email.enabled') | string | lower }}
JITSI_BASE_URL={{ (lookup('tls', 'web-app-jitsi', 'url.base') if MATRIX_JITSI_SHARED else lookup('canonical_url', application_id, 'jitsi')) | dotenv_quote }}
JITSI_SERVICE_ENABLED={{ MATRIX_JITSI_ENABLED | string | lower }}
JITSI_SSO_ENABLED={{ (MATRIX_JITSI_SHARED and lookup('config', 'web-app-jitsi', 'services.sso.enabled') | bool) | string | lower }}
# nocheck: playwright-service-gate — persona drives OIDC path; LDAP federation exercised in LDAP-only matrix variant
LDAP_SERVICE_ENABLED={{ lookup('config', application_id, 'services.ldap.enabled') | string | lower }}
LITELLM_SERVICE_ENABLED={{ lookup('config', application_id, 'services.litellm.enabled') | string | lower }}
# nocheck: playwright-service-gate — consumed via shared persona helpers (roles/test-e2e-playwright/files/personas/)
LOGOUT_SERVICE_ENABLED={{ lookup('config', application_id, 'services.logout.enabled') | string | lower }}
MATOMO_BASE_URL={{ lookup('tls', 'web-app-matomo', 'url.base') | dotenv_quote }}
# nocheck: playwright-service-gate — consumed via shared persona helpers (roles/test-e2e-playwright/files/personas/)
MATOMO_SERVICE_ENABLED={{ lookup('config', application_id, 'services.matomo.enabled') | string | lower }}
MATRIX_BASE_URL={{ lookup('canonical_url', application_id, 'synapse') | dotenv_quote }}
MATRIX_CHATGPT_BRIDGE_ENDPOINT={{ MATRIX_CHATGPT_BRIDGE_ENDPOINT | dotenv_quote }}
MATRIX_CHATGPT_BRIDGE_MODEL={{ MATRIX_CHATGPT_BRIDGE_MODEL | dotenv_quote }}
MATRIX_FLAVOR={{ lookup('config', application_id, 'services.matrix.flavor') | dotenv_quote }}
MATRIX_LIVEKIT_JWT_PATH={{ MATRIX_LIVEKIT_JWT_PATH | dotenv_quote }}
MATRIX_LIVEKIT_PATH={{ MATRIX_LIVEKIT_PATH | dotenv_quote }}
MATRIX_PLUGINS_JSON={{ MATRIX_BRIDGE | to_json | dotenv_quote }}
MATRIX_SERVER_NAME={{ MATRIX_SERVER_NAME | dotenv_quote }}
OIDC_ISSUER_URL={{ OIDC.CLIENT.ISSUER_URL | dotenv_quote }}
SEAWEEDFS_ADMIN_PASSWORD={{ MATRIX_ADMINISTRATOR_PASSWORD | dotenv_quote }}
SEAWEEDFS_ADMIN_USERNAME={{ MATRIX_ADMINISTRATOR_USERNAME | dotenv_quote }}
SEAWEEDFS_APP_BUCKET={{ lookup('objstore', application_id, 'bucket') | dotenv_quote }}
SEAWEEDFS_FILER_URL={{ lookup('canonical_url', 'web-app-seaweedfs', 'filer', consumer=application_id) | dotenv_quote }}
SEAWEEDFS_SERVICE_ENABLED={{ lookup('config', application_id, 'services.seaweedfs.enabled') | string | lower }}
SEAWEEDFS_FRONTEND_SERVICE_ENABLED={{ lookup('config', 'web-app-seaweedfs', 'services.frontend.enabled', false) | string | lower }}
SSO_SERVICE_ENABLED={{ lookup('config', application_id, 'services.sso.enabled') | string | lower }}
{% for bridge in MATRIX_BRIDGES | default([], true) %}
MAUTRIX_{{ bridge.bridge_name | upper | regex_replace('[^A-Z0-9]+', '_') }}_ADDON_ENABLED=true
{% endfor %}