Commit Graph
33 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5.5 46fe011796 fix(web-app-fusiondirectory): lift the PHP memory_limit in the FPM pool
#1259 moved the interim CVE-2026-109618 mitigation (memory_limit = -1)
out of the shared hardening.ini into memory-unlimited.ini and mounted it
only in the roles whose images it had inventoried. Its branch predates
#1263, which gave FusionDirectory the php_hardening mount, so after both
merged FusionDirectory ran with the image default of 128M again.

A conf.d mount would not have fixed it: the nfrastack image writes
php_admin_value[memory_limit] into its FPM pool
(/etc/php7/pools.d/www/www-settings.conf) from PHP_MEMORY_LIMIT, and a
pool php_admin_value outranks every conf.d ini. Measured on main: CLI
128M, FPM 128M. So even before #1259 the hardening ini only ever lifted
the CLI limit.

nfrastack/fusiondirectory:1.5 runs PHP 7.4.33 on Alpine 3.15, end of
life and never patched, so the role carries the mitigation until it
moves to a PHP 8 image.

- Set PHP_MEMORY_LIMIT=-1 in templates/env.j2. The image seds it into
  php.ini and the pool, so CLI and FPM both report -1.
- The root TODO lists FusionDirectory with the image and the reason it
  uses the variable instead of the mount; the role TODO names which
  setting carries which CVE mitigation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 08:57:44 +01:00
kevinveenbirkenbachandClaude Opus 5.5 e3d2a24bcd fix(sys-svc-compose-php): scope memory_limit -1 to unpatched images
The interim CVE-2026-109618 mitigation lived in the shared hardening.ini,
so every PHP role ran without a memory limit until the last image was
patched, and no role's service_memory_mb share applied.

Registry metadata of the images pinned on main shows that 16 of the 20
consumers already ship PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12 (or the
Alpine/Debian build of it). Four predate the fix:
markoshust/magento-php:8.4-fpm (8.4.21), ghcr.io/heviat/webmail:2024.06
(the Mailu OIDC flavor, built 2025-04-04), phpldapadmin/phpldapadmin:2.3.11
(built 2026-05-15) and ghcr.io/shopware/docker-base:8.3 (8.3.25).

- Move memory_limit = -1 into its own content-addressed ini
  (FILE_PHP_MEMORY_UNLIMITED_INI) and mount it only in magento, mailu,
  phpldapadmin and shopware.
- hardening.ini keeps expose_php, session.upload_progress.enabled and
  fatal_error_backtraces as permanent hardening.
- Joomla's php-upload.ini loads as conf.d/uploads.ini again: no -1 has
  to be outranked anymore.
- The root TODO names the four images that still need the override.

Refs #1126

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 22:39:07 +01:00
kevinveenbirkenbachandClaude Opus 5.5 d89c74feab feat(security): harden PHP services and proxy response headers
Proxy:
- server_tokens off, X-Powered-By stripped from upstream responses,
  HSTS max-age raised to one year.
- No global X-Content-Type-Options: under nosniff, ORB (step 3.4)
  blocks no-cors cross-origin responses typed text/html, e.g. tracking
  beacons answered with an empty 204.

PHP (CVE-2026-109618, CVE-2026-109619):
- New role sys-svc-compose-php installs a shared ini (expose_php Off,
  session.upload_progress.enabled 0, fatal_error_backtraces 0 for
  PHP 8.5, interim memory_limit -1) and a PHP-FPM [www] drop-in
  (pm.max_requests = PHP_FPM_MAX_REQUESTS) once per stack host,
  before 04_files renders any compose file.
- The host file names carry a sha1 prefix of the controller-side
  source, so a content change alters every PHP app's compose.yml and
  recreates it, also on remote deploys where compose_volumes cannot
  read the stack host file and hashes the path instead.
- 20 PHP roles mount the ini as a compose/swarm config into their
  image's scan dir; moodle, nextcloud and shopware also mount the FPM
  drop-in. Magento keeps its own pool: its php-fpm.conf has no
  include= and is rendered without notify.
