Commit Graph
30 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 192470cf2e fix(sys-front-inj-matomo): treat a 200 error-dict as API-not-ready instead of crashing
Matomo can answer SitesManager queries with HTTP 200 carrying an error dict ({"result":"error",...}) instead of the expected site array; indexing site_check.json[0] then crashed the deploy of every app with tracking enabled (decidim). Route the mapping shape into the existing API-not-ready deferral, keeping the array path untouched. A dict passes Jinja's sequence test, so is mapping is the only reliable discriminator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 17:30:36 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6cddce1db0 style(meta): normalize YAML indentation and wrap long scalar
Autoformat (mbake/yamllint) re-indented sequence items under their mapping key
across the regenerated meta files and wrapped one long URL scalar in the matomo
inject task. Whitespace/formatting only, no semantic change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 20:36:57 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bd0c70af17 feat(matomo): configurable tracking scope (sub default / root)
Add a per-deployment Matomo tracking scope, defaulting to per-subdomain:

- services.matomo.tracking.scope 'sub' (default) registers one Matomo site per
  consumer subdomain with an isolated cookie; 'root' keeps the prior behaviour
  of one shared site per registrable base domain with cross-subdomain linking.
- sys-front-inj-matomo derives matomo_site_domain (full host vs registrable
  base) and the shared matomo_site_url from it; getSitesId / addSite and the
  tracking snippet (setCookieDomain / setDomains / enableCrossDomainLinking) all
  follow the scope.
- The matomo Playwright env emits MATOMO_TRACKING_SCOPE; the SitesManager test
  matches the consumer's full host in 'sub' and its base domain in 'root'.
- variants.yml variant 0 sets scope=root so the matrix exercises both flavours
  (every other deploy runs the sub default).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 17:32:51 +02:00
kevinveenbirkenbachandClaude Opus 4.8 18cf9b9ada fix(matomo): inject tracker into web-svc consumers on swarm re-injection
The matomo bootstrap re-injects early-rendered web-svc consumers (such as
web-svc-logout) after obtaining the admin token, but in swarm this never ran:
roles_with_service filters by the manager's group_names, which omits
worker-placed web-svc services, so the re-injection loop was empty and the
logout page shipped without the matomo tracker.

