Commit Graph
8 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 4039313266 refactor(tasks): enforce and apply a single task-file numbering scheme
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>
2026-07-23 20:01:31 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cddb0dc59b feat(lint): require emoji-prefixed task/step/job names + convert existing
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>
2026-06-28 22:45:06 +02:00
kevinveenbirkenbachandClaude Opus 4.7 74e3a64a4d refactor(web-app-keycloak): swarm-aware host discovery + realm-import dispatch
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>
2026-06-14 19:08:47 +02:00
kevinveenbirkenbachandClaude Opus 4.7 2a023ca6a1 chore(lint): autoformat strict-failure semantics + claude.sh rename
* 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>
2026-05-09 01:30:49 +02:00
kevinveenbirkenbachandClaude Opus 4.7 d3afe0bc81 test(lint): forbid a file from referencing its own path as a string
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>
2026-05-08 03:53:44 +02:00
kevinveenbirkenbach 33a4b2a430 **feat(web-app-keycloak): add kcadm noisy-JSON helper and remove jq/--query usage**
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
2026-01-24 04:33:14 +01:00
kevinveenbirkenbach fa4ab3835c refactor(keycloak): streamline LDAP assert/update flow
* 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
2025-12-22 12:13:29 +01:00
kevinveenbirkenbach f51b53a615 feat(keycloak-ldap): enforce canonical ldap-roles mapper and add read-only asserts
- 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
2025-12-22 00:12:11 +01:00