- Joomla's php-upload.ini now loads as zzz-joomla-uploads.ini so its
  own memory_limit wins: the media API compares Content-Length with
  toBytes(memory_limit) and rejects every upload at -1.

TODOs record the memory_limit revert condition and accepted
trade-offs, Akaunting on PHP 8.1, FusionDirectory on PHP 7.4 and the
public Keycloak admin console.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 21:03:38 +02:00
kevinveenbirkenbachandClaude Opus 5 8d1d45d246 fix(discourse): pin the OIDC issuer for the launcher-built container
Nextcloud#7 of run 33445831564 fails on three discourse specs, all on one
assertion, all for one reason. The received body is Discourse's own page:
"Sorry, there was an error while trying to authorize your account with oidc."

The browser leg works. What dies is Discourse's server-side back-channel:

    "GET /auth/oidc/callback?...code=..."  302  2.125 2.125
    "GET /auth/failure?message=openid_connect_request_failed&...&strategy=oidc"  200

Four of those, at 2.125 / 2.015 / 2.063 / 2.014 seconds. That is not the plugin's
10s HTTP timeout; it is Discourse's DNS budget, hard-coded at 2s in
lib/final_destination/resolver.rb (connect_timeout arrives nil, so the default
applies). openid_connect_request_failed has exactly one emitter --
omniauth_open_id_connect.rb:147-155, rescue Faraday::Error -- and the alternative,
SocketError -> LookupFailedError, is not a Faraday::Error and would have produced a
500 rather than the observed 302.

The correlation leaves no room: across 18 back-channel requests, all from
192.168.9.3 with UA Faraday v2.14.3, there are exactly two complete token 200 +
userinfo 200 pairs -- and exactly two specs passed. Thirteen truncated flows,
thirteen failures. No test that got a complete exchange failed; none that failed got
one.

Why discourse alone: discourse.inspect.json:72 reads "ExtraHosts": null. Grepping the
whole rescue bundle for the pin finds nextcloud, nextcloud-proxy, mailu-admin,
prometheus and prometheus-sso-proxy. Discourse could not have it: config.yml.j2's
docker_args: carried only --network= and --name=. It is built by discourse_docker's
launcher, not by a compose file, so the lookup's rendered block has nowhere to go --
hence entries_only, which returns the strings and lets the template write
--add-host= lines. The pin itself is NOT re-derived: _sso_pins() and
_gateway_address() stay the single place that knows compose from swarm.

Its existing allowed_internal_hosts cannot help, because ssrf_detector's
lookup_and_filter_ips resolves BEFORE host_bypasses_checks?; the setting only makes a
private answer acceptable once it arrives.

Rendered through a real Templar both ways: with SSO on, the two --add-host lines land
between the networks and --name; with SSO off the output is byte-identical to today,
so clearnet and variant-1 deployments render an unchanged app.yml and trigger no
launcher rebuild. 24 lookup tests green.

Not closed: the biber persona has never passed, here or in run 33317483326. Its
failure text and code path match administrator, which did pass, so it is explained --
but a persona-specific second defect is not positively excluded. Deploying discourse
variant 0 locally, which already has sso and tor enabled, settles it.

Separately worth queueing: discourse's own meta/variants.yml variant 1 sets
sso.enabled: false and only variant 1 is scheduled, so the role that owns these specs
never runs them. Only partner rounds like Nextcloud#7 catch this class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 12:00:56 +02:00
kevinveenbirkenbachandClaude Opus 5 104383942a docs(todo): correct the onion entries the last two runs overtook
gitlab leaves the server-side OIDC reachability list. It was there as a candidate for the container_extra_hosts one-liner, but run 31756560361 shows it resolving the issuer host and completing a TCP connect without any pin (peeraddr=172.30.0.10:443); the failure was the openid_connect gem rebuilding the discovery URL over https regardless of the issuer scheme, fixed in 2389b6e38. Left as written the entry sends the next reader down a path this run already closed. mobilizon joins it, having received the lookup in 0e39f3fad after OAuth2.Error Connection refused twenty-four times.

