refactor(layout): sort shipped scripts by language and split the unit suite

Every script a role ships now lives under `files/<language>/`, and the unit
suite is split the same way: `tests/unit/python/` beside new sibling trees for
the other languages. `tests/lint/filesystem/test_role_files_layout.py` keeps it
that way; directories whose shape is dictated from outside carry a `.nocheck`
naming the constraint (Docker build contexts, WordPress mu-plugins, the Joomla
extension, Odoo addons, Playwright suites, the `files/test/test.sh` harness
that `test-e2e-cli` resolves generically).

This cannot be applied in halves. Moving a file and repointing what names it
are the same change: 14 references resolve only at deploy time, so the tree is
green either before or after, never between.

Those 14 were found by static resolution over every reference class, not by the
test suite -- a full `make quality-high` was green while all of them were
broken:

  * 7 `src:` values built from a role variable holding a bare filename
    (svc-bkp-remote-2-local, decidim, espocrm, friendica, joomla, pixelfed x2).
    The variable doubles as the destination name inside the container, so the
    language segment belongs at the call site, not in the variable.
  * `sys-service/tasks/04_base.yml` resolved every consumer's systemd script
    through `first_found(..., errors='strict')` over `files/script.{sh,py}`.
    18 roles ship exactly that and have no template fallback: the play would
    have died on each.
  * `sys-front-inj-javascript` fell back to `<role>/files/javascript.js`; the
    interface now reads `files/javascript/javascript.js`.
  * `sys-front-inj-logout/templates/head_sub.j2` built the cache-busting mtime
    path through `path_absolute(... 'files', ...)`.
  * 4 `ansible.builtin.script:` invocations naming a bare command
    (pull.py, prune.sh, set_postgres_superuser_password.sh, ganesha-serve.sh).
  * `dev-python/files/shell/install.sh` pointed at a sibling role's script.

Depth-dependent paths inside the moved trees were bumped accordingly: 59
`parents[N]` computations, 12 relative climbs, and the per-role recover CLI,
whose path `cli/administration/recover/recoverers.py` still assembled from the
pre-move location.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-08-22 01:31:09 +02:00
1 parent 6eff9d2ca1
commit 575a5a87ac
1076 files changed
+2141 -550

No files matched your search

