Onion routing is transport-layer with no persona/UI surface, so tor cannot be gated from the per-persona Playwright specs. Mark the tor block with '# nocheck: playwright-service-flag' in the 60 domain roles that ship a playwright.env.j2, per test_env_services_match's documented exemption for services that legitimately cannot be Playwright-gated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each role's meta/variants.yml now pins the tor onion gate both ways so the matrix exercises it: variant 0 pins services.tor.enabled: true, every non-baseline variant pins enabled: false + shared: false (# nocheck: variants-static-override, since tor.shared is a static literal). This gives real test_coverage / test_bond_baseline coverage without the removed per-key code exemptions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Domain-serving roles reference the svc-net-tor provider via a tor: block. Consumers declare enabled (dynamic group_names gate) and shared: true (static — onion is always the shared node model, inline nocheck: dynamic-flag). The provider svc-net-tor additionally declares exclusive/primary defaults that consumers inherit via resolve_service_config unless overridden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The readiness wait and the SSO/LDAP configure step ran `container exec
{{ CHECKMK_NAME }}` with the bare compose name. Under docker stack deploy the
task container is auto-suffixed (and may sit on a worker), so the exec failed
with 'No such container: checkmk' on every retry. Resolve the hosting node and
local container id via resolve_host_cid and delegate both execs to that node;
compose keeps the bare name as a no-op.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the per-role service_replicas Jinja variable with a per-service
replicas: field in meta/services.yml. deploy.yml.j2 resolves it via
resource_filter (with entity fallback), the same path already used for
cpus/mem, so services.yml is the single source of truth for replica
overrides.
- 13 web roles migrated to per-service (or entity-level) replicas: 1
- matomo bootstrap -> replicas: 0, mastodon migrate -> replicas: 1
- minio/seaweedfs provider entries -> replicas: 1, which also pins the
central single-writer object-store providers instead of relying on the
topology default
- service_replicas removed entirely; dropped its dead reference from the
compose-structure lint allowlist and updated requirement 023 wording
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Without service_replicas the swarm deploy falls back to the topology
default of one replica per host, so three checkmk containers raced for
the same OMD site directory on the shared volume and crashlooped
(exit 2/1/137, replicas stuck at 1/3) until the converge wait failed
with 'not converged: checkmk_checkmk'.
Checkmk's container model is one container per site; scaling happens
via distributed monitoring with independent sites, never via replicas
on shared state. Mirrors web-app-jenkins and web-app-suitecrm.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sys-svc-compose already flushes compose handlers (and runs post-deploy) when the including role passes compose_handlers_flush: true. Roles that set it false and then immediately hand-roll their own meta: flush_handlers just reimplement that flush. Add an adjacency-scoped lint that catches the back-to-back form (a deferred flush with real work between the include and the flush stays legitimate and keeps false), and collapse the five offenders (checkmk, chess, jellyfin, pihole, semaphore) to compose_handlers_flush: true.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Checkmk's oauth2-proxy header-auth GUI exposes no logout control the shared
Playwright personas can reach: the classic GUI is iframe-based, its top-frame
toolbar is bare <div>/<a> (no <header>/<nav> anchor), and the native logout
hides behind the 'User' menu. So the biber and administrator personas failed at
'app -> universal logout' with 'no in-app logout control reachable'.
Add a 'javascript' service (gated on services.sso.enabled) so the platform
inlines templates/javascript.js.j2 into every Checkmk response. The script marks
a logout control with data-injected-logout (which the persona helper checks
first): it appends a themed icon to a header/nav group when one exists, else
falls back to a fixed-position top-right button on the top-frame <body>. The
control points at OIDC.CLIENT.LOGOUT_URL so a click clears both the Checkmk and
the Keycloak/oauth2-proxy session. Inline injection is admitted by Checkmk's own
CSP ('unsafe-inline'). Verified in-container before redeploy, then full-matrix
reinstall: V1 6 passed (incl. biber+admin logout), V2/V3 2 passed/4 skipped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements requirement 029: web-app-checkmk deploying checkmk/check-mk-raw
2.4.0p32 (Raw/Community) behind sys-svc-proxy. No native OIDC, so SSO uses the
platform oauth2-proxy gate + Checkmk header-auth (auth_by_http_header =
X-Remote-User, injected by the role proxy.conf.j2 from $authrequest_username =
Keycloak preferred_username), plus a native LDAP connection for user records.
No external DB. Agent receiver (8000) host-port mapped via a new
PORT_BANDS.local.agent band.
Auth/LDAP/proxy mechanisms source-verified against Checkmk v2.4.0p32
(cmk/gui/auth.py, userdb/ldap_connector.py, userdb/_connections.py) and the
infinito sso_proxy nginx chain: fixed the LDAP file path (user_connections.mk)
and directory_type ("openldap"). LDAP sync timing and classic-GUI Playwright
selectors remain live-deploy-validation items (env-blocked).
Validation: make autoformat clean; make test green (lint, test-lint, test-unit,
test-integration 190, test-external).
Refs: docs/requirements/029-web-app-checkmk.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>