espocrm leaves the baseline exclusions. Its onion variant failed in the shared admin persona, fixed in b97cf8888; its clearnet variant returns HTTP 500 on GET /api/v1/App/user with the cause still open. Neither is out of scope any more.

The environment entry keeps its verdict for the 4h30m job cap and gains the boundary to the distro sweep budget, which is a different clock and did have a code fix in 508669809. The two were described interchangeably enough that I mixed them up myself while reporting.

The section header claimed completeness against a run and commit that are now two runs and twelve commits old.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 14:44:07 +02:00
kevinveenbirkenbachandClaude Opus 5 8ffb1f5674 refactor(peertube): make the role clearnet-only
PeerTube distributes video over WebRTC and the role proxies its tracker socket on purpose (templates/proxy.conf.j2:48, with a raised read timeout because peers ping every fifteen minutes). Tor carries no UDP and an onion client cannot hold peer connections, so an onion PeerTube is the app without the feature it exists for. What remained was plain HTTP video at Tor throughput, and a login path that only worked through a sed over the vendored dist of a third-party plugin.

That patch is gone with this change, along with PEERTUBE_OIDC_ALLOW_INSECURE_ISSUER, the variable that gated it, and both tor pins in meta/variants.yml. The root TODO entry describing it is removed too - it carried a three-step exit path (upstream MR, fork, delete) that no longer needs walking. The https-on-onion entry keeps its analysis and loses only the sentence that named peertube among the per-consumer workarounds.

The discovery gate stays. Failing the deploy when the plugin registered without building a client is not tor-specific and was the honest half of e64ed1cd9.

tor.enabled becomes a literal false rather than the block being deleted. Two lints define the contract: test_tor_contract requires every domain-serving role to declare the block, and test_sso_variant_requires_tor names a literal false as the first of three cases that may opt out of pinning the onion on with a reason. Deleting the block failed both; this is the language they specify.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 14:40:48 +02:00
kevinveenbirkenbachandClaude Opus 5 8c7593f43f refactor(container): make container_extra_hosts the only emitter of extra_hosts
extra_hosts is the one compose key a service may not carry twice. The onion SSO
back-channel pin was emitted by a Jinja partial that six roles included, while
six other services wrote the key by hand; nothing stopped a service from
receiving both. YAML then either rejects the document or keeps one list and
drops the other, silently.

The partial becomes plugins/lookup/container_extra_hosts.py, and every pin now
goes through it. Callers add their own entries with extra_hosts=[...], the way
container_volumes already takes extra_volumes=, and the lookup merges them after
the automatic pin and deduplicates in first-seen order. With nothing to emit it
returns an empty string.

The swarm address reasoning from 7b1839681 is preserved and now written down in
the plugin rather than only in that commit: the pin must NOT be host-gateway in
swarm, because that alias resolves per node while openresty publishes :80 with
mode: host under node.role == manager. It carries the stack host's address,
which reaches every task because the compose file is rendered once with the
manager as inventory host. The mode is read as compose_mode_force or
DEPLOYMENT_MODE, not the bare cluster mode, so a role with an override does not
lose its pin and its overlay at once.

Two roles kept a pin that now collides with the automatic one, and both are
resolved the same way -- the hand-written entry stays for clearnet and yields
the .onion case to the lookup, which picks the address per mode. In
web-app-mailu the three conditional entries move into a role-local
mailu_extra_hosts lookup exposed as MAILU_EXTRA_HOSTS, because an eight-line
conditional expression in the template argument is worse than the block it
replaced. It returns its entries as separate results, so vars/main.yml uses
query(); plain lookup() would join them into one comma-separated string.

tests/lint/ansible/jinja/test_compose_extra_hosts_use_lookup.py fails on any
literal extra_hosts: key in a role template, so the invariant survives the next
author who needs a pin. It follows test_compose_ports_use_container_ports_lookup:
the raw construct is forbidden, the lookup is not mandated per service -- a
service with no pins is correct without it, and the swarm branch raises when
facts are absent, which would turn a no-op into a failure surface for containers
that never speak OIDC.

