Commit Graph
5 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 4c91df5de7 test(e2e): forbid raw page.goto, migrate all specs to Tor-resilient gotoOnion
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>
2026-07-08 20:59:38 +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.7 3ffcc5e0ec feat(web-app-zammad): user-SPOT, LDAP source, Telegram boot shim, test fixes
User identity SPOT
- meta/users.yml gains zammad-api-bot (Basic-auth REST API bot) and
  zammad-wizard-bypass-admin (auto_wizard.json setup-bypass admin).
- vars/main.yml reads identity (login/email/firstname/lastname) via
  lookup('users', …); password stays in credentials/ to guarantee the
  shell-safe alphanumeric form needed for the Ansible→bash→docker-exec
  →Ruby ENV chain.
- auto_wizard.json.j2, apply_api_bot.rb, tasks/01_core.yml: consume the
  lookup-resolved identity.

Boot reliability
- templates/zz_telegram_constant_shim.rb.j2: pre-loaded via RUBYOPT;
  pre-declares the Telegram::Bot namespace and intercepts Kernel#require
  to refuse telegram/* loads, sidestepping the broken telegram-bot-ruby
  2.4.0 gem that crashes Zammad 6.5.0 boot. Telegram channel is inert.
- env.j2 sets RUBYOPT=-r/opt/zammad/zz_telegram_constant_shim.rb.
- tasks/01_core.yml stages the shim; compose.yml.j2 bind-mounts it into
  zammad-init/rails/websocket/scheduler/nginx.
- tasks/01_core.yml adds an explicit AutoWizard.setup post-init step
  (upstream zammad-init does NOT auto-process auto_wizard.json), which
  is what V2 (no-auth) and V3 (LDAP-only) need to skip the setup wizard.

LDAP source wire-up (TODO #1)
- files/scripts/apply_ldap_source.rb creates an LdapSource record
  pointing at svc-db-openldap (inetOrgPerson + groupOfNames mapping).
- tasks/01_core.yml runs it when services.ldap.enabled is true.

OIDC group→role mapping (TODO #3)
- templates/zz_oidc_group_role_mapping.rb.j2 patches Zammad's
  User.create_from_hash / update_from_hash to translate the RBAC
  group-path claim (e.g. /roles/web-app-zammad/administrator) into
  the matching Zammad role (Admin / Agent / Customer fallback).
- apply_oidc_settings.rb pins uid_field=preferred_username so OIDC
  matches the human-readable Keycloak username, NOT the sub UUID.
- compose.yml.j2 bind-mounts the initializer when OIDC is enabled.

Test coverage
- new test-login-via-ldap.js (driven only in LDAP-only V3).
- test-alias-domain.js accepts 2xx-direct OR 301-to-canonical
  (sys-svc-proxy renders aliases as 301 sources, not server-name
  aliases — server.yml updated to canonical=helpdesk + alias=
  zammad.helpdesk).
- test-mail-to-ticket.js: stage-level SMTP trace logging; reaches
  Mailu via host.docker.internal:465.
- test-ticket-reply-as-agent.js: scoped contenteditable lookup to
  .article-add to avoid hitting the ticket-title field.
- _shared.js: signInAsApiBot drives /api/v1/signin via the server-side
  APIRequestContext (shared cookie jar with the browser), unblocking
  the SPA-OIDC interlock.

SQL outsourcing
- templates/sql/grant_createdb.sql.j2: the CREATEDB grant now lives in
  a Jinja-templated .sql file; tasks/01_core.yml consumes it via
  lookup('template', …). Role name is rendered into the SQL by Jinja
  (NOT via database_query named_args), because psql parameter binding
  quotes string values as literals (`'zammad'`) which is invalid SQL
  for ALTER ROLE.

Misc
- meta/server.yml: canonical=helpdesk.<domain>, aliases=[zammad.helpdesk.<domain>]
  to match the 022 requirement (Decision #1).
- TODO.md drained — all seven items either landed or are explicitly
  documented as out-of-scope / brittle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 15:53:44 +02:00
kevinveenbirkenbachandClaude Opus 4.7 177f039b11 refactor(web-app-zammad): rename basic_auth_password → api_bot_password + SPOTs
- Rename credential basic_auth_password → api_bot_password and var
  ZAMMAD_ADMINISTRATOR_PASSWORD → ZAMMAD_API_BOT_PASSWORD to reflect
  that the value is the role-internal bot's local password, not the
  administrator's (reused for the wizard-bypass admin only because both
  need the same shell-safe alphanumeric form).
- Introduce ORGANIZATION constant (defaults to SOFTWARE_NAME) and migrate
  organization-string consumers (mattermost team, shopware shop title,
  dashboard login/logout descriptions, simpleicons "provided by",
  user-administrator description/lastname).
- Add HOST_LL_CC_TAG (BCP-47 form, e.g. en-gb) and use in auto_wizard.
- Add NETWORK_TRUSTED_PROXY_CIDRS SPOT and consume from suitecrm,
  shopware and zammad reverse-proxy configs.
- Extract ZAMMAD_WEB_PROTOCOL via lookup('tls', …, 'protocols.web')
  instead of inline 'https' if … else 'http'.
- Use database_query for CREATEDB grant so it works on shared+non-shared
  databases; back the SQL with files/sql/grant_createdb.sql SPOT.
- Read administrator firstname/lastname from users lookup in
  auto_wizard.json.j2 instead of hardcoding.
- Drop redundant elasticsearch: block from web-app-zammad services.yml
  (no consumer reads it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:03:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 2f52a80ece feat(web-app-zammad): expand Playwright coverage + extract bootstrap Ruby
Adds 7 new Playwright scenarios covering helpdesk-core workflows and
infrastructure regressions:

  - test-csp-headers          — CSP response + meta-tag parity
  - test-alias-domain         — server-name alias serves 2xx, not 30x
  - test-rest-api-ticket-create — POST /api/v1/tickets via Basic auth
  - test-ticket-create-as-customer — biber SPA → fill form → submit
  - test-ticket-reply-as-agent — API-seeded ticket; admin posts a reply
  - test-websocket-realtime   — open ticket; API appends article;
                                expect realtime push into the open SPA
  - test-mail-to-ticket       — raw-socket SMTP to Mailu helpdesk
                                mailbox; poll Zammad until ticket
                                appears

Auto-configures Zammad's Email channel (inbound IMAP + outbound SMTP)
against Mailu via a new post-bootstrap rails-runner step. The Ruby for
both bootstrap steps lives in standalone files and is piped through
`container exec -i ... bundle exec rails r -`; the previous wrapper
shell scripts (`apply_*.sh`) are removed in favour of inline `shell:`
calls in tasks/01_core.yml. Env vars are forwarded into the container
via `container exec -e VAR ...` so the Ruby uses `ENV.fetch` and stays
value-free / portable.

vars/main.yml grows three constants:

  - ZAMMAD_OMNIAUTH_INIT_CONTAINER_PATH — bind-mount target inside the
    container (was hard-coded four times in compose.yml.j2)
  - ZAMMAD_HELPDESK_USER / _EMAIL / _PASS — derived from the `helpdesk`
    mail-bot user provisioned via meta/users.yml
  - ZAMMAD_MAIL / ZAMMAD_EMAIL_ENABLED — derived from the central email
    lookup + the services.email gate

playwright.env.j2 grows MAIL_SMTP_HOST/PORT/USER/PASS + HELPDESK_EMAIL
for the SMTP injection in the mail-to-ticket scenario, sorted ASC per
the env-key lint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:03:15 +02:00