Commit Graph
120 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5.5 52fe3c9c2c style: apply make autoformat to the merged Stalwart and Tor files
Formatter output only: the parsed YAML and the Python AST of every touched file equal their previous versions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 19:57:30 +02:00
Alejandro Roman 026b28f9a7 fix(swar-stalwart): migration process 2026-08-30 14:43:00 +04:00
Alejandro Roman 3c7c3239be feat(swarm): fix CI and mirations issues 2026-08-21 00:25:38 +04:00
Alejandro Roman ed1f35d6ae feat(swarm): add new test appraoch + fix swarm issues 2026-08-19 20:08:59 +04:00
Alejandro Roman ac101d2efa Merge kevinveenbirkenbach/feature/swarm-nfs into stalwart integration branch 2026-07-21 10:00:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 04414a0ec5 revert(swarm-nfs): drop backup-drill rework, openproject bypass, xwiki replicas:1
Back to the pre-swarm-nfs-fix baseline:
- 5c2c8f531 + 985ec7eab: the swarm writer-quiesce DR drill. Deep-dive
  attribution of CI run 29715516546 found it the dominant failure source
  (17 of 23 jobs): [9b/9] handed-off generation mismatch, [6/9] quiesce
  stack-rm network race, [4/9] remote-2-local pull stall, compose discourse
  restore duplicate key.
- d6f980574: openproject swarm ingress to web:8080. Carried a leaking
  proxy_internal_port lookup (no per-app default) that broke the seaweedfs
  dependency front-proxy ('Key web not found'); the bypass-the-Apache-proxy
  approach was never verified against downloads/X-Sendfile.
- 1dd153bad: xwiki replicas:1 + mem 3g. Did not resolve the xwiki superadmin
  failure (still red in run 29715516546), so it is unverified.

Re-approach each from a clean baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 12:11:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 5c2c8f531f fix(backup): pass quality-high for the swarm writer-quiesce drill
Follow-up corrections to b449f8157 (swarm DR drill):
- export test.env in 06/07 via set -a so the child db restore/probe
  scripts inherit BKP_TEST_DATABASES_CSV and BKP_TEST_RESTORE_BIN
  instead of aborting at their :? guards before any restore runs
- move db_probe.sh/db_restore.sh into a db/ subfolder (probe.sh,
  restore.sh) and update all callers, so they stop tripping the
  prefix-grouped-files structure lint
- define TEST_E2E_SWARM_DRILL in group_vars/all and drop the now
  redundant default() from test.env.j2 (satisfies the undefined-var
  and spot-default lints together)
- fix a mermaid parse error in the drill README: a ; in a
  sequenceDiagram note was read as a statement separator

make quality-high green (test + lint phases, 15 targets, 0 failures).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 05:45:26 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3ebc4113b1 fix(snipe-it): probe /health and sharpen the manager-pin justifications
The healthcheck fetched GET / which is auth-gated: Laravel answers with an absolute redirect to the public domain (URL::forceRootUrl), GNU wget follows it and fails DNS inside the swarm lab, so the task never turned healthy and converge expired. Probe the unauthenticated /health endpoint instead. Also replace four default-placement justifications with the audit-verified reasons (bluesky sqlite-WAL over NFS, mailu mail-edge IP binding plus NFS-hostile postfix/dovecot state, opencloud JetStream/bleve/boltdb engine state, seaweedfs leveldb/raft/needle volumes) and drop dead general vars whose only consumers were commented-out lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 02:37:27 +02:00
Alejandro Roman 9962429e59 Added playwright testing 2026-06-30 20:37:50 +02:00
kevinveenbirkenbachandClaude Opus 4.7 cd5d22c9d7 refactor(web-app-matomo): renumber tasks, lift HOST_TIMEZONE_LABEL, swarm-aware envfile and bootstrap script
Renumber the tasks/ tree to a flat NN_ scheme (drop the 02b / 03a / 03b
suffixes) and update all include_tasks references; main.yml -> 01_core
stays unchanged. Lift the hardcoded matomo bootstrap timezone label
into a global HOST_TIMEZONE_LABEL constant in group_vars/all so other
apps can share it; default to "United Kingdom" because GB has a single
IANA timezone and matomo's getTimezoneName collapses to the country
name in that case. Drop unconditional double quotes from env.j2 and
bootstrap.env.j2 since docker stack deploy preserves env-file quotes
literally and was feeding matomo "matomo" instead of matomo as the
DB name. Add MATOMO_ADMIN_EMAIL via the users lookup so the bootstrap
template can reference a typed variable instead of constructing the
address inline. Switch 08_patch_trusted_hosts to ansible.builtin.shell
with the script body piped in via stdin from lookup('file', ...) and
shrink the script file to just the inner sh body. Strip section-banner
and restate-the-code comments from vars/main.yml, env.j2 and the
extracted script; keep the two genuine trip-wire comments (matrix
deploy round-2 DB creds, include_role-chain role_vars pollution) in a
shorter Exception form.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 19:08:44 +02:00
kevinveenbirkenbachandClaude Opus 4.7 9cacfbf959 refactor(swarm): inventory-driven topology replaces per-role swarm flags
DEPLOYMENT_MODE is now derived per role from group membership:
swarm iff len(groups[application_id]) > 1, else compose. The cluster
infrastructure flag SWARM_CLUSTER_AVAILABLE is true whenever any host
sits in svc-docker-swarm, so DB and proxy services render attachable
overlay networks even when their own group lists only one host.