Equivalence checked by rendering rather than by reading: under the trim_blocks +
lstrip_blocks the stack-host action forces for compose.yml.j2, both former call
site shapes (indented, and matrix's column 0) emit byte-identical text to the
new form when the block applies. The no-op case differs -- a whitespace-only
line where the include emitted none -- and yaml.safe_load returns the same
document for both.

31 unit tests; make test-lint 325 passed. Does not touch web-app-espocrm, whose
missing pin is a separate claim and gets its own commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 02:02:28 +02:00
kevinveenbirkenbachandClaude Opus 5 e64ed1cd93 fix(peertube): let OIDC discovery reach a plaintext onion issuer
openid-client v6 refuses a non-HTTPS issuer, and an onion-exclusive Keycloak has
none: the onion publishes only HiddenServicePort 80, and https there is blocked
on four separate things (see TODO.md). PeerTube's plugin therefore threw
OAUTH_HTTP_REQUEST_FORBIDDEN during discovery, never built a client, and answered
2326 logins with "OpenID provider unavailable" — while `test -d` on the plugin
directory reported the deploy as ok.

Two changes, one honest and one not:

The gate at the end of enable.yml now fails when the container log carries
"Initial OpenID discovery failed", so a plugin that registered without building a
client stops the deploy instead of surfacing hours later in the browser suite.

The sed over the installed dist is a hack and is marked as one in TODO.md. It
widens the trigger of the escape hatch upstream already implements — the plugin
gates `openid.allowInsecureRequests` on NODE_ENV alone, and setting NODE_ENV=dev
in production would swap PeerTube's whole runtime profile. The `grep -q` after
the substitution is what keeps it tolerable: an upstream release that moves the
line fails the deploy loudly rather than silently doing nothing.

Both are driven by one variable, PEERTUBE_OIDC_INSECURE_ISSUER, which requires
SSO enabled AND tor enabled for peertube AND an .onion issuer, so no deploy
without Tor can execute the patch or ever fail on it. Verified with Ansible's own
templar across seven cases, including https://onionsoup.example.com/ to catch a
too-greedy match. The sed itself was run against the real 2.0.1 tarball: exactly
one hit, `node --check` clean, and the patched expression exercised in four
environment combinations.

Exit path in TODO.md: the plugin is an official Framasoft one (AGPL-3.0 in the
repo root, the npm package merely ships no license field), and the proper fix is
a `registerSetting({ name: 'allow-insecure-issuer' })` OR-ed into the same
condition. Issue text and patch are written; upstream filing is waiting on a
framagit account.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 21:53:31 +02:00
kevinveenbirkenbachandClaude Opus 5 72fecd1c33 docs(todo): align distro job list with meta/distros.yml
The onion note listed manjaro, which is the base image rather than a
declared distro id; the SPOT lint flags any list that diverges from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 13:03:40 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e2bc4e447f docs(todo): document remaining onion e2e failure classes and their state
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 11:29:12 +02:00
kevinveenbirkenbachandClaude Opus 4.7 79409ebf10 test(tooling): integrate markdownlint-cli2, ansible-lint, galaxy-importer + fix the resulting baseline
Tooling integration
* add .markdownlint-cli2.jsonc, .ansible-lint, .ansible-lint-ignore
  configs (permissive day-1: cosmetic rules disabled, semantic ones on)
* extend scripts/install/lint.sh with generic install_pip_pkg helper +
  ensure_ansible_lint / ensure_galaxy_importer / ensure_markdownlint_cli2
  ensure_* functions (pip / npm with sudo / --user / --break-system-packages
  fallbacks). install_ansible_tools now also pulls ansible-lint and
  galaxy-importer; new `markdown` install group.
* extend scripts/lint/ansible.sh to run ansible-lint after the existing
  syntax-check.
* add scripts/lint/markdown.sh and scripts/lint/galaxy.sh runners. The
  galaxy runner parallelizes via xargs (-P=$(nproc)), prints OK/FAIL per
  role, and treats `bare-name dependency` errors as success since our
  roles/ tree is not a Galaxy collection layout. All other Galaxy schema
  errors still fail.
* Makefile: new lint-markdown and lint-galaxy targets, both wired into
  `make lint`.
* CI: new workflows lint-markdown.yml and lint-galaxy.yml; lint-ansible.yml
  now installs ansible-core + ansible-lint; ci-orchestrator wires both
  new lint workflows into lint-gate.

Galaxy schema fixes
* shorten the canonical `galaxy_info.company` block from three lines to
  two ("Kevin Veen-Birkenbach\nhttps://www.veen.world", 45 chars) so it
  stays under Galaxy's hard 50-char limit. Updated everywhere: 229 role
  meta/main.yml plus _CANONICAL_COMPANY in
  tests/lint/repository/test_role_meta_main_galaxy_schema.py.
* shorten 19 over-long role descriptions to <=255 chars.
* add stub READMEs for sys-svc-compose-ca and sys-utils-service-loader.

Markdown baseline fixes
* markdownlint-cli2 --fix run repo-wide (formatting normalization
  across CHANGELOG, role READMEs, docs).
* manual MD041 fixes: prepend H1 in 15 files (CHANGELOG, LICENSE,
  TODO.md helpers, role README templates, etc.).
* MD025 / MD003 / MD001 / MD032 manual fixes for heading-style and
  list-spacing edge cases.
* role README content polish: "## Single Point of Truth (SPOT)" headings
  renamed to "## User data resolution" (D3 self-label rule).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 23:46:37 +02:00
kevinveenbirkenbachandClaude Opus 4.7 43a0592ed5 fix(registry-cache): bypass gcr.io / storage.googleapis.com / googleusercontent.com
The bundled rpardini/docker-registry-proxy 0.6.5 nginx config does not
recognise the GCP Artifact Registry redirect URL shape
(``/artifacts-downloads/namespaces/<ns>/repositories/<repo>/downloads/<token>``)
and replies HTTP 500 to every blob fetch. Local matrix-deploy runs that
include images like ``gcr.io/cadvisor/cadvisor`` therefore fail at
``compose pull`` for the prometheus stack.

Add the three Google-owned blob hosts to ``NO_PROXY`` so the systemd
docker daemon goes direct to upstream for those redirects. The bypass
disables caching for those hosts only; every other registry still flows
through the local cache.

Long-term fix tracked in TODO.md: fork rpardini/docker-registry-proxy
and patch nginx's ``proxy_redirect`` / ``sub_filter`` rules to recognise
the new redirect shape, then drop this bypass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:21:21 +02:00
Environment TestandClaude Sonnet 4.6 750c110f45 fix(docs): apply documentation rules, fix URLs, and remove orphaned references
- Apply documentation.md rules across staged files (emojis after headlines, RFC 2119 keywords, correct link text, Credits format)
- Remove expired ChatGPT share URLs from 39+ role READMEs and templates
- Remove orphaned text after link deletion: bare # @see, {# @see  #}, Discussion: #}, empty Chat Conversation sections, dangling "Conversation is here available.", "Refer to the conversation with ChatGPT ()", "See ChatGPT Conversation", "ChatGPT Session Transcript" references
- Remove empty ## Further Resources and ## Credits sections where no links remain
- Fix URL reachability test: treat 401/403/405 as ok, 429/500/503 as warn, Timeout as warn; add # nocheck: url suppression (inline and line-above)
- Add lint test for broken relative and repo-root-absolute markdown links
- Add # nocheck: url to AUR git clone URLs, CSP allowlist entries, and other non-browser URLs
- Restore docs.infinito.nexus/setup in documentation.md MUST NOT example
- Fix Mobilizon geospatial endpoints (Addok, Photon) reverted to original values with # nocheck: url
- Add integration test rule: MUST NOT write unit tests for integration test logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 00:38:42 +02:00
kevinveenbirkenbachandClaude Sonnet 4.6 96649d8c9b refactor(services): centralize frontend service loading with generic lookup plugin
Introduces a SPOT for all frontend service loading in sys-front-inj-all/tasks/01_services.yml,
driven by a new generic `service` lookup plugin that resolves services by key or role name
and returns {id, role, enabled, shared, needed}. Needed = enabled AND shared (direct or
transitive). The canonical key→role mapping moves to group_vars/all/20_services.yml
(previously scattered hardcoded rules). Removes per-role service loads from bigbluebutton,
nextcloud, and dashboard. Renames 01_dependencies.yml→01_services.yml and
08_services.yml→08_daemons.yml. Adds flush_handlers after each service load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 08:27:21 +02:00
kevinveenbirkenbach 281b9cc081 docs: cleanup mailu administration guide and fix todo formatting 2026-03-23 23:59:21 +01:00
kevinveenbirkenbach d625962da1 fix(sys-pip-install): use isolated python check to fix packaging detection on CentOS
- Use 'python -I' (isolated mode) to check for 'packaging' library.
- This ensures the check fails if the library is missing in the strict environment used by Ansible modules, even if present in user site-packages.
- Fixes pip module failures on CentOS.
2026-03-23 20:21:27 +01:00
kevinveenbirkenbach ce64265cca Optimized docu in preparation for deploy script 2026-02-07 23:17:17 +01:00
kevinveenbirkenbach db127ec5ed Updated todo 2026-02-03 09:59:27 +01:00
kevinveenbirkenbach 82e2cde747 refactor(nginx): replace NGINX vars with nginx_paths lookup and add http/https support
- Drop legacy NGINX path definitions from group_vars
- Add nginx_paths lookup plugin (paths + ensure dirs + http_includes)
- Update roles/templates to use nginx_paths for config/data/cache/user paths
- Add per-domain HTTP->HTTPS redirect + ACME challenge include
- Add unit tests for nginx_paths lookup
- Clean up obsolete sys-svc-letsencrypt role files

https://chatgpt.com/share/697d4466-af54-800f-a243-b28367638c85
2026-01-31 00:52:42 +01:00
kevinveenbirkenbach 30e8b09e84 fix(tls): switch from self-signed leaf certs to CA-signed chain and make CA trust installation deterministic
https://chatgpt.com/share/697ca08d-bb54-800f-a6fc-56cd8e1d75c8
2026-01-30 13:13:44 +01:00
kevinveenbirkenbach 2678090934 feat(ca-trust): unify trust injection + strict templating
Move `with-ca-trust.sh` to `sys-ca-selfsigned` as the single source of truth, add `CA_TRUST_NAME`/`trust_name`, and pass it through `compose_ca_inject.py` + `compose_ca_inject_cmd`. Introduce `module_utils/templating.py` for strict multi-pass rendering with fallback env lookup, update TLS self-signed regen logic, purge script, and extend unit tests accordingly.

https://chatgpt.com/share/697c876d-7140-800f-9981-762dfeeafdfe
2026-01-30 11:26:46 +01:00
kevinveenbirkenbach 70945ae1b8 Optimized todos 2026-01-29 11:25:35 +01:00
kevinveenbirkenbach 61575cc267 Added todos 2026-01-16 21:09:57 +01:00
kevinveenbirkenbach 42a7f529d1 ci: make distros configurable per entry workflow and enforce via workflow_call
- Add `distros` input to code-analyses orchestrator and forward it to build and deploy workflows
- Enforce distros via required workflow_call inputs in test-deploy-* workflows
- Restrict push and pull-request entries to arch only
- Run nightly workflows on full distro matrix
- Align nightly release cron to 00:00 UTC
2026-01-15 16:33:46 +01:00
kevinveenbirkenbach e158dd3f3a refactor(bigbluebutton): make TURN/TLS optional and align coturn with shared service model
- Switch BigBlueButton Docker source to upstream bigbluebutton/docker (main)
- Migrate coturn/collabora from internal to shared service model
- Make TURN protocol configurable (turn vs turns) via TLS_ENABLED
- Add BBB_TURN_PROTOCOL variable and use it in TURN_SERVER
- Only inject coturn TLS cert/key when TLS is enabled
- Normalize IPv6 flag handling with explicit boolean check
- Fix YAML formatting, trailing whitespace, and missing newlines
- Fix web-svc-legal dependency list formatting
- Add TODO entry for inventory dependency resolution

https://chatgpt.com/share/69687cb2-1550-800f-a5a4-394de22b21ec
2026-01-15 06:35:38 +01:00
kevinveenbirkenbach 90caf1b51d docker-compose: always manage files, make compose template optional, and track new E2E failures
- Drop deprecated docker_compose_file_creation_enabled flag (defaults + all consumers)
- Always run docker-compose file routines and bring stack up (caller can disable auto-flush via docker_compose_flush_handlers)
- Treat docker-compose.yml.j2 as optional via first_found (skip if missing)
- Clean up role template vars (remove removed flag, fix alignment)
- Record new E2E CI failures for Akaunting (502) and Baserow (timeout)

Fixes BigBlueButton CI failure caused by missing .env in repository:
Previously file routines could be skipped, so /opt/docker/bigbluebutton/services/repository/.env
was never created/linked and scripts/generate-compose failed with:
"cat: .env: No such file or directory" and "EXTERNAL_IPv4 is not set in .env".
With file management always enabled, the env file is copied/linked before compose generation.

https://chatgpt.com/share/69681be9-f944-800f-9b67-8afdc3a256fc
2026-01-14 23:42:25 +01:00
kevinveenbirkenbach 8f5f2e34e1 Set 302 for initial JIRA setup 2026-01-14 23:07:54 +01:00
kevinveenbirkenbach d47c59ab3e Replaced falsy mastodon by matomo 2026-01-14 22:37:50 +01:00
kevinveenbirkenbach 41d8194b49 Fix MariaDB init for database names with hyphens
- Quote database identifiers with backticks in CREATE DATABASE and GRANT
- Prevent SQL syntax errors for app IDs like `snipe-it`
- Extend TODO with E2E tracking links

https://chatgpt.com/share/696809fa-7728-800f-8f57-a79a9c230b5a
2026-01-14 22:25:52 +01:00
kevinveenbirkenbach 4a3923e405 Removed legacy. Now systemd is available and this exiptions aren't required to behandled anymore 2025-12-30 19:28:36 +01:00
kevinveenbirkenbach 1e5ebbb05f feat(inventory): add --vars-file support for YAML-based host_vars overrides
- add --vars-file CLI option to load host_vars overrides from YAML
- merge vars-file overrides before JSON --vars (JSON takes precedence)
- implement deep-merge logic for YAML vars files
- update CI deploy script to use vars file instead of inline JSON
- add unit test for apply_vars_overrides_from_file
- remove obsolete MASK_CREDENTIALS_IN_LOGS TODO entry

https://chatgpt.com/share/6952e51d-6c50-800f-8764-31dc8c609cdb
2025-12-29 21:31:05 +01:00
kevinveenbirkenbach dcd0bed303 refactor(sys-ctl-bkp-docker-2-loc): move databases.csv permission handling to core
- Move databases.csv permission task from seed phase to core tasks
- Ensure root-only permissions are enforced early and unconditionally
- Remove custom run-once logic and related state tracking
- Simplify role logic and improve determinism
- Update run-once integration test documentation and expectations
- Add TODO to verify Docker-in-Docker behavior
2025-12-28 10:41:42 +01:00
kevinveenbirkenbach 2fccebbd1f Enforce uppercase README.md and TODO.md filenames
- Renamed all Readme.md → README.md
- Renamed all Todo.md → TODO.md
- Added integration test (tests/integration/test_filename_conventions.py) to automatically check naming convention.

Background:
Consistency in file naming (uppercase README.md and TODO.md) avoids issues with case-sensitive filesystems and ensures desktop cards (e.g. Pretix) are properly included.
Ref: https://chatgpt.com/share/68b1d135-c688-800f-9441-46a3cbfee175
2025-08-29 18:11:53 +02:00