Commit Graph
27 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 Fable 5 ba6ecba64b feat(lint): flag redundant compose_handlers_flush=false + manual flush
sys-svc-compose already flushes compose handlers (and runs post-deploy) when the including role passes compose_handlers_flush: true. Roles that set it false and then immediately hand-roll their own meta: flush_handlers just reimplement that flush. Add an adjacency-scoped lint that catches the back-to-back form (a deferred flush with real work between the include and the flush stays legitimate and keeps false), and collapse the five offenders (checkmk, chess, jellyfin, pihole, semaphore) to compose_handlers_flush: true.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 00:00:49 +02:00
kevinveenbirkenbachandClaude Opus 4.8 96aa7784b6 feat(sys-svc-compose): scale all task timeouts via TIMEOUT_FACTOR lookup
Add a 'timeout' lookup plugin that returns round(base * TIMEOUT_FACTOR)
(group_vars default 1, so value-identical to the old literals). One knob
in group_vars stretches every wait in the stack for a slow uplink:
TIMEOUT_FACTOR: 2 doubles them all.

- plugins/lookup/timeout.py + unit tests (identity, factor scaling,
  string coercion, error paths).
- group_vars/all/17_resource.yml: TIMEOUT_FACTOR: 1.
- Convert all 34 literal 'timeout:' task keywords / module args across 25
  task+handler files to "{{ lookup('timeout', <base>) | int }}".
