Shorten the module name now that it backs more than just lookup plugins
(validator CLI, tests, dashboard role). Updates all 26 import sites and
adds a unit test covering the pure helpers.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add tests/lint/ansible/roles/test_web_app_email_integration.py which:
- Emits a GHA warning annotation (via utils.annotations.message) for
each web-app-* role that does not call lookup('email', application_id)
and does not carry an explicit opt-out block.
- Hard-fails when a role DOES call the email lookup but its
compose.services.email is missing enabled: true or shared: true.
- Silencer format: `# noqa: email` on the line directly above an
`email:` block under compose.services with enabled: false + shared: false.
Opt out 13 roles that have no user-facing mail surface:
bridgy-fed, chess, dashboard, littlejs, mig, mini-qr, navigator,
oauth2-proxy, phpldapadmin, phpmyadmin, roulette-wheel, sphinx, yourls.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Moves the SYSTEM_EMAIL_* resolution logic out of group_vars/all/03_email.yml
into a dedicated Ansible lookup plugin, so every role template reads outgoing
mail settings via lookup('email') (global) or lookup('email', application_id)
(per-app). Per-app compose.services.email is merged on top of the resolved
defaults; SYSTEM_EMAIL_* variables remain usable as an inventory escape hatch.
Also splits the email docs: administrator-facing configuration stays under
docs/administration/configuration/, plugin contract and extension rules move
to docs/contributing/design/services/email.md. services.md is relocated to
services/base.md so the services/ subtree can host per-service design pages.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Roles outside the web-*/svc-db-* auto-default families (notably
svc-prx-openresty) declare an explicit `server.domains.canonical` and
must register in the global domains map so `lookup('tls', ...)` can
resolve them. Previously the prefix filter silently dropped them,
causing `application_id 'svc-prx-openresty' not found in domains
mapping` once the legacy `domains` set_fact / `CURRENT_PLAY_DOMAINS`
injection was removed.
Auto-default domain generation (entity_name.DOMAIN_PRIMARY) still
applies only to web-*/svc-db-*. Defensive type checks keep malformed
non-auto-default configs from raising, matching prior behavior.
Tests updated to cover the svc-prx-openresty case and renamed to
reflect the new auto-default-prefix semantics.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
find_provider_roles now uses build_service_registry_from_roles_dir, the
same resolver the SERVICES_DISABLED pre-check uses. Previously it matched
only roles with a literal compose.services.<svc>.image entry, so services
exposed via compose.services.<entity>.provides (e.g. mailu → email) were
invisible to the init phase. The pre-check then flagged the unresolved
provider role as a conflict and aborted every fresh-purged deploy that
disabled "email".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Commit 9b5de4e47 removed the `domains` set_fact in 01_constructor.yml
and migrated only the `domain` lookup to get_merged_domains, leaving
`tls`, `cert`, `compose_file_args`, and the dashboard `docker_cards`
lookup still requiring variables['domains']. That caused
`tls_common: required variable 'domains' is missing` during the OIDC
merge task (first lookup('tls', ...) call at defaults_oidc render).
Also updates sys-svc-compose tasks/handlers so the CA-trust when-clauses
use `lookup('domains') | has_domain(application_id)` instead of the
removed top-level variable. Unit tests for the four lookups now patch
get_merged_domains to read from variables['domains'] so they stay
hermetic without touching the real roles/ tree.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Role-local lookup_plugins/ only autoloads when the role executes, but
oidc_flavor is called at config-merge time from
roles/web-app-nextcloud/config/main.yml during the 01_constructor stage.
Ansible could not resolve the lookup and failed the merge.
Relocate the plugin to plugins/lookup/ (the path declared in
ansible.cfg) so it is discovered before role execution, and move the
unit tests alongside it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a warn-only lint that scans each role's primary compose service and
emits one GitHub Actions `::warning` annotation per missing key in
(min_storage, cpus, mem_reservation, mem_limit, pids_limit). The test
fails once no annotations remain, signalling that the rule should be
flipped from warn-only to strict mode.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Loosens the Open Project URL matcher to any `https://open.project.infinito.nexus/…`
and applies the same linked-item suppression to inline TODO markers that
already applied to TODO.md list items.
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).
Fold test_include_import_exist.py (include_role / import_role target
existence) and test_tasks_existence.py (include_tasks / import_tasks
file existence) into a single test_existence.py. The two tests
previously shared setUp, YAML scan, and recursive collector shape
almost verbatim; the merged file keeps one filesystem walk and one
recursive collector parameterised over the directive keys and the
value field (name vs. file), then exposes two test methods so role
and task existence still fail independently.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Under tests/integration/roles/ introduce four sub-clusters (meta/,
dependencies/, applications/, run_once/) plus nested dependencies/run_after/
and applications/id/. Fold tests/integration/application_id/ into
roles/applications/id/ and tests/integration/run_once/ into roles/run_once/.
Pull four application-related tests out of tests/integration/ into
roles/applications/, and test_run_after_references.py into the run_after/
sub-cluster.
Consolidate tests/integration/linting/ into tests/lint/{ansible,filesystem,
repository}/, so repository-wide lint checks now run under make test-lint
rather than make test-integration.
Each new cluster ships a README.md and __init__.py; cross-referencing
READMEs (categories, ports, services, roles, applications) are updated to
point at the new paths. Path depths inside moved tests and one hardcoded
ignore path in test_domain.py are adjusted accordingly. No behavior change;
all 32 lint tests and every moved cluster pass locally.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move the existing networks test into a dedicated tests/integration/networks/
cluster (with __init__.py and README.md) and add a new integration test that
enforces: every role which defines an application_id in vars/main.yml and
ships a templates/compose.yml.j2 MUST have a dedicated subnet entry under
defaults_networks.local in group_vars/all/08_networks.yml. Close the coverage
gap by registering /28 subnets for web-app-dashboard, web-app-fider,
web-app-jenkins, web-app-mattermost, web-app-mediawiki, web-app-odoo, and
svc-prx-openresty.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move flat tests/integration/test_*.py files into thematic subfolders
(action_plugins, application_id, categories, compose, domains, filters,
handlers, jinja, linting, oauth2_oidc, passwords, ports, roles, run_once,
services, workflows), strip redundant prefixes from filenames, and
adjust path-depth references by +1 level. Add __init__.py and a scope-
focused README.md per cluster so the directory purpose is discoverable
without duplicating the integration.md SPOT. Update design/services.md
to point at the new test locations.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Resolve merge conflict in web-app-peertube/vars/main.yml; migrate
remaining `applications |` and `users.*` references to
`lookup('applications')` / `lookup('users', ...)` in web-app-odoo and
web-app-decidim (compose, env, playwright, setup tasks).
- web-app-peertube: split OIDC tasks into oidc/{enable,disable}.yml,
add install_mem_limit filter + PEERTUBE_MEM_LIMIT /
PEERTUBE_OIDC_PLUGIN_INSTALL_MEM_LIMIT vars to raise the cgroup ceiling
during the one-off `npm run plugin:install` exec (prevents OOM-SIGKILL
that was surfacing as "Container is restarting"); add
upsert-oidc-plugin.sql.j2 and diagnostics.sh.
- CI: test-deploy-{local,server,universal,workstation}.yml tweaks plus
scripts/github/{dump_runner_state,enlarge_swap}.sh for constrained
runners.
- cli/meta/applications/ressources: new CLI entry with unit tests.
- Misc config/docs updates across dashboard, mailu, mattermost, asset,
cdn, file roles and contributing docs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Resolve conflicts by migrating lookup plugins to utils.applications.config
(get_app_conf -> get) while preserving branch's runtime applications/users
lookups. Notable changes:
- plugins/lookup/{config,nginx,service}.py, roles/web-app-dashboard/
lookup_plugins/docker_cards.py: switch to utils.applications.config.get,
keep utils.runtime_lookup_data.get_merged_applications/_users.
- roles/web-app-matrix/docs/Installation.md: use lookup('config', ...)
syntax with markdown link formatting.
- scripts/tests/e2e/rerun-spec.sh: take main's single-source image tag
derivation from roles/test-e2e-playwright/defaults/main.yml.
- tests/integration/test_get_app_conf_paths.py -> test_config_lookup_paths.py:
migrate scan pattern to lookup('config', ...) and skip docs/ directory.
- tests/unit/plugins/lookup/test_config_lookup.py: union of new imports.
- tests/unit/plugins/lookup/test_cert.py: reset runtime caches in
setUp/tearDown to avoid id()-based fingerprint cross-test pollution.
- Add __init__.py in 7 test directories left behind after prior cleanup.
- Delete dead duplicate group_vars/all/{04_users,05_applications}.yml
(untracked on disk; content long migrated to roles/*/{config,users}/main.yml).
Reintroduce the conditional OIDC-plugin selection that was lost when commit
77a0e16ea removed the _applications_nextcloud_oidc_flavor helper. Ship a
role-local lookup plugin at roles/web-app-nextcloud/lookup_plugins/oidc_flavor.py
with resolution order: explicit compose.services.oidc.flavor > oidc_login if
LDAP enabled > sociallogin. Wire all consumers (plugin toggles + oidc.config.php)
through lookup('oidc_flavor') and default compose.services.oidc.flavor to "" so
the LDAP-aware default takes effect (None would trip the non-empty-config
integration guard). Add 12 unit tests covering override, LDAP on/off,
whitespace, non-string, missing-app, and input-validation paths; evict
stubbed utils.applications.config leaked by the keycloak redirect_uris test
before loading the plugin so discovery-order no longer matters. Seed missing
__init__.py in tests/unit/roles/web-app-peertube and
tests/unit/cli/meta/applications/ressources so the repo-wide init-file guard
passes again.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plugin install via `container exec` shares the cgroup with the long-running
peertube node process. Combined RSS was tripping the 8g mem_limit and
SIGKILLing peertube, which surfaced as "Container is restarting" on
subsequent exec attempts.
- Temp raise mem_limit + unlimited swap for the install window, restore
the compose-defined value on the happy path only
- Derive the bumped ceiling from PEERTUBE_MEM_LIMIT + install heap cap
via a new role-local `install_mem_limit` filter (overhead=4 covers
native RSS and spawned npm/node-gyp workers)
- Extract the SQL upsert into templates/upsert-oidc-plugin.sql.j2
- Move enable/disable OIDC tasks under tasks/oidc/ and rename the
diagnostics script
- Document the extract-code convention in docs/contributing/tools/ansible.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a container-shaped heuristic so non-shared compose.services entries
that declare neither resource fields (mem_*/pids_limit/cpus) nor
container-identifying fields (image/name/version/container) are treated
as feature flags and excluded from the resource table. Keeps the
keycloak recaptcha toggle and similar booleans out of the per-role
footprint. Adds unit coverage for the helper and recursion behavior.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a CLI that reports per-container resource budgets (mem_reservation,
mem_limit, pids_limit, cpus) for an Ansible role, recursively following
enabled shared services via the service registry. Aggregation rules:
mem_* and pids_limit are summed; cpus is MAX (shared across containers,
not additive). Includes text + JSON output, cycle protection, and unit
tests covering parsing helpers, aggregation, recursion, rendering, and
end-to-end CLI invocation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consolidates application-config helpers under utils/applications/ with a
concise public API (config.get). Updates all plugin, role, and test
imports; removes the legacy get_app_conf filter and its tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Rename 06..19 → 04..17 so the sequence is dense and gap-free.
- Update hard-coded references in cli/, tests/, and PR template.
- Add README.md describing scope, load order, and naming rules
per docs/contributing/documentation.md standards.
Treat chore/** branches like feature/fix/etc. for CI: trigger the
push pipeline on chore/** pushes and accept chore as a valid PR
branch prefix in full scope. This unblocks the chore/update-* PRs
that update.yml creates automatically, which previously failed
branch-prefix validation and never triggered the push pipeline.
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>
Replace the single docs/agents/action/debug.md with a debug/ directory
hosting three distinct workflows: local-deploy debugging, fully
automated CI pipeline triage via gh, and inspection of operator-placed
log files. Add full pipeline triage flow (enumerate failed runs and
children, classify branch-caused vs external, dedup-then-create issues
on s.infinito.nexus, iterate per role batches with APPS cap, push the
fix branch, file follow-up issues for unresolved root causes).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consolidate gh ask/deny entries via namespace-wildcard patterns, cover
compound subcommands (item-*, field-*, mark-template*), and add a lint
test that enforces ASCII-sorted permission and sandbox arrays in
.claude/settings.json.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lookups for 'service', 'service_registry', and 'applications_current_play'
always re-derive the merged applications mapping from inventory+role defaults
instead of trusting the passed kwargs, which could be shadowed or left
unrendered by nested template evaluations.
Dashboard/keycloak tests now consume the administrator password via
lookup('users','administrator').password so the rendered Playwright .env
matches the realm user provisioned by Ansible. Remove the hardcoded
DASHBOARD_KEYCLOAK_TEST_LOGIN_PASSWORD / KEYCLOAK_LOCAL_REALM_ADMIN_PASSWORD
overrides that previously masked the mismatch.
run_one.yml: drop users/applications from the template vars block. Those
entries created a shadowing context that broke nested lookup('users', ...)
inside lookup('template', ...).
utils/runtime_lookup_data: decrypt Ansible 2.19 EncryptedString values at
the lookup boundary and try templar rendering before falling back to
aggregated defaults when override mappings arrive as placeholders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5xx responses signal an upstream-side problem rather than a stale link
in this repository, so they shouldn't fail the URL reachability check.
Generalises the previous 500/503 special case to every 5xx code.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Network gate does not honor wildcards, so allowedDomains is enumerated
explicitly for every host the agent + tooling actually need. Adds
~/.cache/pip, ~/.venvs, ~/.ansible to allowWrite so the pre-commit
make test hook can install the editable package and run ansible.
Adds host shell / editor / tooling state files to .gitignore (and the
auto-generated .dockerignore mirror) so they never become part of the
working tree. Switches the dependabot coverage test to git ls-files
with an os.walk fallback that derives its skip list from the live
.gitignore, so it stays correct in container test environments
without .git/ while still ignoring untracked host artefacts.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extends _WARNING_STATUS_CODES with 418 (I'm a teapot) and 451
(Unavailable For Legal Reasons) so they no longer fail the reachability
check. Inline-documents each status code in both _OK_STATUS_CODES and
_WARNING_STATUS_CODES, and updates the module docstring and failure
message accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extends _WARNING_STATUS_CODES with 418 (I'm a teapot) and 451
(Unavailable For Legal Reasons) so they no longer fail the reachability
check. Inline-documents each status code in both _OK_STATUS_CODES and
_WARNING_STATUS_CODES, and updates the module docstring and failure
message accordingly.
Co-Authored-By: Claude Opus 4.6 <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>
- plugins/lookup/config.py: honor default by setting skip_missing_app=not strict
so lookup('config', app, path, default) returns the default when the app is
missing from the applications dict, instead of raising during early constructor
phases. Fixes 5 test-development jobs.
- roles/web-app-nextcloud/files/playwright.spec.js: replace unsupported
.toSatisfy() with a boolean check inside expect.poll() + .toBe(true).
Fixes Deploy web-app-nextcloud.
- roles/sys-svc-container/files/container.py: when the target image has no
ENTRYPOINT, inject the internal CA as a volume plus NODE_EXTRA_CA_CERTS,
SSL_CERT_FILE, REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE instead of falling
back to a plain 'docker run' without CA trust. Fixes npm
UNABLE_TO_VERIFY_LEAF_SIGNATURE inside Microsoft Playwright images for
moodle, prometheus and onlyoffice deploys.
- tests/unit/roles/sys-svc-container/files/test_container.py: cover the new
no-ENTRYPOINT CA-injection path.
Note: web-app-mini-qr 'lookup ghcr.io: no such host' is not addressed here
and likely needs a separate investigation of CoreDNS forwarding on the CI
runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds inventory consistency guard that fails fast when SERVICES_DISABLED
conflicts with an already-deployed inventory, and ensures the env var is
forwarded through the dedicated runner, development exec command, and
local test scripts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 07_admin_identities.yml: resolves LDAP-backed admin identities
for OCC calls that require the actual NC username, not the LDAP DN
- vars: add NEXTCLOUD_HPB_TURN/STUN_ACTIVE_CONFIG selecting standalone
or onboard TURN based on enabled flags; add TALK_ADMIN_URL
- config: talk container gated on spreed plugin flag
- env.j2 + playwright.env.j2: expose active TURN/STUN config and
Talk admin URL for container env and E2E tests
- playwright.spec.js: extend with Talk TURN/STUN E2E assertions
- schema: add spreed.enabled validation
- coturn compose: move relay port range before TLS block so ports are
always set regardless of TLS mode
- docs/requirements: document TURN relay requirement
- test_resolver: cover new resolution paths
Resolve conflicts:
- docs/agents/action/iteration.md: keep both new bullets (SERVICES_DISABLED
proposal + make test requirement)
- docs/contributing/design/services.md: deleted (renamed to
docs/contributing/code/services.md in this branch)
- group_vars/all/20_services.yml: keep deletion from this branch (req-001)
- tests/lint/ansible/roles/test_service_core_first_task_run_once.py:
use build_service_registry_from_roles_dir (req-001) with repo_root()
from main for robust path resolution
Fix broken relative links caused by rename and deletion of files:
- docs/contributing/design/architecture.md: services.md → ../code/services.md
- docs/contributing/design/exceptions.md: load_frontend_service.yml →
load_service.yml
- docs/requirements/001-service-registry-refactoring.md: fix paths for
unit.md, integration.md, principles.md, documentation.md, AGENTS.md
Co-Authored-By: Claude Sonnet 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>