The Playwright E2E gate previously fired through `MODE_CI`, a boolean
that OR-ed three env-var markers (`GITHUB_ACTIONS`, `ACT`,
`INFINITO_MAKE_DEPLOY`) AND-ed with an `INFINITO_SKIP_E2E` opt-out.
That mechanism duplicated information `RUNTIME` already carries:
- `make deploy-*` already bakes `RUNTIME=dev` into the inventory at
init time (`RUNTIME_VARS_JSON='{"RUNTIME":"dev"}'`).
- CI runners (act / GitHub Actions) detect `RUNTIME=act|github` from
their canonical env markers via `cli.meta.runtime.detect_runtime`
during init.
- A bare `ansible-playbook` from a production shell stays at the
default `RUNTIME=host`.
Switching the gate to `RUNTIME in ['dev', 'act', 'github']` therefore
covers every case `MODE_CI` covered, AND folds the gate into the
single existing runtime SoT rather than maintaining a parallel one.
Changes:
- `tasks/stages/02_server.yml` E2E include now keys on `RUNTIME`.
- `group_vars/all/01_modes.yml` drops the `MODE_CI` block; a short
note explains the retirement.
- `scripts/meta/env/ci.sh` deleted (it only existed to export
`INFINITO_MAKE_DEPLOY=1`).
- The 5 `scripts/tests/deploy/local/deploy/*.sh` entry-points stop
sourcing `ci.sh`.
- `cli/deploy/development/deploy.py` no longer forwards the four
retired env markers into the container; the runtime decision is
already serialised into the inventory the deploy stage consumes.
- `scripts/tests/deploy/local/deploy/reuse-kept-app.sh` drops the
same four `-e` flags from its `docker exec`.
- `docs/requirements/006-playwright-service-gated-tests.md` gets a
prepended "MODE_CI retired" update note; the historical sections
remain for context but the dead `ci.sh` link target was reduced to
inline code.
Behaviour: any runtime where E2E was fired before still fires it now,
and the previous opt-outs have a single replacement: pass
`RUNTIME=host` (or `--vars '{"RUNTIME":"host"}'`) to skip Playwright on
a deploy that would otherwise have run it.
Implements requirements 005, 006, and 007.
005: per-application Keycloak `group-ldap-mapper`s anchor each app's
role groups under `/roles/<application_id>/<role_name>` (and, for
tenant-aware apps, `/roles/<application_id>/<tenant>/<role_name>`).
The flat-CN LDAP layout keeps each CN globally unique so Keycloak's
group-tree resolver never collides; per-app mappers use the LDAP
`description` as the visible Keycloak group name to keep the path
free of redundant prefixes. Migration purges legacy pre-005 entries
and forces a Keycloak `logout-all` so stale tokens drop pre-005
group paths.
006: per-service `<SERVICE>_SERVICE_ENABLED` env flags and the
`service-gating.js` helper let role specs `skipUnlessServiceEnabled`
cleanly when a shared service is missing or `SERVICES_DISABLED` is
set; `MODE_CI` markers (`INFINITO_MAKE_DEPLOY`, `GITHUB_ACTIONS`,
`ACT`) propagate through the deploy CLI into the test stage.
007: WordPress->Discourse round-trip Playwright scenario gated on the
`web-app-discourse` deployment.
WordPress Playwright runs 5/5 green on the single-site flow; the
multisite + Discourse scenarios are correctly skipped when their
service prerequisites are absent. The `rbac_group_path` lookup is the
single sanctioned producer for OIDC group paths and is wired into
every consumer (yourls, lam, minio, openwebui, pgadmin, phpldapadmin,
phpmyadmin, prometheus, xwiki).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per-app domain overrides belong in `applications.<app>.server.domains` and flow through the regular applications-merge pipeline. Removes the parallel `variables['domains']` recursive-combine path from the constructor stage, the domain/domains lookup plugins, and get_merged_domains(). The svc-prx-openresty canonical entry is already registered in canonical_domains_map, so the inline combine in 01_constructor.yml is redundant.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Removes the placeholder interpreter (utils/dict_renderer.py) in favor of
standard {{ lookup('config', ...) }} / {{ lookup('domain', ...) }} calls
inside role configs, and eliminates the `domains` set_fact stage in
tasks/stages/01_constructor.yml by introducing a cached get_merged_domains
helper plus a new `domains` lookup plugin (full map + by-app subtree).
The `domain` lookup no longer depends on a pre-computed `domains` variable;
it delegates to get_merged_domains, which respects inventory-level overrides
from both `applications:` (authoritative canonical source) and `domains:`
(direct override map). Caching mirrors the applications pipeline — keyed on
(roles_dir, variables signature, override fingerprint) with a re-entry guard.
Replaced `{{ domains[app_id] }}` / `{{ domains }}` usages across web-app-matrix,
-bluesky, -mastodon, -peertube, -keycloak, test-e2e-playwright, and
group_vars. Added two performance tests for lookup('domains') mirroring the
applications cache assertions (≥50x warm-to-hot ratio, 120s cold budget).
The removal in 918c49add had no practical effect on matomo's resolution
path (role-vars `domain: "{{ lookup('domain', application_id) }}"` was
already honored via include_tasks vars `application_id: 'web-app-matomo'`),
but other roles rely on these two vars being set at include_role level.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Speed up per-play lookups that previously re-read YAML and re-templated
against a cold Templar on every invocation:
- applications_current_play: cache the rendered applications map keyed
on the current play's identity so the 28+ plugin install calls reuse
one resolved result.
- runtime_lookup_data / load_app: memoize the raw applications load and
reuse it from the templar path instead of rereading group_vars.
- templating: merge caller-supplied variables onto templar's existing
available_variables (keeping ansible_facts / hostvars visible) and
tag the input with TrustedAsTemplate so Ansible 2.19+ actually
renders {{ ... }} instead of returning it unchanged.
Tests: add integration perf test + unit regression guarding the
available_variables merge restores prev state after the call.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces inline `applications`/`users` merging with dedicated lookup
plugins and runtime hydration. Introduces `add_csp_hash` filter,
integrates sort into `find_dock_val_by_bkp_entr`, splits the Keycloak
one-shot realm import into `05a_realm_import_run.yml`, and fixes the
Mastodon administrator task YAML. Removes obsolete `csp_hashes` filter,
`sys-token-store` Jinja filter, and empty CLI setup modules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete group_vars/all/20_services.yml; all service metadata now lives
in each role's config/main.yml under compose.services.<name>
- Rename generic 'database' service key to explicit 'mariadb'/'postgres'
across all app roles; remove legacy type: field
- Add utils/service_registry.py and plugins/lookup/service_registry.py
as the single source of truth for service discovery
- Add utils/database_service.py to centralize DB service resolution
- Delete service_load_enabled filter and service_should_load lookup;
replaced by service lookup plugin
- Update sys-utils-service-loader to run in constructor stage and use
generic load_service.yml; remove load_frontend_service.yml
- Add _service_loader_preloading guard to sys-svc-compose,
sys-svc-webserver-core and sys-ctl-alm-compose to prevent
health-checks/alarms from firing during preload phase
- Replace manual load_app.yml calls for shared DB/Mailu with assert-
based preload validation in sys-svc-rdbms and sys-svc-mail
- Update networks.yml.j2 templates to resolve LDAP/AI networks via
service_registry instead of hardcoded role names
- Migrate all tests to new service discovery API; delete obsolete tests
- Update docs/contributing/code/services.md to reflect role-local model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unbound failed on laptop deployments because DOCKER_IN_CONTAINER was never
materialized as an Ansible fact, and root-hints/forward-zone were gated on it.
Remove the DinD-specific forward-zone block and make root-hints unconditional
so DNSSEC iterative resolution works on bare-metal hosts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts the shared frontend service loader from sys-front-inj-all into
tasks/utils/load_services.yml and tasks/utils/_load_frontend_service.yml,
called once from tasks/stages/02_server.yml before web-svc and web-app
roles. This decouples service loading from per-app injection and makes
load order explicit via SERVICE_REGISTRY entry order. Updates docs,
comments, and adds an integration test enforcing the new SPOT.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Migrates large parts of the legacy util-* role structure to inventory-driven
bundles and standardizes AUR installation via central system roles.
- Adds `web-svc-legal`, `web-svc-asset`, and `web-app-dashboard` to all server bundles.
- Removes `util-srv-corporate-identity` entirely.
- Introduces new workstation bundle inventories:
`admin`, `admin-network`, `browser`, `design`, `dev-*`, `game-*`, `office`.
- Uses bundle variables `SYS_PACKAGES` and `SYS_AUR_PACKAGES` as the primary
installation mechanism.
- Removes/replaces obsolete util-desk/util-dev roles where fully covered.
- Renames dev roles:
`util-desk-dev-core` -> `dev-core`,
`util-desk-dev-python` -> `dev-python`,
`util-desk-dev-arduino` -> `dev-arduino`.
- Adds missing `application_id` vars for renamed roles.
- Removes the entire `util` section from `roles/categories.yml`.
- Replaces direct `kewlfft.aur.aur` calls in desktop/driver roles with
a centralized wrapper role.
- Introduces new role `sys-aur-install` as AUR installation wrapper.
- Migrates `dev-yay` to `sys-aur` and adds `SYS_AUR_PACKAGES: []` default.
- Extends constructor stage:
auto-load `sys-package` when `SYS_PACKAGES` is set,
and `sys-aur` + `sys-aur-install` when `SYS_AUR_PACKAGES` is set.
- Cleans up stage loading:
removes util-srv from `02_server.yml`,
reduces workstation loading to `desk-roles.yml` + `drv-non-free`.
- Updates integration/unit tests for the new invokable and include behavior.
- Integration test now accepts static `include_tasks` references.
- Fixes recursion risk between `sys-aur` and `sys-aur-install` by setting
`run_once_sys_aur` at the beginning of `sys-aur/tasks/01_core.yml`.
BREAKING CHANGE:
- `util-*` categories and bundle paths are no longer part of stage loading.
- Multiple `util-desk-*`, `util-dev-*`, and `util-srv-*` roles were removed.
- Deployment groups must be migrated to the new bundle/role naming.
* replace implicit modules with ansible.builtin.* for consistency
* normalize redirect domain sources and targets to avoid string slicing issues
* wrap domain lookups in list before flatten/first to prevent single-character truncation
* materialize CURRENT_PLAY_DOMAINS before generate_all_domains to eliminate _AnsibleLazyTemplateList errors
* minor whitespace and formatting cleanup for improved readability
https://chatgpt.com/share/698de3f8-2d50-800f-ab99-edcce4f0734a
* ensure source and target domains are flattened and cast to string
* prevent _AnsibleLazyTemplateList from being used as dict keys in items2dict
* stabilize generate_all_domains execution for redirect mappings
* switch to ansible.builtin.set_fact for consistency
https://chatgpt.com/share/698de3f8-2d50-800f-ab99-edcce4f0734a
* flatten DOMAIN_PRIMARY before merging into CURRENT_PLAY_DOMAINS
* convert lazy template values to plain strings to avoid unhashable type errors
* fix generate_all_domains failure caused by nested _AnsibleLazyTemplateList
https://chatgpt.com/share/698de3f8-2d50-800f-ab99-edcce4f0734a
* explicitly merge DOMAIN_PRIMARY as canonical domain for svc-prx-openresty into CURRENT_PLAY_DOMAINS
* prevents tls lookup failures when rendering default_server.conf.j2
* stabilize domain mapping for webserver + OpenResty bootstrap phase
* normalize ansible.builtin.set_fact usage in constructor stage
* minor whitespace alignment in WEBSERVER_CPUS_EFFECTIVE
https://chatgpt.com/share/698de3f8-2d50-800f-ab99-edcce4f0734a
* add SOFTWARE_DOMAIN derived from SOFTWARE_NAME lowercased
* introduce DOMAIN_HOMEPAGE defaulting to dashboard domain if present, otherwise SOFTWARE_DOMAIN
* add automatic primary → homepage redirect mapping in constructor
* migrate TLS and CA paths from SOFTWARE_NAME|lower to SOFTWARE_DOMAIN
* update systemd unit suffix and timer/service discovery globs to SOFTWARE_DOMAIN
* switch OIDC default realm and client id to SOFTWARE_DOMAIN
* adjust SuiteCRM well-known software name to SOFTWARE_DOMAIN
* update unit tests to use SOFTWARE_DOMAIN for strict Jinja expansion
https://chatgpt.com/share/698db094-22bc-800f-8454-10d97f817659
Universal roles are now covered exclusively by the constructor and destructor
stages, removing the universal stage execution to prevent duplicate role
invocations and redundant lifecycle handling.
https://chatgpt.com/share/698bcad1-d964-800f-8e23-2ac459da8c34
- Introduce database_consumer_id_passed to avoid fact/vars collisions
- Explicitly pass consumer context into svc-db-postgres via include_role
- Strengthen context assertion in postgres init tasks
- Move once-flag include to the beginning of postgres core tasks
- Make POSTGRES_EXEC_SHELL non-interactive by injecting PGPASSWORD
- Improve test coverage to detect facts overridden by include-time vars
https://chatgpt.com/share/69833e56-93a0-800f-8e3d-d970cf87daef
- Rename sys-service-runner to sys-service-terminator
- Add deploy-wide timer lockdown using SOFTWARE_NAME-based unit matching
- Mask timers and stop services during deploy, unmask and re-enable timers at finalization
- Ensure deterministic end-of-deploy service execution with diagnostics
https://chatgpt.com/share/697e595b-f378-800f-9f2b-5c5f416c2981
cert_plan now strictly renders Jinja-containing path variables (e.g. TLS_SELFSIGNED_BASE_PATH / LETSENCRYPT_LIVE_PATH) using hostvars context and fails fast if markers remain. Add unit tests covering successful expansion, hostvars precedence, and hard-fail behavior when variables are missing or Jinja leaks through. Include SOFTWARE_NAME in constructor debug output for easier runtime inspection.
https://chatgpt.com/share/697b73c6-f5f8-800f-96cc-e360a137e7a7
with explicit per-application TLS resolution.
Key changes:
- Introduce sys-front-tls-layer as the single TLS abstraction
- Centralize certificate paths via TLS_CERT_FILE / TLS_KEY_FILE / TLS_CA_FILE
- Replace sys-svc-letsencrypt SSL templates with generic TLS layer includes
- Add tls_* Jinja filters (enabled, mode, protocol, port, websocket)
- Resolve TLS mode per application (letsencrypt | self_signed | off)
- Remove implicit defaults and WEB_* globals to fail fast on misconfiguration
- Support self-signed certificates with SAN awareness
- Make TLS behavior explicit and consistent across all roles
This decouples application logic from certificate providers and
allows switching TLS flavor without touching app roles.
https://chatgpt.com/share/69727c61-8e68-800f-a267-473a7e627978
- Force PYTHON=python3 for test-local-init to avoid missing venv python
- Rename test-local-inventory-init-all target to test-local-init
- Fix JSON quoting for --vars in local deploy scripts
- Add RUNTIME default to group_vars
- Improve debug output for initial host vars
- Update user hint in local run script
https://chatgpt.com/share/697222e1-5edc-800f-b9ab-511d8afc3142
Introduce reusable test-e2e-cypress role that:
- auto-discovers application roles providing tests/cypress/env.j2
- stages per-role Cypress projects into /tmp
- renders .env from env.j2 with application context
- optionally waits for application readiness (HTTP 200/302)
- runs Cypress in a pinned Docker image with stable browser settings
- collects failures and fails the play at the end
- stores per-role reports and artifacts
Designed as a test-agnostic execution framework.
Each application role owns its Cypress project and specs.
https://chatgpt.com/share/696d4ad5-740c-800f-904d-84c6fff83e3c
Add a defensive assertion in svc-db-postgres init to ensure application_id scope
is not polluted by upstream loaders.
Also normalize load_app debug output formatting and add a no-op hardening step
to make variable intent explicit for future scope-guarding refactors.
https://chatgpt.com/share/696ce9ee-68ac-800f-9ea0-d73c285af9a8
- add optional debug output for application context
- extract database and oauth2 enable checks into role vars
- use normalized flags in task conditions
- fix typo in load_app task log message
https://chatgpt.com/share/696cbc91-cef8-800f-acfd-9cef34e28b0b
- move sys-token-store initialization to constructor stage
- remove duplicate token store includes from frontend and app roles
- allow Mailu reachability check to accept configurable status codes (200, 301)
- make Mailu health check consistent with web-app-mailu config
- increase test-local-rapid verbosity for better diagnostics
https://chatgpt.com/share/696c0f49-7888-800f-8175-fb21893c0d67
Introduce a new sys-cleanup role to perform cross-distro cleanup (apt, pacman,
dnf, yum, language caches, temp dirs and journald) for CI/container environments.
Add aggressive Docker prune handler (system + buildx + builder + log truncate)
to prevent GitHub Actions images from growing uncontrollably.
Integrate Nix garbage collection and store optimisation for CI runs.
Cleanup is guarded by MODE_CLEANUP and DOCKER_IN_CONTAINER to ensure it never
runs on real production hosts.
https://chatgpt.com/share/6967ad99-8e50-800f-b4e9-4cd8e45c29bc
- Rename CI workflow and MODE from "rest" to "universal"
- Extend CLI and test runner to support universal deploy type
- Add tasks/stages/02_universal.yml for universal host type
- Update discover logic to use universal app selection
- Remove legacy rest->server mapping and obsolete select helper
https://chatgpt.com/share/6967625e-81c8-800f-8592-5d5b8edec1e2