- tests/lint/repository/yaml/test_timeout_uses_lookup.py enforces the
  lookup in every task/handler timeout (opt-out: # nocheck: timeout-lookup).
- swarm.yml pre-deploy build handler: add the missing timeout (same
  network-build hang vector as compose.yml's Build compose).
- Drop 13 pre-existing narration comments in the touched files (comment
  lint enforces whole-file on any edited file).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 13:57:30 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4ace141939 fix(web-app-pihole): drop redundant sso-proxy provider_ca_files task
Under self_signed TLS the shared sso-proxy template (web-app-keycloak) now both bind-mounts the platform CA to CA_TRUST.cert_container (sso_proxy/container.yml.j2) and points provider_ca_files at it (oauth2-proxy-keycloak.cfg.j2), gated on the same condition as this task. pihole's lineinfile added a SECOND provider_ca_files (the wrapper-injected /tmp path, which is skipped for the distroless oauth2-proxy image), producing 'toml: key provider_ca_files is already defined' so the sidecar crash-looped and never converged. The task is redundant and its path less reliable than the template's explicit bind mount, so remove it and the now-unused PIHOLE_SSO_PROXY_CA_CONTAINER_PATH.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 16:47:34 +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 45df36e9c4 fix(web-app-pihole): gate sso-proxy CA-trust on IS_STACK_HOST
The oauth2-proxy-keycloak.cfg the lineinfile edits is rendered only on the stack host; on swarm workers it does not exist, so the task failed with 'Destination ... oauth2-proxy-keycloak.cfg does not exist' (rc 257) on wrk-01/wrk-02 while the manager succeeded. Gate the task on IS_STACK_HOST so it runs only where the file exists; compose (IS_STACK_HOST true) is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 23:15:39 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4c8a1ca59d refactor(compose): source published container ports from ports.internal
Rewrite every hardcoded literal container port in a compose.yml.j2 publish
mapping (- "<host>:<...ports.local|public.kind...>:<LITERAL>") to read the
declared ports.internal.<kind> via lookup, across 22 roles, so the published
(local/public) port and the container (internal) port are a single declared
source of truth. Mappings whose container already references the lookup or a
variable are left as-is.

This surfaced and fixed a real swarm bug: web-app-openproject declared
ports.internal.http: 8080 while the container actually listens on 80, so the
swarm resolve_upstream pointed openproject at the wrong port. Reconciled to 80
(the mapping's real container port).

Extend tests/lint/roles/test_swarm_internal_ports.py with a second check: a
published mapping's container segment must come from ports.internal via a lookup
(or a variable referencing it), never a hardcoded literal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 03:30:11 +02:00
kevinveenbirkenbachandClaude Opus 4.8 faca8835ea style(web-app-pihole): yamllint-normalize meta and tasks
Pure formatter pass, no behaviour change: add the `---` document marker, indent
the run_after list item, normalize a quote style and drop over-aligned key
padding in 01_core.yml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:31:36 +02:00
kevinveenbirkenbach e3a923fc28 Add wait_for task for Pi-hole HTTP endpoint 2026-06-24 03:46:12 +02:00
kevinveenbirkenbach e3d3f4e6a5 Delete roles/web-app-pihole/tasks/01_setup.yml 2026-06-24 03:46:12 +02:00
Prageeth Panicker 2fc7585ae8 fix(pihole): Pi-hole v6 compatibility fixes for login and password setup
- native.spec.js: update button selector from /sign in|login/i to
  /log in|sign in/i — Pi-hole v6's submit button text is
  'Log in (uses cookie)', not 'Sign in' or 'Login'

- 01_setup.yml: remove pihole setpassword CLI task — Pi-hole v6 blocks
  this command when FTLCONF_webserver_api_password is set via env var
  ('set by environment variable; please unset it to use this function').
  Password is now set at container startup via the env var, which is
  the v6-idiomatic approach.
2026-06-24 03:46:11 +02:00
Prageeth Panicker b10a09d28c fix(pihole): use provider_ca_files (plural array), not provider_ca_file
oauth2-proxy's singular 'provider-ca-file' flag has a known bug
(oauth2-proxy/oauth2-proxy#2802) and may not be a valid config key on
:latest, causing oauth2-proxy to fail config parsing and crash on
startup. This made nginx's auth_request to sso-proxy return 500 for
every pihole request (HTTP Error 500 on https://pihole.infinito.example/),
blocking even the pre-Playwright readiness check.

provider_ca_files (plural, array of strings) is the documented,
working config key for loading a custom CA for the OIDC provider
connection.
2026-06-24 03:46:11 +02:00
Prageeth Panicker 408026bf7f fix(pihole): trust self-signed platform CA for sso-proxy OIDC discovery
oauth2-proxy (quay.io/oauth2-proxy/oauth2-proxy) is a distroless image
with no /bin/sh, so the platform's CA-trust wrapper (with-ca-trust.sh,
applied by compose_ca.py for services with a shell) is skipped for this
container. Go binaries ignore SSL_CERT_FILE/REQUESTS_CA_BUNDLE and use
only the OS system cert pool, so on self-signed TLS setups oauth2-proxy
fails OIDC discovery against Keycloak with
'x509: certificate signed by unknown authority'. nginx then falls back
to pihole's native /admin/login instead of redirecting to Keycloak,
breaking SSO entirely in CI and on any self-signed deployment.

Fix: append provider_ca_file to the rendered sso-proxy config after
web-app-keycloak/tasks/sso_proxy.yml renders it and before compose up
runs. oauth2-proxy loads this CA explicitly for the OIDC provider
connection, bypassing the system cert pool entirely.

Scoped to this role: avoids touching the shared
oauth2-proxy-keycloak.cfg.j2 template (would affect every
flavor: oauth2 role platform-wide). No-op on production
(TLS_MODE=letsencrypt).
2026-06-24 03:46:11 +02:00
Prageeth Panicker 3daa60b7c0 fix(web-app-pihole): add compose_handlers_flush and increase wait_for timeout to 300s 2026-06-24 03:46:11 +02:00
Prageeth Panicker 3e964ffd31 fix(web-app-pihole): address reviewer feedback - SSO/native password, split tests, remove schema 2026-06-24 03:46:10 +02:00
Prageeth Panicker 2746654d36 fix(web-app-pihole): migrate to v9.x SSO pattern and fix compose_volumes 2026-06-24 03:46:10 +02:00
Prageeth Panicker 23d8374bcf fix(web-app-pihole): fix dynamic flags, port, personas, block size, docker exec, README 2026-06-24 03:46:10 +02:00
Prageeth Panicker 02e6c36aba fix(web-app-pihole): resolve CI lint failures and test compliance 2026-06-24 03:46:10 +02:00
Prageeth Panicker 835333d658 fix(web-app-pihole): wait for Keycloak OIDC endpoint before setup
Pi-hole deploys immediately after Keycloak but Keycloak needs time to
initialize OIDC. Adding explicit wait for Keycloak OIDC discovery endpoint
ensures oauth2-proxy can complete OIDC discovery and serve 302 redirects
instead of 500 errors when the platform Playwright wait check runs.
2026-06-24 03:46:10 +02:00
Prageeth Panicker f79a7350c3 fix(web-app-pihole): fix lint errors and add HTTPS health check
- meta/services.yml: add noqa comment for email integration
- tasks/01_setup.yml: use uri_retry instead of legacy uri module
- tasks/01_setup.yml: add HTTPS endpoint check to prevent 500 in CI wait check
- tasks/01_setup.yml: increase oauth2-proxy wait timeout to 300s with ignore_errors
2026-06-24 03:46:10 +02:00
Prageeth Panicker 29948cac9d fix(web-app-pihole): add ignore_errors to oauth2-proxy wait task
oauth2-proxy requires Keycloak to complete OIDC discovery before binding its port.
If Keycloak is still warming up, oauth2-proxy may not be ready within the timeout.
Playwright tests validate the actual functionality end-to-end.
2026-06-24 03:46:09 +02:00
Prageeth Panicker 772e92cf03 fix(web-app-pihole): increase oauth2-proxy wait timeout to 300s
oauth2-proxy needs time to complete OIDC discovery against Keycloak in CI.
120s was insufficient - increased to 300s to allow for slower CI environments.
2026-06-24 03:46:09 +02:00
Prageeth Panicker e3b76e81c0 fix(web-app-pihole): address reviewer feedback and fix CI failures
- tasks/01_core.yml: set docker_compose_flush_handlers: true, remove manual flush_handlers task
- tasks/01_setup.yml: add wait for oauth2-proxy port to fix HTTP 500 in CI wait check
- meta/services.yml: use NETWORK_PUBLIC_DNS_RESOLVERS SPOT for upstream_dns
- vars/main.yml: remove default from upstream_dns lookup, join list with semicolon
2026-06-24 03:46:09 +02:00
Prageeth Panicker 470118494a fix(web-app-pihole): migrate to meta/services.yml, fix domain resolution, disable native password 2026-06-24 03:46:09 +02:00
Prageeth Panicker 786bda0bfb fix(web-app-pihole): fix compose template, RBAC group, playwright env and wait flag 2026-06-24 03:46:09 +02:00
Prageeth Panicker 3112bb6402 fix(web-app-pihole): fix CI lint failures
- Add tasks/01_core.yml with run_once guard (test_service_core_first_task_run_once)
- Update tasks/main.yml to load 01_core.yml with run_once guard
- Add '# noqa: shared' comment on oauth2 config (test_service_shared_consistency)
- Remove unused PIHOLE_PORT variable from vars/main.yml (test_variable_usage)
2026-06-24 03:46:08 +02:00
Prageeth Panicker 561db31693 feat(web-app-pihole): add Pi-hole role with OAuth2/Keycloak RBAC
- Deploy Pi-hole as web app with NGINX proxy and OAuth2 protection
- Only web-app-pihole-administrators group can access the dashboard
- DNS port 53 (TCP/UDP) exposed for network-wide ad blocking
- Upstream DNS configurable per inventory (default: Cloudflare 1.1.1.1)
- Redis session store for OAuth2 proxy
- Timezone from HOST_TIMEZONE platform variable
- Port bindings use DOCKER_BIND_HOST platform variable
- Register subnet 192.168.102.240/28 in networks
- Register ports 8070 (http) and 16493 (oauth2) in ports
- Playwright tests: oauth2 protection, admin login, biber denied (3/3 passing)

Known limitations:
- Pi-hole v6 gravity blocklist requires manual setup via admin UI
- Internal *.infinito.example DNS forwarding to CoreDNS planned as follow-up
2026-06-24 03:46:08 +02:00