- roles_with_service: add a scope kwarg; scope='all' bypasses the per-host
  group_names filter (the merged applications config is already
  deployment-scoped, so iterating all of it equals the deployment's consumers).
- 05_bootstrap: enumerate consumers with scope='all', stat each compose project
  dir, and re-inject only deployed ones. Avoids a fatal chdir into an undeployed
  consumer's missing /opt/compose/<entity>/ that scope='all' would otherwise hit.
- sys-front-inj-matomo: resolve matomo_effective_token (override else
  lookup('users')); the disable-gate and the SitesManager getSitesId/addSite
  calls use it, so the re-injection passes the fresh bootstrap token and bypasses
  the play-start-stale controller-side users cache that left matomo disabled.

scope defaults to 'host' and the override defaults to empty, so every existing
caller and the per-consumer injection path are unchanged. Validated green in
both compose and swarm round 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 16:37:56 +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.8 b579d36a3b fix(sys-front-inj-matomo): degrade when Matomo returns a non-JSON 200
site_check treated any HTTP 200 as a usable API and included inject_apply, which dereferences site_check.json. When Matomo answers 200 with an HTML body (e.g. its installer page during a provider/consumer ordering window) the result has no .json attribute and the play crashes ('dict has no attribute json'). Require site_check.json to be defined for the register/inject path and degrade (disable the snippet, reapply later) otherwise, completing the best-effort degrade contract.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:29:38 +02:00
kevinveenbirkenbachandClaude Opus 4.8 f73c072739 fix(sys-front-inj-matomo): degrade gracefully when Matomo is unreachable
sys-stk-front-proxy applies injections before it deploys the vhost, and in swarm a tracking consumer can be provisioned before Matomo serves its own vhost (provider/consumer ordering). Probing Matomo therefore must not hard-fail the whole deploy: probe with failed_when false, and when Matomo is not reachable disable the Matomo snippet for that domain and continue (reapplied on a later pass once Matomo is up). The site-registration and tracking-injection body is moved to inject_apply.yml, included only when Matomo answers 200, so the reachable path is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 23:35:25 +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 951f6d36d2 chore(lint): unify autoformat/galaxy parallelism into one PARALLEL env var
* scripts/lint/autoformat.sh: rename AUTOFORMAT_PARALLEL to PARALLEL,
  declare it at file start with default `true`; still env-overridable.
  Reword the worker comment so the literal `# shellcheck` token no
  longer appears at start-of-line and trips SC1072/SC1073.
* scripts/lint/galaxy.sh: drop the GALAXY_FATAL / GALAXY_NAMESPACE /
  GALAXY_PARALLEL env vars (over-engineered for a single repo). Failure
  is always fatal. NAMESPACE is an internal constant. Add the same
  PARALLEL env var (default `true`, env-overridable); falsy demotes the
  xargs fan-out to one worker.
* docs/contributing/environment/variables.md: collapse the four
  AUTOFORMAT_*/GALAXY_* rows into one `PARALLEL` row covering both
  consumers.
* docs/contributing/tools/make.md: refer to `PARALLEL=0` everywhere;
  add the lint-galaxy parallelism note.

Plus working-tree drift across roles/, group_vars/, inventories/, and
tasks/ that 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 00:59:24 +02:00
kevinveenbirkenbach 837d0c5335 test(suppression): unify # noqa / # nocheck marker grammar
Introduce a single grammar for per-line, per-block, and per-file
suppression markers across the test suite, replacing seven ad-hoc
syntaxes that had drifted apart.

Helper
  utils/annotations/suppress.py exposes is_suppressed_at,
  is_suppressed_in_head, is_suppressed_anywhere, line_has_rule, and
  suppressed_line_numbers. Markers may use either `noqa` or `nocheck`
  (case-insensitive synonyms), live inside `#`, `//`, `{# ... #}`, or
  `<\!-- ... -->` comments, and combine multiple kebab-case rules
  comma-separated. 17 unit tests cover the grammar in isolation.

Refactored consumers
  - tests/external/repository/test_urls_reachable.py (rule: url)
  - tests/external/docker/test_image_versions.py via
    utils/docker/version_updater.py (rule: docker-version)
  - tests/lint/repository/test_no_direct_yaml_calls.py (rule:
    direct-yaml)
  - tests/lint/ansible/test_service_shared_consistency.py (rule:
    shared)
  - tests/lint/ansible/roles/test_web_app_email_integration.py (rule:
    email)
  - tests/lint/repository/test_python_file_size.py (rule: file-size)
  - tests/lint/ansible/test_run_once_tags.py +
    tests/integration/roles/run_once/test_schema.py (rules: run-once,
    run-once-suffix)

Marker migration
  12 role tasks/main.yml files: `# run_once_<key>: deactivated`
  -> `# nocheck: run-once`. roles/web-app-suitecrm/meta/services.yml
  drops a malformed inline `noqa: intentional legacy pin` from a TODO
  comment so the new parser does not pick it up as a stray rule.

Caching wins
  Test files that previously loaded YAML / read files via raw
  yaml.safe_load + Path.read_text now route through utils.cache.yaml
  (load_yaml_any / load_yaml_str) and utils.cache.files.read_text:
    - test_service_shared_consistency.py
    - test_web_app_email_integration.py
    - tests/integration/roles/run_once/test_schema.py
    - utils/docker/version_updater.py
  This both speeds up repeated reads and stays consistent with the
  direct-yaml lint policy.

Documentation
  New SPOT page at docs/contributing/actions/testing/suppression.md
  with grammar, position semantics, the catalog of rules, examples,
  and an "adding a new rule" checklist. lint.md and external.md drop
  their per-rule tables and link to the new page. All touched docs
  conform to docs/contributing/documentation.md (no em-dash thought
  breaks, no SPOT self-labels, RFC-2119 keywords used consistently).

Settings sort tooling
  scripts/lint/sort_claude_settings.sh wraps utils/claude/settings_sort.py
  and is wired into scripts/lint/autoformat.sh. The tooling fixes the
  ASCII-ascending requirement enforced by
  tests/lint/repository/test_claude_settings_sorted.py; the test's
  failure message now points operators at the script. .claude/settings.json
  is committed in sorted form.
2026-04-30 11:54:46 +02:00
kevinveenbirkenbachandClaude Opus 4.6 b70a783423 refactor(lookups): migrate to runtime applications/users lookups
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>
2026-04-15 23:44:19 +02:00
Environment TestandClaude Sonnet 4.6 83262816a3 docs(contributing): apply documentation.md rules across all staged files
- Move emojis after headline text (CONTRIBUTING.md, actions/, design/, tools/, tests/)
- Replace em dashes with colons, semicolons, or complete sentences throughout
- Add missing emojis to all headlines in exceptions.md, principles.md, services.md, shell.md, setup.md, pull-request.md, commit.md, act.md, docker.md, pr/README.md
- Update H1 titles to reflect renamed directories (actions/, design/)
- Fix broken relative links in workflow.md after directory moves
- Fix full-path link texts in services.md (style.css.md, javascript.js.md)
- Fix broken principles.md link to lint.md after testing/ → actions/testing/ move

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 21:06:17 +02:00
kevinveenbirkenbachandClaude Sonnet 4.6 9eab315577 fix(matomo): disable inj_enabled.matomo when token unavailable, remove redundant CDN task
Sets inj_enabled.matomo=false when the Matomo token is empty so the NGINX
template skips body/head snippets and avoids 'matomo_site_id is undefined'.
Removes the explicit CDN load task — CDN is now covered by the generic
frontend service loader in 01_services.yml (loaded only when needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 11:33:57 +02:00
kevinveenbirkenbachandClaude Sonnet 4.6 33eebcae7c fix(matomo): skip injection gracefully when token is not yet available
Splits injection logic into inject.yml and guards execution via main.yml
when the Matomo API token is empty (e.g. first deployment or bootstrap not
yet run). Documents the exception and its retry behaviour in
docs/contributing/code/exceptions.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 10:00:40 +02:00
kevinveenbirkenbach c6f5fdea15 refactor plugins layout and migrate uri calls to uri_retry 2026-03-19 01:41:07 +01:00
kevinveenbirkenbach 3bb8c0ce30 refactor(tls): rename tls_resolve lookup to tls
The TLS lookup has been renamed from `tls_resolve` to `tls` to better
reflect its responsibility as a strict TLS state resolver.

This refactor updates all usages across the codebase, including:
- lookup plugins and internal helpers
- roles, vars, tasks, and templates
- tests, stubs, and error messages
- documentation and changelog references

Behavior, lookup API, and semantics remain unchanged.

https://chatgpt.com/share/6985e635-5a94-800f-b794-937e566ee308
2026-02-06 14:01:32 +01:00
kevinveenbirkenbach 8fe6b92e63 refactor(lookups): migrate nginx_paths, tls_resolve and cert_plan to strict positional want-path API
- Replace legacy want= keyword usage with mandatory positional want-path
- Align all nginx_paths, tls_resolve and cert_plan lookups to strict API
- Keep behavior unchanged while enforcing consistent lookup semantics

https://chatgpt.com/share/6985d642-b40c-800f-9cdf-ed54fc484a92
2026-02-06 13:06:09 +01:00
kevinveenbirkenbach 0b9f71463c refactor(tls): replace legacy tls filters with strict tls_resolve lookup
- Remove deprecated filter_plugins/tls.py and all dependent filters
- Introduce strict lookup plugin lookup_plugins/tls_resolve.py as single TLS authority
- Migrate all roles, templates, vars, and tasks to use tls_resolve (protocols, ports, URLs, cert paths)
- Enforce explicit TLS context (domains, applications, TLS_ENABLED, TLS_MODE)
- Support letsencrypt and self_signed with SAN handling and per-app overrides
- Update TLS provider roles to assert resolver state instead of setting facts
- Add comprehensive unit tests for tls_resolve lookup

https://chatgpt.com/share/6972b49b-b074-800f-a323-dd9fe69d02eb
2026-01-23 00:36:46 +01:00
kevinveenbirkenbach 9fdb0cddd0 Replace global WEB_PROTOCOL / WEB_PORT / WEBSOCKET_PROTOCOL logic
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
2026-01-22 20:36:49 +01:00
kevinveenbirkenbach 95e3823d2f refactor: centralize token store init and allow Mailu 301 status checks
- 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
2026-01-17 23:37:54 +01:00
kevinveenbirkenbach 14c968578d fix(matomo): retry site verification until DNS and API are ready
Add retry logic with 30 attempts and 2s delay to Matomo site check to
handle transient DNS and startup timing issues in Docker-in-Docker and CI
environments.

This prevents false negatives caused by temporary name resolution failures
while CoreDNS and the Matomo service are still initializing.

https://chatgpt.com/share/696aab20-6e28-800f-a860-4a6a1fcd7446
2026-01-16 22:18:17 +01:00
kevinveenbirkenbach 7dea10949a Ensure Matomo is loaded when unreachable or token is missing
- Include sys-token-store as a dependency for frontend injections
- Make Matomo loading conditional on reachability or missing token
- Handle undefined reachability checks conservatively
- Remove redundant empty-token validation spacing
- Ensure deterministic and idempotent Matomo bootstrap behavior

https://chatgpt.com/share/69579627-1b40-800f-971b-039bc8dc413b
2026-01-02 10:55:47 +01:00
kevinveenbirkenbach 15219a8192 Fail early if Matomo API token is empty
Add a validation guard after token store inclusion to abort execution
when users.administrator.tokens['web-app-matomo'] is empty or whitespace.
This prevents silent Matomo API failures caused by misconfigured tokens.

https://chatgpt.com/share/69552203-4f40-800f-94b1-7ce54ca81d0a
2025-12-31 14:15:40 +01:00
kevinveenbirkenbach 93f09ac0a7 feat(token-store): hydrate runtime tokens + unify Matomo token usage
**Body**

* add sys-token-store filter plugin to hydrate users.*.tokens from persisted store (users win if non-empty)
* load token store during sys-token-store core run and inject hydrated tokens into users fact
* remove legacy lookup task and simplify docs + store path naming
* switch Matomo frontend injection to use hydrated users.administrator.tokens[web-app-matomo] directly
* ensure Mailu token handling uses sys-token-store write task and checks token presence via users.*.tokens
* add unittest for token hydration filter plugin with path-based module loading
2025-12-31 13:43:29 +01:00
kevinveenbirkenbach fadde240d8 refactor(tokens): unify token handling via sys-token-store
- Introduce sys-token-store lookup.yml (users → store → empty)
- Introduce sys-token-store write.yml (persist + inject into runtime users)
- Remove all implicit token generation and legacy token tasks
- Migrate Matomo to users.<user>.tokens[application_id]
- Remove redundant Matomo token.value and credentials schema
- Fix Matomo bootstrap env: use MATOMO_ADMIN_USER consistently
- Harden Matomo site verification error handling
- Align sys-front-inj-matomo with unified token model

https://chatgpt.com/share/694d7d55-28a0-800f-8c91-cd09cb9ded7f
2025-12-25 19:07:08 +01:00
kevinveenbirkenbach 27c399123b Optimized handler loading. Requirerd due to 2.18->2.20 update 2025-12-04 00:53:27 +01:00
kevinveenbirkenbach c835ca8f2c refactor(front-injection): stabilize run_once flow and explicit web-service loading
- sys-front-inj-all: load web-svc-cdn and web-svc-logout once; reinitialize inj_enabled after services; move run_once block to top; reorder injections.
- sys-front-inj-css: move run_once call into 01_core; fix app_style_present default; simplify main.
- sys-front-inj-desktop/js/matomo: deactivate per-role run_once blocks; keep utils/run_once where appropriate.
- sys-front-inj-logout: switch to files/logout.js + copy; update head_sub mtime lookup; mark set_fact tasks unchanged.
- sys-svc-cdn: inline former 01_core tasks into main; ensure shared/vendor dirs and set run_once in guarded block; remove 01_core.yml.

Rationale: prevent cascading 'false_condition: run_once_sys_svc_cdn is not defined' skips by setting run-once facts only after the necessary tasks and avoiding parent-scope guards; improves determinism and handler flushing.

Conversation: https://chatgpt.com/share/68ecfaa5-94a0-800f-b1b6-2b969074651f
2025-10-13 15:12:23 +02:00
kevinveenbirkenbach 97af4990aa refactor(webserver): rename roles and update references
- Rename sys-svc-webserver -> sys-svc-webserver-core
- Rename sys-stk-front-pure -> sys-svc-webserver-https
- Update includes, run_once flags, and docs across:
  * sys-ctl-mtn-cert-renew
  * sys-front-inj-*
  * sys-stk-front-proxy
  * sys-svc-certs
  * sys-svc-cln-domains
  * web-opt-rdr-*
  * web-svc-*
- Remove redundant webserver include in web-opt-rdr-www
- Fix documentation links

Ref: ChatGPT conversation https://chatgpt.com/share/68d6cea2-3570-800f-acb3-c3277317f17b
2025-09-26 19:34:42 +02:00
kevinveenbirkenbach b02d88adc0 Refactored server roles for better readability 2025-09-01 18:08:35 +02:00
kevinveenbirkenbach 231fd567b3 feat(frontend): rename inj roles to sys-front-*, add sys-svc-cdn, cache-busting lookup
Introduce sys-svc-cdn (cdn_paths/cdn_urls/cdn_dirs) and ensure CDN directories + latest symlink.

Rename sys-srv-web-inj-* → sys-front-inj-*; update includes/templates; serve shared/per-app CSS & JS via CDN.

Add lookup_plugins/local_mtime_qs.py for mtime-based cache busting; split CSS into default.css/bootstrap.css + optional per-app style.css.

CSP: use style-src-elem; drop unsafe-inline for styles. Services: fix SYS_SERVICE_ALL_ENABLED bool and controlled flush.

BREAKING CHANGE: role names changed; replace includes and references accordingly.

Conversation: https://chatgpt.com/share/68b55494-9ec4-800f-b559-44707029141d
2025-09-01 10:10:23 +02:00