Add tests/lint/repository/test_task_file_numbering.py: numbered task
files use exactly two leading digits, a numbered *_core.yml must be
00_core.yml, per directory the numbers are unique/consecutive and start
at 01 (00 with a core file), numbered includes appear in ascending
order, and shared helpers live in tasks/utils/ instead of the numbered
chain.
Apply it across every role: rename NN_core.yml to 00_core.yml with a
consecutive down-shift of the siblings, move letter-suffix children into
a subdirectory named after their parent task, relocate helpers included
from more than one place into tasks/utils/, and update every reference
(include_tasks, path_absolute, .ansible-lint-ignore, requirement docs).
Legacy narration comments in the touched files are deleted; the upstream
xwiki.properties reference block opts out via nocheck. The unused
MAILU_IP6_PUBLIC var (only ever named in now-removed comments) is dropped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tests/lint/repository/test_name_emoji_and_length.py: every Ansible task
name and GitHub Actions workflow/job/step name must start with an emoji (first
char not 0-9/A-Za-z) and be <= 80 chars.
- emit emoji names at the source: cli/build/include generator now writes
"🔧 setup <app>" / "🚿 flush handlers after <app>" so generated
tasks/groups/*-roles.yml satisfy the convention too
- convert existing task/step/job/workflow names to emoji-prefixed, choosing a
task-fitting icon per action (📦 install, ✅ ensure, 🔍 probe, 🥾 bootstrap,
🚀 deploy, 🧩 service-module load, ⬇️ checkout, 📂 include-routines, ...)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restructures the keycloak role so manager-side operations run on the
hosting node under both deployment models without per-task delegation
noise:
- tasks/02_manager_ops.yml: extracts the manager-side body into
02a_manager_ops_on_host.yml and includes it once with
`apply: delegate_to: KEYCLOAK_HOST_NODE`. Ansible's `apply:` keyword
propagates the delegate to every task in the included file so each
step (kcadm login, client / mail / RBAC / LDAP updates) runs on the
stack host without the inner files needing to know about it.
- tasks/04_login.yml: dual-path discovery. Swarm waits for the
keycloak service to converge via `container service ps`, resolves
the hosting node, and sets KEYCLOAK_HOST_NODE; compose sets it to
inventory_hostname (single-host model). Subsequent LOCAL_CID
resolution is now gated `when: DEPLOYMENT_MODE == 'swarm'` and
scoped to a single block; compose leaves KEYCLOAK_LOCAL_CID unset
and relies on vars/main.yml's
`KEYCLOAK_EXEC_CONTAINER: container exec -i {{ KEYCLOAK_LOCAL_CID
| default(KEYCLOAK_CONTAINER_ADDRESS) }}` fallback. Removes the
brittle inline shell-template else-branch that previously echoed
KEYCLOAK_CONTAINER for compose.
- tasks/05a_realm_import_run.yml: compose path runs the import
in-place via `compose down/up/run`; swarm path dispatches to a new
05b_realm_import_swarm.yml that scales the import service via
`container service update`, tails its logs, and rescales to 0. The
3 mode-gated tasks share a single `when:` wrapper to satisfy the
ansible-repeated-when-run lint.
- tasks/update/05_ldap_shared.yml (new): extracted from the previous
inline LDAP-shared block in the manager-ops handler so the
surrounding block stays under the >3-children limit. Combined
when-guard (KEYCLOAK_LDAP_ENABLED AND KEYCLOAK_LDAP_SHARED) lives
on the include.
- tasks/assert/05_ldap.yml: read-only assertion path; uses
KEYCLOAK_EXEC_KCADM (mode-agnostic).
- handlers/main.yml: drops the comment block that restated
`ignore_errors: true` on the sync-ldap-groups handler. The
ignore_errors + delegate_to + transient-failure semantics remain
intact; the prose was restating the directive, not naming a
trip-wire.
Verified internally coherent + compose-mode-safe via static audit:
include chain main -> 01_core -> 02_manager_ops -> 02a -> {04_login,
05_realm_import -> 05a (compose-branch) | 05b (swarm-branch),
update/{01_client, 02_mail_realm, 03_mail_master,
04_rbac_client_scope, 05_ldap_shared}, assert/05_ldap}. All
include_tasks targets resolve, all KEYCLOAK_* vars are set before
consumption, all kcadm/update/assert tasks are mode-agnostic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* scripts/lint/autoformat.sh:
- rename run_sort_claude_settings worker to run_claude (matches the
renamed scripts/lint/claude.sh).
- drop the EXIT trap that wiped status_dir; cleanup happens explicitly
after `wait` returns, so a parallel worker that interrupts the
parent never races a vanished status dir.
- each worker now captures its tool's exit code and writes one of
OK / SKIP / FAIL. Tolerated `expected violations remain`-style exits
(markdownlint-cli2 rc≤1, ansible-lint rc≤2) still count as OK; only
real failures count as FAIL.
- all workers run to completion regardless of individual tool failures
(so the user always sees the full picture); after the summary, the
script exits 1 if any worker reported FAIL.
* scripts/lint/sort_claude_settings.sh -> scripts/lint/claude.sh
(history preserved via git mv); update test_claude_settings_sorted.py
fix-hint accordingly.
Plus working-tree drift across roles/, group_vars/, inventories/,
requirements/, and .pre-commit-config.yaml accumulated from the
make-test setup phase regenerating generated artefacts during recent
test runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hard-coded self-path references rot the moment the file moves: a header
comment ``# utils/foo/bar.py`` at the top of a module, a docstring
mentioning ``utils/foo/bar.py``, or a docs entry linking
``utils/foo/bar.py`` from inside ``utils/foo/bar.py`` itself all silently
desync from reality after the next ``git mv``.
The new lint walks every project file, computes its POSIX-style relative
path from PROJECT_ROOT, and reports any line whose text contains that
path as a substring. Files at the repo root (no ``/`` in their relative
path) and setuptools-generated ``*.egg-info/`` artefacts are exempt.
Per-line opt-out via ``# nocheck: self-path-reference`` on the offending
line, registered in the suppression catalog.
Existing offenders cleaned up:
- 72 redundant ``# <self-path>`` header lines removed across roles,
cli, plugins, scripts, tests, and utils.
- 4 prometheus templates that told consumers to "update
<self-template-path>" rewritten to drop the redundant self-reference.
- 8 docstring/comment self-references in cli, plugins, tests, utils,
and the dashboard oidc.js.j2 header rewritten to describe the layout
without naming the file's own path.
- 17 legitimate usage examples (shell scripts, test data lists, one
template self-include doc-block) marked with ``nocheck:
self-path-reference``.
- ``container.sh`` heredoc usage strings switched to ``${0}`` so the
marker stays out of the user-visible help output.
- ``healthcheck/http.yml.j2`` doc-block rewritten to prose because
``{# ... #}`` Jinja comments cannot host an inner ``{# nocheck #}``
(the inner ``#}`` closes the outer comment).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces role-local `kcadm_json` filter + `module_utils/kcadm_json.py` to reliably parse kcadm output with JVM noise, and reuses it in `keycloak_kcadm_update` and LDAP/RBAC/recaptcha tasks to eliminate jq/`--query`. Also refactors LDAP groups.path handling via `include_tasks` to avoid repeated `when` conditions and adds unit tests for filter/module utils/library behavior.
https://chatgpt.com/share/69743d89-b1c0-800f-b571-90f64605dfe4
* Run LDAP assertions only when MODE_ASSERT is enabled (guarded at include level)
* Remove redundant MODE_ASSERT conditions inside assert/05_ldap.yml
* Simplify mapper-id refresh logic by relying on the surrounding block condition
https://chatgpt.com/share/694927e3-2794-800f-9bc7-749c1e32a541
- Resolve LDAP UserStorageProvider via client-side filtering (avoid unreliable kcadm --query)
- Enforce exactly one canonical 'ldap-roles' LDAP mapper per LDAP component
- Deterministically deduplicate existing ldap-roles mappers (lexicographic id order)
- Safely parse created mapper id and fallback to authoritative refresh
- Add read-only assert tasks to validate LDAP, mapper uniqueness, groups.path and top-level group
- Wire LDAP asserts into role execution when MODE_ASSERT is enabled
- Improve idempotency, robustness and CI failure diagnostics
https://chatgpt.com/share/69487ed5-3b58-800f-8ac6-bbb1bbe3688a