+1 -1
View File
@@ -106,7 +106,7 @@ Every invokable role in the tested lifecycle envelope, with its upstream homepag
| [Jenkins](roles/web-app-jenkins/) | beta | Open-source automation server for CI/CD pipelines, builds, and plugin-driven deployment workflows | [🌐](https://www.jenkins.io/) [🎬](https://www.youtube.com/channel/UC5JBtmoz7ePk-33ZHimGiDQ) [🛠️](roles/web-app-jenkins/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Jitsi Meet](roles/web-app-jitsi/) | beta | Self-hosted WebRTC platform for end-to-end-encryptable video conferencing with federated authentication | [🌐](https://jitsi.org/) [🎬](https://www.youtube.com/channel/UCyXuxN-aNUpRv0juUXLyjbw) [🛠️](roles/web-app-jitsi/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Universal Logout](roles/web-svc-logout/) |
| [Joomla](roles/web-app-joomla/) | beta | Open-source content management system for building websites, intranets, and online applications without writing code | [🌐](https://www.joomla.org/) [🎬](https://www.youtube.com/user/joomla) [🛠️](roles/web-app-joomla/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [MariaDB](roles/svc-db-mariadb/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [Keycloak](roles/web-app-keycloak/) | beta | Self-hosted identity and access management platform for single sign-on, multi-factor authentication, and user federation | [🌐](https://www.keycloak.org/) [🛠️](roles/web-app-keycloak/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [Keycloak](roles/web-app-keycloak/) | beta | Self-hosted identity and access management platform for single sign-on, multi-factor authentication, and user federation | [🌐](https://www.keycloak.org/) [🛠️](roles/web-app-keycloak/README.md#quick-setup) | [Content Delivery Network](roles/web-svc-cdn/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
| [KIX](roles/web-app-kix/) | beta | Open-source ITSM and helpdesk platform (OTRS fork) for ticketing, CMDB, knowledge base, and reporting | [🌐](https://www.kixdesk.com/en/) [🎬](https://www.youtube.com/watch?v=D62emos1FQ8) [🛠️](roles/web-app-kix/README.md#quick-setup) | [Backup Docker Volumes](roles/svc-bkp-volume-2-local/), [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Mailu](roles/web-app-mailu/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [PostgreSQL](roles/svc-db-postgres/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LAM](roles/web-app-lam/) | beta | Web interface for administering LDAP directories: managing users, groups, and other directory objects | [🌐](https://www.ldap-account-manager.org/) [🛠️](roles/web-app-lam/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Dashboard](roles/web-app-dashboard/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [OpenLDAP](roles/svc-db-openldap/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/), [Universal Logout](roles/web-svc-logout/) |
| [LibreTranslate](roles/web-svc-libretranslate/) | beta | Self-hosted open-source machine translation API for translating and detecting text across languages | [🌐](https://libretranslate.com/) [🛠️](roles/web-svc-libretranslate/README.md#quick-setup) | [Corporate Design](roles/web-svc-css/), [Keycloak](roles/web-app-keycloak/), [Matomo](roles/web-app-matomo/), [Prometheus](roles/web-app-prometheus/), [Tor Onion Service](roles/svc-net-tor/) |
+1 -1
View File
@@ -1,7 +1,7 @@
# recover
Uniform recovery for the `svc-bkp-*` backup roles. One command wraps each
role's `files/recover.py` behind a single grammar and drives a full
role's `files/python/recover.py` behind a single grammar and drives a full
disaster recovery in the correct order.
## Usage
+5 -3
View File
@@ -1,7 +1,7 @@
"""Recoverer classes: one per svc-bkp-* recovery type.
Each Recoverer parses and validates its own colon-encoded ``source`` and
builds the role's ``files/recover.py`` invocation. Colon segments are
builds the role's ``files/python/recover.py`` invocation. Colon segments are
classified by shape: an ABSOLUTE path is the restore destination (replacing
a --target flag); for device a RELATIVE segment is the on-device snapshot
subpath and an all-digit ``YYYYMMDDHHMMSS`` segment is the generation to
@@ -47,7 +47,7 @@ def remote_target(target: str) -> bool:
class Recoverer(ABC):
"""One recovery type backed by a role's ``files/recover.py``."""
"""One recovery type backed by a role's ``files/python/recover.py``."""
name: str
role: str
@@ -55,7 +55,9 @@ class Recoverer(ABC):
no_backup_flag: bool = True
def script(self) -> str:
return str(PROJECT_ROOT / "roles" / self.role / "files" / "recover.py")
return str(
PROJECT_ROOT / "roles" / self.role / "files" / "python" / "recover.py"
)
@abstractmethod
def args(self, source: str, target: str) -> list[str]:
+1 -1
View File
@@ -1,6 +1,6 @@
---
# Recovery schema for `infinito administration recover`.
# One uniform command wraps each svc-bkp-* role's files/recover.py.
# One uniform command wraps each svc-bkp-* role's files/python/recover.py.
command: "recover <type> <source> <target> [--preview] [--no-safety-backup]"
target: "host to restore onto (positional label)"
+2 -2
View File
@@ -140,7 +140,7 @@ INFINITO_DNS_HOSTS_FILE=/etc/hosts
INFINITO_DNS_IP=172.30.0.53
# Repo-relative path of the docker CLI install script.
INFINITO_DOCKER_CLI_INSTALL_SCRIPT=roles/sys-svc-container/files/install-cli.sh
INFINITO_DOCKER_CLI_INSTALL_SCRIPT=roles/sys-svc-container/files/shell/install-cli.sh
# Filesystem the docker data root runs on; empty until scripts/tests/deploy/utils/filesystem/resolve.sh settles the row's kind.
INFINITO_DOCKER_FILESYSTEM=
@@ -257,7 +257,7 @@ INFINITO_PUBLISH_PORTS=true
INFINITO_PULL_POLICY=never
# Repo-relative path of the system python install script.
INFINITO_PYTHON_INSTALL_SCRIPT=roles/dev-python/files/install.sh
INFINITO_PYTHON_INSTALL_SCRIPT=roles/dev-python/files/shell/install.sh
# The compose deploy runs the recover drill between PASS 1 and PASS 2 (backup/recover verification); set `false` to skip.
INFINITO_RECOVER_DRILL=true
+1 -1
View File
@@ -13,7 +13,7 @@ For injector wiring, activation, and repository-wide behavior rules, see [Contri
## Implement
- You MUST use `templates/javascript.js.j2` when runtime values from the inventory or role variables must be rendered into the browser code.
- You MUST use `files/javascript.js` when the script is static and does not depend on templating.
- You MUST use `files/javascript/javascript.js` when the script is static and does not depend on templating.
- You MUST wait for the DOM before touching elements, and guard missing elements so unrelated pages do not break.
- You MUST keep event handlers, observers, and DOM mutations idempotent because injected scripts may run on dynamic pages or be triggered repeatedly.
- You MUST prefer stable selectors and narrow hooks over text matching or timing-based hacks.
+2 -2
View File
@@ -2,7 +2,7 @@
End-to-end flow of the backup chain and its recover counterparts. Solid
arrows run on schedule (systemd units + pull); dashed arrows are the
recover direction (`files/recover.py` of each role, enforced by
recover direction (`files/python/recover.py` of each role, enforced by
`tests/lint/ansible/roles/test_bkp_roles_have_recover.py`). The swarm
test pipeline exercises the full chain in
`scripts/tests/deploy/swarm/routine/backup/base.sh`.
@@ -65,7 +65,7 @@ underneath the replay.
Per-role recover procedures live in each role's `## Recover` README
section; `svc-bkp-remote-2-local` documents its one-way opt-out in
`files/recover.py.nocheck`.
`files/python/recover.py.nocheck`.
## Deploy-time trigger flow
+1 -1
View File
@@ -11,7 +11,7 @@ You MUST use these linting and quality tools where applicable:
You MUST apply these repo-wide rules when you add, move, or review files:
- Keep broad folders shallow when that helps readability. Direct children SHOULD stay at 12 or fewer items per folder.
- Treat structural hubs such as `roles/`, `cli/`, `tests/unit/plugins/filter`, `tests/unit/roles`, `inventories/bundles/servers`, `inventories/bundles/workstations`, `plugins/filter`, `plugins/lookup`, `group_vars/all`, and `.github/workflows` as intentional exceptions when they are used to organize the tree.
- Treat structural hubs such as `roles/`, `cli/`, `tests/unit/python/plugins/filter`, `tests/unit/python/roles`, `inventories/bundles/servers`, `inventories/bundles/workstations`, `plugins/filter`, `plugins/lookup`, `group_vars/all`, and `.github/workflows` as intentional exceptions when they are used to organize the tree.
- You SHOULD prefer smaller, more focused folders over dumping many unrelated files into one directory.
For refactoring guidance, see [Refactoring](../refactoring.md).
@@ -67,8 +67,8 @@ The placement rule is per check. The catalog "Position" column uses these labels
| `hardcoded-dns-resolver` | same or above | [test_no_hardcoded_dns_resolvers.py](../../../../tests/lint/repository/network/test_no_hardcoded_dns_resolvers.py) | Marks a line that needs a literal IP from `NETWORK_PUBLIC_DNS_RESOLVERS` where the substitution point cannot consume the variable (CoreDNS non-Jinja templates, host-bootstrap shell, doc examples). |
| `dynamic-flag` | same line OR comment block above key | [test_dynamic_flags.py](../../../../tests/integration/roles/meta/services/test_dynamic_flags.py) | Marks a `roles/*/meta/services.yml` flag whose value stays literal. Per-flag (same line) for databases. Block-level (comment block above) when both flags stay literal. |
| `native-metrics` | comment block above | [test_native_metrics_contract.py](../../../../tests/integration/roles/meta/services/prometheus/test_native_metrics_contract.py) | Marks a role whose `services.prometheus.native_metrics.enabled` and `templates/prometheus.yml.j2` presence are intentionally inconsistent. Reserved for prepared-but-default-off scrape fragments (operator opt-in). |
| `prometheus-scrape` | same or above | [test_roles_with_service.py](../../../../tests/unit/plugins/lookup/test_roles_with_service.py) | Documents a `services.prometheus.scrape: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.prometheus.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('prometheus')` drops it from `PROMETHEUS_TARGET_ROLES_JSON`. Reserved for 301-redirect-only vhosts that never serve a request through lua-resty-prometheus, so they emit no `app="<role>"` label and have no scrape target. The marker accompanies the `scrape:` data flag the lookup honors. |
| `matomo-track` | same or above | [test_roles_with_service.py](../../../../tests/unit/plugins/lookup/test_roles_with_service.py) | Documents a `services.matomo.track: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.matomo.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('matomo')` drops it from `MATOMO_TARGET_ROLES_JSON` and the matomo tracker e2e contract. Reserved for static-file (autoindex) and 301-redirect vhosts that carry no user-facing HTML page worth a `_paq` tracker. The marker accompanies the `track:` data flag the lookup honors. |
| `prometheus-scrape` | same or above | [test_roles_with_service.py](../../../../tests/unit/python/plugins/lookup/test_roles_with_service.py) | Documents a `services.prometheus.scrape: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.prometheus.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('prometheus')` drops it from `PROMETHEUS_TARGET_ROLES_JSON`. Reserved for 301-redirect-only vhosts that never serve a request through lua-resty-prometheus, so they emit no `app="<role>"` label and have no scrape target. The marker accompanies the `scrape:` data flag the lookup honors. |
| `matomo-track` | same or above | [test_roles_with_service.py](../../../../tests/unit/python/plugins/lookup/test_roles_with_service.py) | Documents a `services.matomo.track: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.matomo.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('matomo')` drops it from `MATOMO_TARGET_ROLES_JSON` and the matomo tracker e2e contract. Reserved for static-file (autoindex) and 301-redirect vhosts that carry no user-facing HTML page worth a `_paq` tracker. The marker accompanies the `track:` data flag the lookup honors. |
| `variants-static-override` | same line | [test_variants_no_static_override.py](../../../../tests/integration/roles/meta/services/test_variants_no_static_override.py) | Allows a `roles/*/meta/variants.yml` leaf override of an attribute whose base value in `meta/services.yml` is a static literal. Place on the override line in `variants.yml`. Use only when the consumer chain is provably immune to the variant-merge propagation gap; the default is to make the base value dynamic via `"{{ '<role>' in group_names }}"`. |
| `variants-shared-false-once` | same or above | [test_variants_shared_false_once.py](../../../../tests/lint/ansible/services/test_variants_shared_false_once.py) | Exempts one `roles/*/meta/variants.yml` `services.<key>.shared: false` pin from the one-local-provider-variant limit for a service whose base `meta/services.yml` uses literal `enabled: true` and dynamic `shared`. Place on the extra `shared: false` line or service key line. Place above the service key in `meta/services.yml` to exempt the service. |
| `variants-services-match` | same or above | [test_services_match.py](../../../../tests/integration/roles/meta/variants/test_services_match.py) | Allows a `roles/*/meta/variants.yml` `services.<key>` entry to reference a service key that is NOT declared as a top-level entry in `meta/services.yml`. Reserved for resolver-only matrix hooks (typically on invokable infrastructure roles) whose variant entries pin the round's companion topology via service-key flags the resolver maps to provider roles, with no real consumer contract in the base meta. |
+1 -1
View File
@@ -7,7 +7,7 @@ Run unit tests with `make test-unit`.
- You MUST use Python `unittest` as the test framework.
- Tests MUST live under `tests/unit/`.
- Mirror the source tree: a file at `plugins/lookup/service.py` gets its tests at `tests/unit/plugins/lookup/test_service.py`.
- Mirror the source tree: a file at `plugins/lookup/service.py` gets its tests at `tests/unit/python/plugins/lookup/test_service.py`.
## Requirements 📋
@@ -69,7 +69,7 @@ applications:
|---|---|
| [applications.py](../../../../../../plugins/lookup/applications.py) | Runtime entry point for the `applications` lookup. |
| [applications.py (cache)](../../../../../../utils/cache/applications.py) | Shared aggregation helper that builds and caches defaults (`get_application_defaults`, `get_variants`, `get_merged_applications`). |
| [test_applications.py](../../../../../../tests/unit/plugins/lookup/test_applications.py) | Unit tests covering the full-dict, single-entry, override, strict missing, and non-strict missing cases. |
| [test_applications.py](../../../../../../tests/unit/python/plugins/lookup/test_applications.py) | Unit tests covering the full-dict, single-entry, override, strict missing, and non-strict missing cases. |
For the related users pattern see [users.md](users.md).
For the per-role matrix-variant list that backs `applications` when more than one shape exists, see [variants.md](../../../../design/variants.md) (deploy-time mechanism) and [variants.md](../../role/variants.md) (file format).
@@ -82,6 +82,6 @@ users:
|---|---|
| [users.py](../../../../../../plugins/lookup/users.py) | Runtime entry point for the `users` lookup. |
| [users/ (cache)](../../../../../../utils/cache/users/) | Shared aggregation helper package that builds and caches defaults, handles reserved users, UID/GID allocation, and uniqueness validation. Placeholder substitution (DOMAIN_PRIMARY / ORGANIZATION / SOFTWARE_NAME) lives in [users/placeholders.py](../../../../../../utils/cache/users/placeholders.py). |
| [test_users.py](../../../../../../tests/unit/plugins/lookup/test_users.py) | Unit tests covering the full-dict, single-entry, override, strict missing, and non-strict missing cases. |
| [test_users.py](../../../../../../tests/unit/python/plugins/lookup/test_users.py) | Unit tests covering the full-dict, single-entry, override, strict missing, and non-strict missing cases. |
For the related applications pattern see [applications.md](applications.md).
@@ -7,10 +7,10 @@ For browser-side validation requirements after visible behavior changes, see [Pl
## `javascript.js.j2` ⚙️
- `sys-front-inj-javascript` loads `templates/javascript.js.j2` when it exists and otherwise falls back to `files/javascript.js`.
- `sys-front-inj-javascript` loads `templates/javascript.js.j2` when it exists and otherwise falls back to `files/javascript/javascript.js`.
- The injector runs when `services.javascript.enabled` is enabled.
- The loaded script is collapsed into a one-liner before injection and added to the CSP hash list so inline execution remains consistent with the generated policy.
- You MUST use `javascript.js.j2` when the script depends on role variables or inventory values, and use `files/javascript.js` when the script is static.
- You MUST use `javascript.js.j2` when the script depends on role variables or inventory values, and use `files/javascript/javascript.js` when the script is static.
## Inventory 📋
@@ -83,7 +83,7 @@ This declares two variants. Variant 0 pins every dynamic service-key from `meta/
2. Make sure variant 0 pins every dynamic service-key from `meta/services.yml` to `enabled: true, shared: true`.
3. Append a list entry for the new variant. For every dynamic service-key variant 0 enables, the new entry MUST either keep it on (re-pin `enabled: true, shared: true`) or explicitly disable it (`enabled: false, shared: false`). Add the variant-specific overrides that justify the new entry.
4. If the new variant relies on cleanup steps that the standard inter-round entity purge does not cover, extend the role's purge handling. The matrix wrapper invokes the standard purge between rounds for every app whose variant changed.
5. Add or extend the deep-merge edge-case tests in [test_variants.py](../../../../../tests/unit/utils/cache/test_variants.py) when the new variant exercises behaviour beyond the existing fixtures (for example list replacement vs. nested scalar override).
5. Add or extend the deep-merge edge-case tests in [test_variants.py](../../../../../tests/unit/python/utils/cache/test_variants.py) when the new variant exercises behaviour beyond the existing fixtures (for example list replacement vs. nested scalar override).
## What Not To Do 🚫
@@ -220,8 +220,8 @@ The `lookup('database', ...)` API is the convenience accessor for database conne
| [load_service.yml](../../../../../roles/sys-service-loader/tasks/load_service.yml) | Per-service load helper used by the central service loader |
| [01_constructor.yml](../../../../../tasks/stages/01_constructor.yml) | Calls the service loader during constructor |
| [load/app.yml](../../../../../tasks/utils/load/app.yml) | Run-once role loader |
| [test_service_registry.py](../../../../../tests/unit/utils/roles/applications/services/test_registry.py) | Unit tests for discovery, buckets, and `run_after` ordering |
| [test_service.py](../../../../../tests/unit/plugins/lookup/test_service.py) | Unit tests for `lookup('service', ...)` |
| [test_service_registry.py](../../../../../tests/unit/python/utils/roles/applications/services/test_registry.py) | Unit tests for discovery, buckets, and `run_after` ordering |
| [test_service.py](../../../../../tests/unit/python/plugins/lookup/test_service.py) | Unit tests for `lookup('service', ...)` |
| [test_resolvable.py](../../../../../tests/integration/infrastructure/services/test_resolvable.py) | Integration checks for discovered service resolution |
| [test_canonical.py](../../../../../tests/integration/infrastructure/services/test_canonical.py) | Canonical alias consistency checks |
| [test_transitive_dependencies.py](../../../../../tests/integration/infrastructure/services/test_transitive_dependencies.py) | Integration coverage for transitive dependency resolution |
@@ -6,7 +6,7 @@ For administrator-facing configuration (keys, override variables, precedence), s
Primary files:
- [email.py](../../../../../plugins/lookup/email.py) for the plugin.
- [test_email.py](../../../../../tests/unit/plugins/lookup/test_email.py) for unit tests.
- [test_email.py](../../../../../tests/unit/python/plugins/lookup/test_email.py) for unit tests.
## Call Shapes 📞
+3 -3
View File
@@ -66,9 +66,9 @@ Apps without a `meta/variants.yml` file collapse to a single empty overlay in `_
| [init.py](../../../cli/administration/deploy/development/init.py) | Dev CLI entry that drives `build_dev_inventory_matrix` to materialise `<inventory-dir>-<round>` folders. |
| [deploy/cli.py](../../../cli/administration/deploy/development/deploy/cli.py) | Dev CLI entry that re-derives the matrix plan and iterates one deploy per folder, with per-app cleanup between rounds. |
| [entity.sh](../../../scripts/tests/deploy/local/purge/entity.sh) | Cleanup script invoked between rounds for every app in the previous round's include set. |
| [test_variants.py](../../../tests/unit/utils/cache/test_variants.py) | Unit tests covering parser edge cases, deep-merge semantics, caching, and the variant-zero default path. |
| [tests/.../inventory/](../../../tests/unit/cli/administration/deploy/development/inventory/__init__.py) | Unit-test package mirroring the source split: [`test_spec.py`](../../../tests/unit/cli/administration/deploy/development/inventory/test_spec.py), [`test_payload.py`](../../../tests/unit/cli/administration/deploy/development/inventory/test_payload.py), [`test_planner.py`](../../../tests/unit/cli/administration/deploy/development/inventory/test_planner.py), [`test_builder.py`](../../../tests/unit/cli/administration/deploy/development/inventory/test_builder.py). |
| [test_matrix_deploy.py](../../../tests/unit/cli/administration/deploy/development/test_matrix_deploy.py) | Wrapper-level tests covering the per-round folder iteration and cleanup logic. |
| [test_variants.py](../../../tests/unit/python/utils/cache/test_variants.py) | Unit tests covering parser edge cases, deep-merge semantics, caching, and the variant-zero default path. |
| [tests/.../inventory/](../../../tests/unit/python/cli/administration/deploy/development/inventory/__init__.py) | Unit-test package mirroring the source split: [`test_spec.py`](../../../tests/unit/python/cli/administration/deploy/development/inventory/test_spec.py), [`test_payload.py`](../../../tests/unit/python/cli/administration/deploy/development/inventory/test_payload.py), [`test_planner.py`](../../../tests/unit/python/cli/administration/deploy/development/inventory/test_planner.py), [`test_builder.py`](../../../tests/unit/python/cli/administration/deploy/development/inventory/test_builder.py). |
| [test_matrix_deploy.py](../../../tests/unit/python/cli/administration/deploy/development/test_matrix_deploy.py) | Wrapper-level tests covering the per-round folder iteration and cleanup logic. |
| [cli.py (provision)](../../../cli/administration/inventory/provision/cli.py) | Parses `--app-variants <JSON>` and forwards the per-app variant index to `generate_credentials_for_roles`. |
| [credentials_generator.py](../../../cli/administration/inventory/provision/credentials_generator.py) | Issues one credentials subprocess per app, appending `--variant <N>` when the app's variant is set. |
| [credentials/](../../../cli/administration/inventory/credentials/__main__.py) | `InventoryManager`-backed credential generator; `--variant N` selects which `variants.yml` overlay applies. |
+3 -3
View File
@@ -78,7 +78,7 @@ The HTTPS-only inner-build gap requires per-image CA-trust bootstrap, which is o
## Compose Wrapper Auto-Detection 🪄
The runner's `compose` wrapper at [roles/sys-svc-compose/files/compose.py](../../../roles/sys-svc-compose/files/compose.py) auto-detects compose files when invoked from per-app directories under `/opt/compose/<app>/`:
The runner's `compose` wrapper at [roles/sys-svc-compose/files/python/compose.py](../../../roles/sys-svc-compose/files/python/compose.py) auto-detects compose files when invoked from per-app directories under `/opt/compose/<app>/`:
| File | When |
|---|---|
@@ -87,7 +87,7 @@ The runner's `compose` wrapper at [roles/sys-svc-compose/files/compose.py](../..
| `compose.ca.override.yml` | when present (TLS self-signed CA-inject runs) |
| `compose.cache.override.yml` | generated on the fly when `INFINITO_CACHE_PACKAGE_FRONTEND_IP` is set; emits `build.extra_hosts` for every service that has a `build:` key |
[pull.py](../../../roles/sys-svc-compose/files/pull.py) delegates to the same wrapper so `pull` and `build --pull` operations see the identical `-f` set.
[pull.py](../../../roles/sys-svc-compose/files/python/pull.py) delegates to the same wrapper so `pull` and `build --pull` operations see the identical `-f` set.
## Environment Variables 🌳
@@ -119,7 +119,7 @@ When a new package manager or upstream needs caching:
2. If the upstream uses HTTPS, add it to `HOSTNAMES` in [package-frontend-certs.sh](../../../scripts/docker/cache/package-frontend/certs.sh) so a leaf cert is issued.
3. Add a server-block in [upstreams.conf](../../../compose/package-cache-frontend/upstreams.conf) that reverse-proxies onto the new Nexus repo path (rewrite if upstream URL prefix differs from the Nexus repo path).
4. Add an `extra_hosts` entry on the `infinito` service in [compose/cache.override.yml](../../../compose/cache.override.yml) for runner-side traffic.
5. If the upstream is HTTP-only and inner-`dockerd` builds need it, also add it to `_CACHE_HTTP_HOSTNAMES` in [compose.py](../../../roles/sys-svc-compose/files/compose.py) so the per-app `compose.cache.override.yml` includes it in `build.extra_hosts`.
5. If the upstream is HTTP-only and inner-`dockerd` builds need it, also add it to `_CACHE_HTTP_HOSTNAMES` in [compose.py](../../../roles/sys-svc-compose/files/python/compose.py) so the per-app `compose.cache.override.yml` includes it in `build.extra_hosts`.
## Background 📚
+1 -1
View File
@@ -11,7 +11,7 @@ module.exports = [
"**/__pycache__/**",
// Jinja2-templated JS — not valid JS until rendered.
"roles/*/templates/**/*.js",
"roles/web-app-bigbluebutton/files/ep_redis_publisher_index.js",
"roles/web-app-bigbluebutton/files/javascript/ep_redis_publisher_index.js",
],
},
{
+1 -1
View File
@@ -22,7 +22,7 @@ Requires: openssh-clients
#
# EL9 AppStream exposes only python3.9 via the generic python3 capability.
# In those environments we still bootstrap Python 3.11+ separately via
# roles/dev-python/files/install.sh, but the RPM metadata must remain
# roles/dev-python/files/shell/install.sh, but the RPM metadata must remain
# installable from the stock distro repositories.
%if 0%{?rhel} == 9
Requires: python3
+3 -3
View File
@@ -194,8 +194,8 @@ ignore = [
# ``patch.object(sut, "os")`` replacements). Converting these call
# sites to ``pathlib.Path`` would require rewriting every coupled
# test in lockstep — out of scope for the use-pathlib pass.
"roles/sys-ctl-rpr-container-hard/files/script.py" = ["PTH"]
"roles/sys-ctl-rpr-container-soft/files/script.py" = ["PTH"]
"roles/sys-ctl-rpr-container-hard/files/python/script.py" = ["PTH"]
"roles/sys-ctl-rpr-container-soft/files/python/script.py" = ["PTH"]
# BLE001 (flake8-blind-except) ratchet.
# Broad `except Exception:` is now selected project-wide so NEW code is
@@ -264,7 +264,7 @@ ignore = [
"cli/administration/deploy/development/deploy.py" = ["N806"]
"cli/administration/deploy/development/init.py" = ["N806"]
"cli/administration/deploy/development/inventory.py" = ["N806"]
"tests/unit/cli/administration/deploy/development/test_inventory.py" = ["N806"]
"tests/unit/python/cli/administration/deploy/development/test_inventory.py" = ["N806"]
# Lazy-loaded class binding: ``ValueGenerator = _value_generator_cls()``
# rebinds the imported class inside the function. PEP 8 keeps the
@@ -91,7 +91,7 @@
- name: 🗑️ Optionally drop shell snippet for Nix
ansible.builtin.script:
cmd: >-
{{ role_path }}/files/write_nix_shell_snippet.sh
{{ role_path }}/files/shell/write_nix_shell_snippet.sh
{{ dev_nix_shell_snippet_path | quote }}
register: dev_nix_shell_snippet_result
changed_when: >
@@ -105,7 +105,7 @@
- name: 🧹 Aggressively prune Nix data (GC + optimise)
become: true
ansible.builtin.script: >
aggressive_prune_nix.sh
shell/aggressive_prune_nix.sh
{{ dev_nix_binary_path | quote }}
changed_when: true
when:
@@ -6,7 +6,7 @@
- name: 🧹 Purge stale nixbld users blocking the multi-user installer
ansible.builtin.script:
cmd: "{{ role_path }}/files/purge_stale_nixbld.sh"
cmd: "{{ role_path }}/files/shell/purge_stale_nixbld.sh"
register: dev_nix_purge_stale_nixbld_result
changed_when: >
dev_nix_purge_stale_nixbld_result.stdout is search('\\[CHANGED\\]')
+1 -1
View File
@@ -1,7 +1,7 @@
---
- name: 🧹 Purge stale nixbld users blocking the multi-user installer
ansible.builtin.script:
cmd: "{{ role_path }}/files/purge_stale_nixbld.sh"
cmd: "{{ role_path }}/files/shell/purge_stale_nixbld.sh"
register: dev_nix_purge_stale_nixbld_result
changed_when: >
dev_nix_purge_stale_nixbld_result.stdout is search('\\[CHANGED\\]')
@@ -24,8 +24,8 @@ fi
. /etc/os-release
ID_LIKE="${ID_LIKE:-}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
DOCKER_APT_SANITIZER="${REPO_ROOT}/roles/sys-svc-container/files/apt_repo.sh"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
DOCKER_APT_SANITIZER="${REPO_ROOT}/roles/sys-svc-container/files/shell/apt_repo.sh"
log() {
printf '>>> [dev-python] %s\n' "$*"
+1 -1
View File
@@ -5,7 +5,7 @@
when: run_once_sys_pip is not defined
- name: 📦 Install and prefer Python 3.11+ as default
ansible.builtin.script: "{{ role_path }}/files/install.sh"
ansible.builtin.script: "{{ role_path }}/files/shell/install.sh"
environment:
SKIP_DOCKER_APT_SANITIZER: "1"
become: true
+1 -1
View File
@@ -90,7 +90,7 @@ infinito administration deploy dedicated "$INVENTORY/devices.yml" \
## Recover
Run `files/recover.py` on the host with the backup device attached:
Run `files/python/recover.py` on the host with the backup device attached:
```
recover.py /dev/sdX1 /mnt/usb-recover /var/lib/infinito/backup [--snapshot <timestamp>]
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
# nocheck: mirrored-unit-test - subclasses utils.recovery.base and is exercised
# collectively by tests/unit/python/utils/recovery/test_role_recover_scripts.py; a
# per-role copy would assert the base class twice over
"""Restore the local backup root from the encrypted backup device.
Opens the LUKS device (interactive passphrase prompt, or stdin with
@@ -25,7 +28,7 @@ import subprocess
import sys
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parents[3] # nocheck: project-root-import
_REPO_ROOT = Path(__file__).resolve().parents[4] # nocheck: project-root-import
sys.path.insert(0, str(_REPO_ROOT))
from utils.recovery.base import DirectoryRecovery # noqa: E402
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
# nocheck: mirrored-unit-test - main() is one straight line of rsync and mount
# subprocess calls against an attached backup device; every branch it has is a return
# code from the host, so the assertions would only restate the mocks
import datetime
import glob
+1 -1
View File
@@ -97,7 +97,7 @@ infinito administration deploy dedicated "$INVENTORY/devices.yml" \
## Recover
Run `files/recover.py` on the host that serves the NFS export:
Run `files/python/recover.py` on the host that serves the NFS export:
```
recover.py <backups>/<machine-hash>/backup-nfs-to-local/<generation>/files/<state>/<volume> <export-base>/<state>/<volume>
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
# nocheck: mirrored-unit-test - subclasses utils.recovery.base and is exercised
# collectively by tests/unit/python/utils/recovery/test_role_recover_scripts.py; a
# per-role copy would assert the base class twice over
"""Restore an NFS export subtree from a backup snapshot.
Runs the role's deployed backup unit first (the usual differential
@@ -17,7 +20,7 @@ import argparse
import sys
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parents[3] # nocheck: project-root-import
_REPO_ROOT = Path(__file__).resolve().parents[4] # nocheck: project-root-import
sys.path.insert(0, str(_REPO_ROOT))
from utils.recovery.base import DirectoryRecovery # noqa: E402
+1 -1
View File
@@ -92,7 +92,7 @@ infinito administration deploy dedicated "$INVENTORY/devices.yml" \
## Recover
This role's direction is one-way by design (`files/recover.py.nocheck`): it pulls provider backups onto this host, so the pulled tree under `<backups>/<machine-hash>/<repo>/<generation>/` IS the recovery store and there is no live target here to restore into.
This role's direction is one-way by design (`files/python/recover.py.nocheck`): it pulls provider backups onto this host, so the pulled tree under `<backups>/<machine-hash>/<repo>/<generation>/` IS the recovery store and there is no live target here to restore into.
To recover a source system, transfer the wanted generation to it (the provider's `backup` user only whitelists pull commands, so pushing requires an explicit operator rsync with a root-capable target) and run the matching role's `recover.py` there (`svc-bkp-volume-2-local` for docker volumes, `svc-bkp-nfs-2-local` for NFS exports).
@@ -19,7 +19,7 @@
- name: "🚀 Deploy '{{ DOCKER_BACKUP_REMOTE_2_LOCAL_SCRIPT }}'"
copy:
src: "{{ DOCKER_BACKUP_REMOTE_2_LOCAL_FILE }}"
src: "python/{{ DOCKER_BACKUP_REMOTE_2_LOCAL_FILE }}"
dest: "{{ DOCKER_BACKUP_REMOTE_2_LOCAL_SCRIPT }}"
mode: "0755"
+1 -1
View File
@@ -108,7 +108,7 @@ infinito administration deploy dedicated "$INVENTORY/devices.yml" \
## Recover
Run `files/recover.py` on the target host:
Run `files/python/recover.py` on the target host:
```
recover.py <backups>/<machine-hash>/backup-secrets-to-local/<generation>/files [--restore-node-identity]
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
# nocheck: mirrored-unit-test - subclasses utils.recovery.base and is exercised
# collectively by tests/unit/python/utils/recovery/test_role_recover_scripts.py; a
# per-role copy would assert the base class twice over
"""Restore host-generated secret material from a backup snapshot.
Runs the role's deployed backup unit first (a fresh differential
@@ -24,7 +27,7 @@ import shutil
import sys
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parents[3] # nocheck: project-root-import
_REPO_ROOT = Path(__file__).resolve().parents[4] # nocheck: project-root-import
sys.path.insert(0, str(_REPO_ROOT))
from utils.paths import DIR_SECRETS # noqa: E402
+2 -2
View File
@@ -75,7 +75,7 @@ flowchart TD
BAUDOLO --> CHECK3B["DR drill [3b]<br>newest backup-docker-to-local generation<br>must be fresh + non-empty<br>(catches over-exclusion)"]
EXPORT["svc-bkp-nfs-2-local<br>on the export host<br>rsyncs the export tree"] --> TREE["backup-nfs-to-local/&lt;generation&gt;<br>the single capture"]
BAUDOLO -.->|"no second copy<br>through the mount"| TREE
TREE --> RECOVER["files/recover.py volume<br>resolves Mountpoint + Options"]
TREE --> RECOVER["files/python/recover.py volume<br>resolves Mountpoint + Options"]
RECOVER -->|"Options set"| PROBE{"mountpoint -q<br>(ssh for --docker-host)"}
PROBE -->|unmounted| REFUSE["SystemExit: a restore would land<br>on the node disk and be shadowed<br>on the next mount"]
PROBE -->|mounted| RSYNC["rsync -a --delete through the<br>mounted export onto the server"]
@@ -296,7 +296,7 @@ credentials live in the target host's own `databases.csv`.
### A single volume
Run `files/recover.py` on the backed-up host to restore one volume's files:
Run `files/python/recover.py` on the backed-up host to restore one volume's files:
```
recover.py <backups>/<machine-hash>/backup-docker-to-local/<generation>/<volume>/files <volume>
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
# nocheck: mirrored-unit-test - subclasses utils.recovery.base and is exercised
# collectively by tests/unit/python/utils/recovery/test_role_recover_scripts.py; a
# per-role copy would assert the base class twice over
"""Restore a backup-docker-to-local generation: a volume's files, or the
generation's database dumps.
@@ -26,7 +29,7 @@ import subprocess
import sys
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parents[3] # nocheck: project-root-import
_REPO_ROOT = Path(__file__).resolve().parents[4] # nocheck: project-root-import
sys.path.insert(0, str(_REPO_ROOT))
from utils.paths import FILE_DATABASE_SECRETS # noqa: E402
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
@@ -32,7 +32,7 @@ through the recover chain, require the marker and every recorded container
back, and finally let the host's own container health service judge.
That last step is deliberately the deployed
[`sys-ctl-hlth-container` script](../../../sys-ctl-hlth-container/files/script.sh)
[`sys-ctl-hlth-container` script](../../../sys-ctl-hlth-container/files/shell/script.sh)
rather than a check of the drill's own: it is what watches the host in
production, it knows swarm services, and it dumps 200 log lines per sick
container. It is invoked as a script, not as its systemd unit — the unit's
+1
View File
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
+2 -2
View File
@@ -18,8 +18,8 @@
dest: "{{ [ lookup('container', application_id, 'directories.instance'), item.dest ] | path_join }}"
mode: "{{ item.mode }}"
loop:
- { src: "entrypoint.sh", dest: "entrypoint.sh", mode: "0755" }
- { src: "healthcheck.sh", dest: "healthcheck.sh", mode: "0755" }
- { src: "shell/entrypoint.sh", dest: "entrypoint.sh", mode: "0755" }
- { src: "shell/healthcheck.sh", dest: "healthcheck.sh", mode: "0755" }
loop_control:
label: "{{ item.dest }}"
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
+1 -1
View File
@@ -42,7 +42,7 @@
- name: "✅ POSTGRES | Ensure postgres superuser password matches inventory"
ansible.builtin.script: > # nocheck: container-address-quote script evals the fragment itself
set_postgres_superuser_password.sh {{ POSTGRES_CONTAINER_ADDRESS | quote }} {{ POSTGRES_PASSWORD | quote }}
shell/set_postgres_superuser_password.sh {{ POSTGRES_CONTAINER_ADDRESS | quote }} {{ POSTGRES_PASSWORD | quote }}
register: postgres_pw_result
delegate_to: "{{ STACK_HOST }}"
run_once: true
+1 -1
View File
@@ -36,7 +36,7 @@
rescue:
- name: "💾 Postgres | Dump pg_hba.conf into the diagnostics folder" # nocheck: rescue-extra-diagnostics pg_hba.conf is postgres-specific auth config the generic rescue script cannot capture, and it is what a failed TCP-auth wait needs
ansible.builtin.script: "{{ lookup('path_absolute', 'roles/svc-db-postgres/files/dump_pg_hba.sh') }}"
ansible.builtin.script: "{{ lookup('path_absolute', 'roles/svc-db-postgres/files/shell/dump_pg_hba.sh') }}"
environment:
POSTGRES_CONTAINER_ADDRESS: "{{ POSTGRES_LOCAL_CID }}"
PGPASSWORD: "{{ POSTGRES_PASSWORD }}"
@@ -20,7 +20,7 @@ RUN rm -rf /var/lib/apt/lists/* \
{% endif %}
COPY <<'BOOT_ENTRYPOINT_EOF' /usr/local/bin/boot-entrypoint.sh
{{ lookup('file', lookup('path_absolute', 'roles/svc-db-postgres/files/boot-entrypoint.sh')) }}
{{ lookup('file', lookup('path_absolute', 'roles/svc-db-postgres/files/shell/boot-entrypoint.sh')) }}
BOOT_ENTRYPOINT_EOF
RUN chmod +x /usr/local/bin/boot-entrypoint.sh
+1
View File
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
+1 -1
View File
@@ -68,7 +68,7 @@
- name: "🚀 Stage the Tor container entrypoint into the build context"
stack_host_copy:
src: "{{ role_path }}/files/entrypoint.sh"
src: "{{ role_path }}/files/shell/entrypoint.sh"
dest: "{{ TOR_ENTRYPOINT_HOST }}"
mode: "0755"
become: true
+1 -1
View File
@@ -1,7 +1,7 @@
---
- name: "⏳ Wait until the node onion answers internally (loopback fast path)"
ansible.builtin.script:
cmd: "{{ role_path }}/files/onion_self_reach.py {{ TOR_NODE_ONION }}"
cmd: "{{ role_path }}/files/python/onion_self_reach.py {{ TOR_NODE_ONION }}"
register: _tor_self_reach
retries: 90
delay: 5
@@ -1,3 +1,6 @@
# nocheck: mirrored-unit-test - orchestrates docker stop/start around an rsync move
# between disks; its helpers read live container state through docker inspect and a unit
# test would pin the mock, not the migration
import argparse
import shutil
import subprocess
+1
View File
@@ -0,0 +1 @@
# nocheck: role-files-layout - Role test harness with test.sh as its entry point; grouped by purpose, screened and kept on 2026-08-21.
+1 -1
View File
@@ -15,7 +15,7 @@
- name: 📄 Copy entrypoint to build context
ansible.builtin.copy: # nocheck: stack-host-consumer (include is IS_STACK_HOST-gated)
src: entrypoint.sh
src: shell/entrypoint.sh
dest: "{{ RUNNER_INSTALL_DIR }}/build/entrypoint.sh"
mode: "0755"
+1 -1
View File
@@ -66,7 +66,7 @@
- name: "🔍 Detect {{ DIR_VAR_LIB }} pre-mount state"
ansible.builtin.script:
cmd: "{{ role_path }}/files/premount_state.sh"
cmd: "{{ role_path }}/files/shell/premount_state.sh"
executable: /bin/bash
environment:
DIR_VAR_LIB: "{{ DIR_VAR_LIB }}"
@@ -1,7 +1,7 @@
---
- name: "🔍 Detect controller {{ DIR_VAR_LIB }} pre-mount state"
ansible.builtin.script:
cmd: "{{ lookup('path_absolute', 'roles/svc-storage-nfs-client/files/premount_state.sh') }}"
cmd: "{{ lookup('path_absolute', 'roles/svc-storage-nfs-client/files/shell/premount_state.sh') }}"
executable: /bin/bash
environment:
DIR_VAR_LIB: "{{ DIR_VAR_LIB }}"
+1 -1
View File
@@ -18,7 +18,7 @@ SVC_STORAGE_NFS_SERVER_STATE_ALLOWED_CIDRS:
- "*"
SVC_STORAGE_NFS_SERVER_GANESHA_SERVE: >-
ganesha-serve.sh
shell/ganesha-serve.sh
{{ SVC_STORAGE_NFS_SERVER_SERVICE['ganesha'][ansible_facts['os_family']] | quote }}
2049
{{ lookup('timeout', 120) | int }}
+1 -1
View File
@@ -90,7 +90,7 @@
- name: "📦 CA | install trust helper script (SPOT) on host"
become: true
ansible.builtin.copy:
src: "with-ca-trust.sh"
src: "shell/with-ca-trust.sh"
dest: "{{ BIN_CA_TRUST }}"
owner: root
group: root
+1 -1
View File
@@ -1,7 +1,7 @@
---
- name: "🧹 Cleanup caches and logs (cross-distro: arch/debian/ubuntu/fedora/centos)"
become: true
ansible.builtin.script: cleanup_caches.sh
ansible.builtin.script: shell/cleanup_caches.sh
changed_when: true
- name: 🧹 Cleanup journald logs (CI/container only)
@@ -6,7 +6,7 @@
javascript_file_custom: >-
{{ (application_id | abs_role_path_by_application_id ~ '/templates/javascript.js.j2')
if lookup('fileglob', application_id | abs_role_path_by_application_id ~ '/templates/javascript.js.j2')
else application_id | abs_role_path_by_application_id ~ '/files/javascript.js' }}
else application_id | abs_role_path_by_application_id ~ '/files/javascript/javascript.js' }}
- name: "📄 Load JavaScript code for '{{ application_id }}'"
set_fact:
@@ -1,6 +1,6 @@
---
- name: 🚀 Deploy logout.js
copy:
src: logout.js
src: javascript/logout.js
dest: "{{ INJ_LOGOUT_JS_DESTINATION }}"
mode: "0644"
@@ -1 +1 @@
<script src="{{ lookup('cdn', 'web-svc-cdn').urls.shared.js }}/{{ INJ_LOGOUT_JS_FILE_NAME }}{{ lookup('local_mtime_qs', lookup('path_absolute', 'roles', 'sys-front-inj-logout', 'files', INJ_LOGOUT_JS_FILE_NAME)) }}"></script>
<script src="{{ lookup('cdn', 'web-svc-cdn').urls.shared.js }}/{{ INJ_LOGOUT_JS_FILE_NAME }}{{ lookup('local_mtime_qs', lookup('path_absolute', 'roles', 'sys-front-inj-logout', 'files', 'javascript', INJ_LOGOUT_JS_FILE_NAME)) }}"></script>
File renamed without changes.
+1 -1
View File
@@ -2,7 +2,7 @@
- block:
- name: 📁 create {{ BIN_LOCK }}
copy:
src: sys-lock.py
src: python/sys-lock.py
dest: "{{ BIN_LOCK }}"
mode: "0755"
File renamed without changes.
Loaded 100 of 1076 files, more files were not shown because too many files have changed in this diff. Show more