All service_is_stateful flags are removed across svc-db-mariadb,
svc-db-postgres, svc-db-openldap, svc-prx-openresty, svc-docker-registry
and svc-db-mariadb's compose template; the inventory shape now expresses
the same intent. Cluster-wide handlers (swarm build/push/validate/deploy,
external network creation, DB healthcheck) gain run_once + delegate_to
the manager so they execute exactly once regardless of how many hosts
the role's play targets. CA-injection and compose validate are gated to
compose-mode only; their compose-config strictness breaks when the
deploy block coexists with container_name under swarm.

Dead per-host swarm-resolve infrastructure is removed: swarm_resolve_
container.sh, resolve_container.yml, resolve_self.yml, the MariaDB-
specific swarm_mariadb_cid.sh, the cross-host template replication
step, and the _swarm_retries / _swarm_delay defaults. With run_once +
delegate_to: manager replacing the old "render every template on every
swarm peer" pattern, every consumer becomes a noop on workers and
collapses to the manager's one-shot path.

The web-app-nextcloud memcache override mapping flips from the legacy
"single" sentinel to "compose" (semantically equivalent under the new
model). Requirement 023 is updated to reflect the new model and drops
the now-irrelevant per-role opt-out / placement-constraint clauses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-04 17:11:07 +02:00
kevinveenbirkenbachandClaude Opus 4.7 177f039b11 refactor(web-app-zammad): rename basic_auth_password → api_bot_password + SPOTs
- Rename credential basic_auth_password → api_bot_password and var
  ZAMMAD_ADMINISTRATOR_PASSWORD → ZAMMAD_API_BOT_PASSWORD to reflect
  that the value is the role-internal bot's local password, not the
  administrator's (reused for the wizard-bypass admin only because both
  need the same shell-safe alphanumeric form).
- Introduce ORGANIZATION constant (defaults to SOFTWARE_NAME) and migrate
  organization-string consumers (mattermost team, shopware shop title,
  dashboard login/logout descriptions, simpleicons "provided by",
  user-administrator description/lastname).
- Add HOST_LL_CC_TAG (BCP-47 form, e.g. en-gb) and use in auto_wizard.
- Add NETWORK_TRUSTED_PROXY_CIDRS SPOT and consume from suitecrm,
  shopware and zammad reverse-proxy configs.
- Extract ZAMMAD_WEB_PROTOCOL via lookup('tls', …, 'protocols.web')
  instead of inline 'https' if … else 'http'.
- Use database_query for CREATEDB grant so it works on shared+non-shared
  databases; back the SQL with files/sql/grant_createdb.sql SPOT.
- Read administrator firstname/lastname from users lookup in
  auto_wizard.json.j2 instead of hardcoding.
- Drop redundant elasticsearch: block from web-app-zammad services.yml
  (no consumer reads it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:03:15 +02:00
kevinveenbirkenbachandClaude Opus 4.7 79faaf21e7 refactor(ansible): move INFINITO_* env lookups out of group_vars/roles into dev inventory
\`lookup('env', 'INFINITO_*')\` calls in group_vars / roles couple
deployment-agnostic Ansible code to default.env, which only exists in
dev/CI. Production deploys never source .env, so the lookups silently
fall back to their group_vars defaults and the inventory's intent gets
lost on the way (see the IP4 host_vars-overlay incident fixed in
8980b00b1).

Migrated keys (group_vars/roles -> inventory):
- DOMAIN_PRIMARY            (00_general.yml)
- BUILDKIT_ENABLED          (00_general.yml)
- CA_CONTAINER_ENABLED      (02_tls.yml)
- defaults_networks.internet.{ip4,ip6,dns}  (08_networks.yml)
- TEST_E2E_PLAYWRIGHT_KEEP  (roles/test-e2e-playwright/defaults/main.yml)

group_vars and the role default now carry literal fallback values;
the dev/CI inventory at \`inventories/development/default.yml\` pulls
the live values from .env via straight \`lookup('env', 'INFINITO_*')\`
calls without any \`| default(...)\` filter, because load.sh guarantees
the keys are set whenever .env exists.

The convention is enforced by the new lint test
\`tests/lint/filesystem/env/test_no_ansible_env_lookups.py\`, which
scans group_vars/, tasks/, roles/, and playbook.yml for any
\`lookup('env', 'INFINITO_*')\` against a default.env key and fails
with a pointer to the dev inventory as the injection site.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:57:13 +02:00
kevinveenbirkenbachandClaude Opus 4.7 3ee0f44c14 feat(compose): add INFINITO_BUILDKIT_ENABLED toggle + offline-pull tolerance
Lets operators force the legacy docker builder via INFINITO_BUILDKIT_ENABLED=0
(propagated through env/default.env, the compose env block, the BUILDKIT_ENABLED
ansible var and both the compose wrapper and the Build-compose handler), and
makes sys-svc-compose pull.py treat a failed `docker compose pull` as success
when every required image is already present locally — both needed to deploy
in sandboxed environments where docker.io is unreachable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:55:09 +02:00
kevinveenbirkenbachandClaude Opus 4.7 a77a570409 refactor(env): consolidate INFINITO_* namespace and centralize path/image SPOTs
Closes a stack of env-pipeline regressions left over from the recent
INFINITO_* namespace refactor by:

* DOMAIN_PRIMARY now reads INFINITO_DOMAIN strictly (was: legacy DOMAIN
  env var → defaulted to infinito.localhost, which never resolved
  because CoreDNS serves the INFINITO_DOMAIN value, infinito.example).
* group_vars/all/08_networks.yml IPs (ip4/ip6/dns) now read
  INFINITO_IP4 / INFINITO_IP6 / INFINITO_DNS_IP.
* PLAYWRIGHT_KEEP_ALL renamed to INFINITO_PLAYWRIGHT_KEEP end-to-end
  (env-builder, role default, run_one.yml docker exec, playwright.config.js,
  lint allowlist, docs anchor, CI workflow vars).
* PKGMGR_IMAGE renamed to INFINITO_PARENT_IMAGE; Dockerfile ARG drops
  the inline default so env/default.env is the only SPOT.
* INFINITO_SRC_DIR centralized: Dockerfile ARG (no default) + ENV;
  compose forwards it as build-arg, volume mount path, and container env;
  every Python CLI + shell helper + CI workflow now reads it strictly
  (os.environ[...] / "${INFINITO_SRC_DIR:?...}") instead of the literal
  /opt/src/infinito.
* New entries in env/default.env: INFINITO_IP6=::1, INFINITO_PARENT_IMAGE,
  INFINITO_PLAYWRIGHT_KEEP=false. All three propagated through
  utils/env/handlers/passthrough.STATIC_KEYS and (where consumed in the
  container) through compose.yml's environment block.

Validated end-to-end with `make test` (2360 tests across lint, lint-*,
test-lint, test-external, test-unit, test-integration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 02:30:34 +02:00
kevinveenbirkenbachandClaude Opus 4.7 944e782d84 refactor(applications): introduce status lookup + rbac_app_ids filter; rename allowed_applications → APPLICATIONS_WHITELIST
- plugins/lookup/status.py: new lookup returning {whitelist, running, groups, all}, cached per (whitelist, groups). Consumers replace direct group_vars references.
- web-app-keycloak/filter_plugins/rbac_per_app.py: add `rbac_app_ids` (intersect input list with invokable apps; sorted, deduped).
- web-app-keycloak/tasks/update/05c_per_app_mappers.yml: drop two set_fact tasks; consume KEYCLOAK_RBAC_{ALL,RUN}_APP_IDS as constants from vars/main.yml. Split orphan-purge scope (all host-deployed) from mapper-sync scope (current run).
- Rename Ansible-side `allowed_applications` → `APPLICATIONS_WHITELIST` (group_vars/all default, deploy CLI `-e` injection, generated include `when:` clause, debug task, test asserts). Python kwarg name unchanged (internal contract).
- test-e2e-playwright: `TEST_E2E_PLAYWRIGHT_ONLY_ROLES` consumes `lookup('status').running`; `TEST_E2E_PLAYWRIGHT_APPS` moved from set_fact to vars/main.yml constant.
- 01_constructor debug: collapse to single `status:` block over the lookup result.
- web-app-{opencloud,opentalk}/vars: drop dead `group_names | default([])` + fix latent `| lower`-on-list precedence bug.
- New lint `test_no_jinja_default_on_ansible_magic_var.py`: forbid `| default(...)` on Ansible magic vars (group_names, inventory_hostname, …); meta-scan + 7 fixture positive cases.
- Unit tests for `rbac_app_ids` (10) and `status` lookup (8).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 18:39:52 +02:00
kevinveenbirkenbach 92cc9a49df test(lint): forbid | default(...) on resolvable group_vars/all SPOT paths
Adds tests/lint/ansible/test_no_jinja_default_on_spot_path.py: scans every
Jinja `{{ ... | default(...) }}` block under roles/, tasks/, group_vars/,
identifies the actual default target via a paren-aware left-walk from the
matched `|`, and fails when the target's dotted path resolves cleanly
against any group_vars/all/*.yml dict tree. Role vars/defaults are
intentionally out of scope (Ansible loads them only when the owning role
is in the play, so cross-role defaulting is a legitimate caller guard,
not SPOT decoupling). Per-line opt-out: `# nocheck: spot-default`.

Fixes the 21 violations the test surfaces:
- group_vars/all/00_general.yml: drop `| default('')` on CAPTCHA self-checks
- group_vars/all/02_tls.yml: drop `| default(...)` on DOMAIN_PRIMARY in CA subject
- roles/web-app-{listmonk,keycloak,espocrm}/meta/schema.yml: drop defaults on CAPTCHA.*
- roles/web-app-suitecrm/templates/env.j2: map empty SECURITY -> 'none' via `or`,
  not via the default filter (SPOT value `""` is always set)
- roles/web-app-opentalk/tasks/main.yml: drop default on MODE_ASSERT (always bool)
- roles/user-workstation/tasks/01_core.yml: drop default on MASK_CREDENTIALS_IN_LOGS
- roles/test-e2e-playwright/tasks/run_one.yml: drop defaults on TLS_MODE + CA_TRUST.*

Also corrects the dotted-path bugs in roles/web-app-odoo/vars/main.yml that
referenced non-existent LDAP keys (`LDAP.SERVER.REACH_DOMAIN`,
`LDAP.USERS.SERVICE_ACCOUNT.*`, `LDAP.ATTRIBUTES.ID`, `LDAP.SERVER.SSL`) to
the canonical paths actually defined in group_vars/all/12_ldap.yml.
2026-05-14 17:12:56 +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 04d31ec038 refactor(host-locale): introduce HOST_CS + HOST_LANG, replace hardcoded UTF-8
group_vars/all/00_general.yml gains:
- HOST_CS:   "UTF-8"                          (POSIX codeset / character encoding)
- HOST_LANG: "{{HOST_LL_CC}}.{{HOST_CS}}"     (full LANG env value, e.g. en_GB.UTF-8)

Replaces the corresponding hardcoded literals at the call sites:
- dev-locales/locale.conf.j2:    LANG/LANGUAGE -> {{ HOST_LANG }}
- dev-locales/locale.gen.j2:     active locale entry -> {{ HOST_LANG }} {{ HOST_CS }}
                                 (also fixes the en_US/en_GB drift against HOST_LL_CC)
- sys-ctl-alm-email/script.sh.j2: MIME charset -> {{ HOST_CS }}
- web-svc-legal/imprint.html.j2: <meta charset=...> -> {{ HOST_CS }}
- web-app-discourse/vars/main.yml: DISCOURSE_LOCAL "C.UTF-8" -> "C.{{ HOST_CS }}"
                                   (keeps the C-locale prefix that the container needs)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:47:22 +02:00
Environment TestandClaude Opus 4.6 77a0e16ea6 refactor(web-app-nextcloud): consolidate oidc.flavor under compose.services.oidc
Single source of truth at compose.services.oidc.flavor. Removes stray
root-level keys, deletes the _applications_nextcloud_oidc_flavor helper,
and switches all consumers (plugin toggles + PHP template) to direct
lookups. Also fixes inherited precedence bug on plugin.enabled filters
and corrects OICD/floavor typos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 11:15:27 +02:00
Environment Test fb7c581a83 refactor(nextcloud): migrate get_app_conf to lookup('config', ...)
Replace legacy filter with the canonical lookup plugin across
nextcloud config, group_vars, dashboard template, and vars
template. Switches Talk TURN from onboard to standalone coturn
by default; gates talk container on spreed plugin flag.

Adds lint test to catch remaining get_app_conf usages.
2026-04-13 15:17:34 +02:00
kevinveenbirkenbach c3fb04e91a refactor: share application dependency resolution 2026-04-01 15:13:04 +02:00
kevinveenbirkenbach 340e8a151c fix: stabilize public bind handling for nextcloud talk and mailu 2026-03-25 14:43:52 +01:00
kevinveenbirkenbach d44eee1048 Fix Ansible fact deprecations and loop variable collisions 2026-02-26 17:54:14 +01:00
kevinveenbirkenbach 88851a8f87 Implemented SOFTWARE_URL 2026-02-25 12:23:52 +01:00
kevinveenbirkenbach 5b807fe37f chore(ansible): document interpreter settings in group vars 2026-02-23 18:56:57 +01:00
kevinveenbirkenbach 70ecef3c1f Unify Python interpreter and pip install handling across distros 2026-02-22 15:50:37 +01:00
kevinveenbirkenbach 92946ee008 refactor(core): introduce SOFTWARE_DOMAIN and unify homepage, tls, service, and oidc defaults
* add SOFTWARE_DOMAIN derived from SOFTWARE_NAME lowercased
* introduce DOMAIN_HOMEPAGE defaulting to dashboard domain if present, otherwise SOFTWARE_DOMAIN
* add automatic primary → homepage redirect mapping in constructor
* migrate TLS and CA paths from SOFTWARE_NAME|lower to SOFTWARE_DOMAIN
* update systemd unit suffix and timer/service discovery globs to SOFTWARE_DOMAIN
* switch OIDC default realm and client id to SOFTWARE_DOMAIN
* adjust SuiteCRM well-known software name to SOFTWARE_DOMAIN
* update unit tests to use SOFTWARE_DOMAIN for strict Jinja expansion

https://chatgpt.com/share/698db094-22bc-800f-8454-10d97f817659
2026-02-12 11:50:55 +01:00
kevinveenbirkenbach b78ab29218 Renamed config entry from docker to compose
https://chatgpt.com/share/69870f54-d708-800f-9870-e9ae5a4bff44
2026-02-07 11:09:36 +01:00
kevinveenbirkenbach efc160d199 Deleted DOCKER_VARS_FILE orphans 2026-02-05 18:26:19 +01:00
kevinveenbirkenbach 76d09dbc3f refactor: centralize docker wrappers, CA injection paths, and update tests
Unify compose/run wrappers under PATH_* variables, wire CA trust injection
consistently, extend with NSS/Chromium support, and adapt unit tests to the
new run-based execution model.

https://chatgpt.com/share/697e1f92-bc5c-800f-968d-ad43c50afaea
2026-01-31 17:06:09 +01:00
kevinveenbirkenbach 2e7e31ba05 refactor: rename infinito-compose to compose-base and fix wrapper usage in cert deploy
- Rename infinito-compose wrapper to compose-base across roles and tests
- Introduce DOCKER_CMD_BASE as global base command configuration
- Update sys-ctl-mtn-cert-deploy to use compose_cmd consistently
- Fix compose wrapper argument parsing by enforcing "--" passthrough
- Harden project name resolution for trailing-slash instance paths
- Align docker restart helper scripts with compose-base naming
- Update unit tests to reflect renamed wrapper and new paths

https://chatgpt.com/share/697cf057-bd04-800f-9117-c007088f7fb8
2026-01-30 18:54:22 +01:00
kevinveenbirkenbach b2fb72d112 feat(tls): split TLS settings to 02_tls and add self-signed root CA role
Move TLS/ACME/CA vars out of 00_general into group_vars/all/02_tls.yml and renumber subsequent group_vars files. Add sys-ca-selfsigned to generate /etc/<software>/ca/root-ca.crt and make docker-compose-ca depend on it. Update setup script, templates, and tests to use the new applications/users file numbering.

https://chatgpt.com/share/697b8150-22ac-800f-98b1-e063a659b684
2026-01-29 16:48:03 +01:00
kevinveenbirkenbach 171693a2fa Added more documentation 2026-01-28 14:11:26 +01:00
kevinveenbirkenbach 4dbbcec106 feat(docker-compose): add dynamic CA trust injection for self-signed TLS
Introduce docker-compose-ca role with CA wrapper and inject script, add CA-aware compose override handling, and refactor compose pull/run logic to support multi-file projects. Update handlers, lookups, paths, and unit tests to consistently resolve TLS-driven CA injection without implicit defaults.

https://chatgpt.com/share/6973c00c-139c-800f-8ddb-e7d0cf5043fc
2026-01-23 19:36:55 +01:00
kevinveenbirkenbach ed11ab1c52 fix(tls): make TLS_SELFSIGNED_SCOPE a global var and require it in cert_plan
https://chatgpt.com/share/6972d189-4b80-800f-947b-a4f23b5a21f5
2026-01-23 02:40:18 +01:00
kevinveenbirkenbach c3c54ce043 refactor(tls): split resolution and certificate planning, add global self-signed SAN support
- Extract shared TLS logic into module_utils/tls_common
- Introduce cert_plan lookup for certificate paths and SAN computation
- Simplify tls_resolve to strict protocol/port/domain resolution only
- Add global self-signed certificate scope covering all domains
- Mount self-signed cert base into OpenResty container
- Update Nginx templates to use cert_plan for ssl_certificate paths
- Add comprehensive unit tests for tls_common, tls_resolve, and cert_plan

https://chatgpt.com/share/6972c568-9e8c-800f-b89a-a0061966f9a8
2026-01-23 01:48:31 +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 0eb7071a49 fix(local-tests): force python3 for local inventory init and stabilize runtime vars
- Force PYTHON=python3 for test-local-init to avoid missing venv python
- Rename test-local-inventory-init-all target to test-local-init
- Fix JSON quoting for --vars in local deploy scripts
- Add RUNTIME default to group_vars
- Improve debug output for initial host vars
- Update user hint in local run script

https://chatgpt.com/share/697222e1-5edc-800f-b9ab-511d8afc3142
2026-01-22 14:14:50 +01:00
kevinveenbirkenbach daab131b71 ci: auto-detect storage constraints and enable aggressive docker cleanup
- add storage detection utility for CI (DockerRootDir free space check)
- automatically set STORAGE_CONSTRAINED in cli.deploy.test when disk < 100 GiB
- forward STORAGE_CONSTRAINED into generated CI inventory via --vars
- introduce global STORAGE_CONSTRAINED default in group_vars
- run aggressive docker prune handler only in storage constrained mode
- mark CI inventory environment as development

https://chatgpt.com/share/696d6a11-2d90-800f-83e8-a30f6229e2e0
2026-01-19 00:17:31 +01:00
kevinveenbirkenbach fd983bc69c refactor(ci,network): make DNS, IP and domain configuration fully env-driven
- Introduce env.ci as single source of truth for CI networking
- Make docker-compose, CoreDNS and Docker daemon fully env-driven
- Render CoreDNS Corefile from template via envsubst
- Replace hardcoded IPs/domains with environment variables
- Integrate env-based networking into Ansible defaults
- Remove static Corefile and daemon.json

This makes DNS and networking deterministic and reproducible across
host, CoreDNS, infinito runner and Docker-in-Docker.

https://chatgpt.com/share/696a3dda-5c6c-800f-8a16-47c0c604e1e3
2026-01-16 14:30:14 +01:00
kevinveenbirkenbach 198a2fe3cf fix(ansible): enforce system python interpreter and install python-ldap via OS packages
- Stop auto-injecting ansible_python_interpreter from PYTHON env for localhost
- Set ansible_python_interpreter globally to /usr/bin/python3
- Add interpreter to sample inventory
- Remove role-local interpreter overrides
- Switch python-ldap installation to distro package (python-ldap / python3-ldap)
- Drop pip-based python-ldap installation to avoid venv/libldap mismatches

https://chatgpt.com/share/6964335a-29cc-800f-ae65-6a35c7cd2559
2026-01-12 14:48:53 +01:00
kevinveenbirkenbach 04c9490745 Solved unit and integration tests 2026-01-10 13:07:12 +01:00
kevinveenbirkenbach 493c908931 fix(vars): guard applications access and fix OIDC flavor ternary precedence
- Default applications to an empty mapping to avoid undefined access
- Add explicit parentheses to ensure correct Jinja filter and ternary evaluation
- Stabilize Nextcloud OIDC flavor resolution when inventory provides no applications

https://chatgpt.com/share/695fff6e-8d20-800f-be9a-d0ad30ee198e
2026-01-08 20:17:58 +01:00
kevinveenbirkenbach 047c86058a Added workstation user to pass variables to pass integration tests 2026-01-08 12:36:57 +01:00
kevinveenbirkenbach 6bc097f96f refactor(email,domain): unify primary domain and TLS handling
- replace localhost special-casing with valid FQDN (infinito.localhost)
- derive system email DOMAIN and HOST directly from DOMAIN_PRIMARY
- align Mailu TLS_FLAVOR with SYSTEM_EMAIL.TLS (mail vs notls)
- tie OIDC_VERIFY_SSL to TLS_ENABLED for consistent test/CI behavior
- update CI deploy script to use new primary domain

https://chatgpt.com/share/695311c0-fbe8-800f-8058-9d40a06b189a
2025-12-30 00:41:46 +01:00
kevinveenbirkenbach ea04035e12 feat(config): rename SSL_ENABLED to TLS_ENABLED across stack
* Replace global `SSL_ENABLED` flag with `TLS_ENABLED`
* Update web protocol/ports (http/https, ws/wss) to use `TLS_ENABLED`
* Switch cert-related roles and nginx TLS header gating to `TLS_ENABLED`
* Update app env templates (BookWyrm, Confluence, Jira, Magento, OpenProject, WordPress, etc.) to use `TLS_ENABLED`
* Adjust inventory generator to write `TLS_ENABLED` and update CLI help text accordingly
* Update unit tests for inventory vars overrides to expect `TLS_ENABLED`

https://chatgpt.com/share/695306ef-a798-800f-b118-e07b525e1811
2025-12-29 23:55:20 +01:00
kevinveenbirkenbach bf4af7c823 Renamed domain variables 2025-12-29 20:37:47 +01:00
kevinveenbirkenbach d734a15ad6 feat(ci,webserver): add localhost DNS + default vhost 404 assertion
- switch CI DNS to CoreDNS-based *.localhost resolution (A/AAAA → loopback)
- set PRIMARY_DOMAIN to localhost for CI deploys
- add explicit DNS resolution assert for test.localhost
- deploy explicit default_server vhost returning 404 text/plain
- assert default vhost behavior via HTTP before app domains exist

https://chatgpt.com/share/6952cf2a-bbd4-800f-b2b8-c4baba66e301
2025-12-29 19:57:41 +01:00