Commit Graph
14682 Commits
Author SHA1 Message Date
infinito-nexus-updater[bot] e50dcf876c update(images): update Docker image versions (web-svc-logout) 2026-10-30 22:34:13 +00:00
kevinveenbirkenbach 2729a56125 Merge pull request #1308 from infinito-nexus/fix/web-app-fusiondirectory/lifecycle-eol
fix(web-app-fusiondirectory): set the role's lifecycle to eol
2026-10-30 23:33:44 +01:00
kevinveenbirkenbach 6f12dcc147 Merge remote-tracking branch 'origin/main' into fix/web-app-fusiondirectory/lifecycle-eol 2026-10-30 23:24:37 +01:00
kevinveenbirkenbachandClaude Opus 5.5 727cce33ec fix(web-app-fusiondirectory): set the role's lifecycle to eol
FusionDirectory's image runs PHP 7.4, which has been out of security
support since 2022, and upstream ships no PHP 8 build. The runtime
health check of #1265 therefore reports every deployment of it, and in
CI a red FusionDirectory job makes the matrix's fail-fast cancel every
other job of the run (seen on #1265's run 41101611445: one red job, 79
cancelled). There is nothing to fix on our side short of upstream
shipping a supported runtime.

- meta/services.yml: lifecycle beta -> eol. Default CI (tested envelope
  alpha..maintenance) no longer deploys the role, the updater and the
  image mirror skip it (mirrored image set 188 -> 187).
- README.md: end-of-life banner as lifecycle.md requires for eol: the
  project neither maintains nor tests the role, operators use it at
  their own risk, upstream FusionDirectory for support.
- Root README.md: make docs drops the role from the generated table of
  the tested lifecycle envelope.

Production deploys of the role keep running the runtime check, so an
operator who still deploys it sees the PHP 7.4 finding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:24:31 +01:00
kevinveenbirkenbach b97f38ca49 Merge pull request #1261 from infinito-nexus/fix/web-app-keycloak/admin-network-allowlist/1121
feat(web-app-keycloak): serve /admin only to declared source networks
2026-10-30 23:15:41 +01:00
kevinveenbirkenbach d95319c116 Merge pull request #1307 from infinito-nexus/fix/web-app-stalwart/swarm-smtp-listener
fix(storage): keep the NFS client off the ports the platform publishes
2026-10-30 23:09:32 +01:00
kevinveenbirkenbach b0bacd072f Merge remote-tracking branch 'origin/main' into fix/web-app-stalwart/swarm-smtp-listener 2026-10-30 23:02:44 +01:00
kevinveenbirkenbachandClaude Opus 5.5 eb7056dafd fix(storage): keep the NFS client off the ports the platform publishes
Main CI run 40976399687, socialhome#0 (swarm, tor, centos): the CLI tests
of svc-net-tor (onion:25 "socks CONNECT failed with reply 0x01") and
web-app-stalwart (probe_mail relay: ConnectionRefusedError on port 25)
failed. dockerd on the manager had aborted the whole ingress program of
the mail stack:

  Failed to add ingress: failed to program ingress ports:
  failed to bind host port 0.0.0.0:993/tcp: address already in use

/proc/net/tcp named the squatter: 192.168.244.10:993 -> :2049, the
node's own NFS client. The mount carries no noresvport, so the kernel
drew a source port from the 665-1023 reserved window and landed on
imaps. None of 25/465/993/995/4190/8095 got a DNAT rule or a
docker-proxy listener while every other published port did, and
stalwart still reported healthy because its healthcheck runs inside the
container. 993 and 995 are the only published ports inside that window,
so this is luck of the draw on any NFS-backed swarm host that runs the
mail role.

mount_opts now emits noresvport. insecure on the kernel-flavor export is
the other half: kernel nfsd defaults to secure and answers a mount from
an unprivileged source port with EACCES. It reaches the kernel flavor
only; ganesha already accepts unprivileged clients.

What it costs: the next deploy of every existing NFS client sees a
pending opts change and remounts the shared state; a host-side job
holding that path at that instant fails loudly. A plain remount may keep
a running mount on its old reserved port until the next real mount.

Port of f46c4d0bab from feature/store-i18n, applied identically so the
later store-i18n -> main merge stays conflict-free.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:02:41 +01:00
kevinveenbirkenbach 8a19b024db Merge pull request #1265 from infinito-nexus/feature/sys-ctl-hlth-runtime/vulnerable-runtimes/1127
feat(sys-ctl-hlth-runtime): alert on EOL or unpatched PHP and missing PHP hardening
2026-10-30 22:45:25 +01:00
kevinveenbirkenbach 4f8661ec19 Merge pull request #1306 from infinito-nexus/update/version-sources-web-app-gitea-20261030-01d3535
update(versions): update pins with a declared source (web-app-gitea)
2026-10-30 22:30:58 +01:00
infinito-nexus-updater[bot] 6a9c788d23 update(versions): update pins with a declared source (web-app-gitea) 2026-10-30 21:23:14 +00:00
kevinveenbirkenbach f8da96b01e Merge pull request #1305 from infinito-nexus/fix/tests/codeql-unused-project-root
fix(tests): resolve CodeQL unused PROJECT_ROOT in two test packages
2026-10-30 21:15:39 +01:00
kevinveenbirkenbach 2507f7584b Merge remote-tracking branch 'origin/main' into fix/tests/codeql-unused-project-root 2026-10-30 21:10:23 +01:00
kevinveenbirkenbachandClaude Opus 5.5 cb18214760 fix(tests): resolve CodeQL unused PROJECT_ROOT in two test packages
CodeQL py/unused-global-variable flagged two test package inits
(code-scanning alerts #1068 and #1072):

- tests/unit/python/roles/web-app-fider/__init__.py exports PROJECT_ROOT
  to test_tenant_bootstrap_gate.py through `from . import PROJECT_ROOT`
  but declared no __all__. Declare it, as every other test package
  that re-exports PROJECT_ROOT does.
- tests/unit/python/roles/sys-front-tls/__init__.py defined a
  PROJECT_ROOT nothing imports: the only test lives in templates/, whose
  own __init__.py provides it. Leave the role-level package init empty,
  like the other role-level test packages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 21:10:21 +01:00
kevinveenbirkenbach 76a60065fc Merge pull request #1295 from infinito-nexus/fix/ci/deploy-disable-union
fix(ci): merge the matrix row's disable tokens with the caller's list
2026-10-30 20:48:00 +01:00
kevinveenbirkenbach 91e444dcca Merge pull request #1304 from infinito-nexus/fix/web-app-mailu/lifecycle-eol
fix(web-app-mailu): set the role's lifecycle to eol
2026-10-30 20:17:22 +01:00
kevinveenbirkenbachandClaude Opus 5.5 193e7d4463 fix(web-app-mailu): set the role's lifecycle to eol
Mailu is superseded by web-app-stalwart and the project no longer
maintains it. Its OIDC flavor runs the archived heviat/Mailu-OIDC images
(the webmail ships Roundcube 1.6.9 and PHP 8.3.15), and its unbound
sidecar fails DNS since the root KSK rollover (#1303). Rather than fix
a role on its way out, mark it end of life:

- meta/services.yml: lifecycle deprecated -> eol. The updater and the
  image mirror now skip the role (the mirrored image set drops from
  189 to 188 entries), and default CI keeps excluding it as before.
- README.md: the banner now states that the project neither maintains
  nor tests the role, that operators use it at their own risk, and
  links upstream Mailu for support, as lifecycle.md requires for eol.
  The migration pointer to web-app-stalwart stays.
- web-app-stalwart README: "deprecated" becomes "end-of-life".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 20:10:49 +01:00
kevinveenbirkenbach bad992a537 Merge remote-tracking branch 'origin/main' into feature/sys-ctl-hlth-runtime/vulnerable-runtimes/1127 2026-10-30 18:47:55 +01:00
kevinveenbirkenbachandClaude Opus 5.5 a2e91a6158 fix(sys-ctl-hlth-runtime): run the check after every app container exists
hlth-runtime set system_service_force_flush_final: false. In debug mode
(CI) that makes sys-service start the unit as soon as the role is
included, so whether the check saw the app containers depended on where
the role landed in the play: in CI run 41023277637 SuiteCRM#0 and
Nextcloud#4 had their containers up first (suitecrm started 11:46:28,
check 11:49:02), while FusionDirectory#0 in the run before checked
before its containers existed and passed without inspecting anything.
In production (SYS_SERVICE_ALL_ENABLED false) the unit never ran during
a deploy at all, only from its timer.

Put it on the final run list like every other health check that
inspects containers (hlth-container, hlth-volumes, hlth-csp,
hlth-webserver, hlth-disc-space, hlth-btrfs): sys-service-terminator
starts it once all apps are deployed, so a runtime below its floor
fails the deploy deterministically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 18:47:50 +01:00
kevinveenbirkenbach 85febdf3d7 Merge pull request #1297 from infinito-nexus/fix/sys-svc-webserver-core/proxy-worker-limits
fix(sys-svc-webserver-core): size proxy workers from the proxy alone
2026-10-30 17:40:49 +01:00
kevinveenbirkenbach df98ebbd36 Merge pull request #1302 from infinito-nexus/fix/web-app-openproject/swarm-seeder-wait
fix(web-app-openproject): wait for the swarm seeder and detect dead DB sockets
2026-10-30 17:39:44 +01:00
kevinveenbirkenbach 35f7505dc9 Merge pull request #1301 from infinito-nexus/fix/svc-bkp-volume-2-local/restore-into-resolved-mountpoint
fix(svc-bkp-volume-2-local): restore into the resolved volume mountpoint
2026-10-30 17:38:59 +01:00
kevinveenbirkenbach bc0af0e9dc Merge pull request #1299 from infinito-nexus/update/docker-image-versions-web-app-funkwhale-20261030-863dbb9
update(images): update Docker image versions (web-app-funkwhale)
2026-10-30 17:31:59 +01:00
infinito-nexus-updater[bot] 9c1969e97c update(images): update Docker image versions (web-app-funkwhale) 2026-10-30 15:54:01 +00:00
kevinveenbirkenbach c5ee33def3 Merge remote-tracking branch 'origin/main' into fix/web-app-keycloak/admin-network-allowlist/1121 2026-10-30 16:52:08 +01:00
kevinveenbirkenbachandClaude Opus 5.5 2393e8ddba fix(web-app-keycloak): reject scoped IPv6 admin networks, drop module docstring
Addresses two CodeRabbit findings on PR #1261.

1. Scoped IPv6 (thread 4421596356): ipaddress.ip_network accepts a scope
   ID, so `fe80::1%eth0` resolved to `fe80::1%eth0/128` and the vhost
   would carry `allow fe80::1%eth0/128;`, which nginx refuses to load.
   kc_admin_networks now raises AnsibleFilterError for any entry whose
   network address carries a scope ID. test_admin_allowlist.py covers a
   scoped address and a scoped CIDR; both fail against the previous
   filter.
2. Module docstring (thread 4421596351): removed; it described the
   module instead of documenting parameters or a trip-wire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:52:06 +01:00
kevinveenbirkenbach e995d9c008 Merge remote-tracking branch 'origin/main' into fix/web-app-openproject/swarm-seeder-wait 2026-10-30 16:51:58 +01:00
kevinveenbirkenbachandClaude Opus 5.5 2d80ad5f1b fix(web-app-openproject): wait for the swarm seeder and detect dead DB sockets
Compose gates web, worker and cron on the seeder via depends_on
service_completed_successfully. Swarm ignores depends_on, so nothing
waited for the one-shot seeder there. In CI (store-i18n run 40979252521,
OpenProject#0 swarm) an overlay flap reset the seeder's Postgres
connection; Postgres rolled back RootSeeder's transaction, but the
seeder never noticed and sat idle on the dead socket forever
("Executing database seed..."). No UserCustomFieldSection rows were
committed, so /my/account rendered without fieldsets and the deploy
still reported green.

- 01_manager_ops.yml: in swarm, after the handler flush deploys the
  stack, poll job_state.sh on the seeder service until its newest task
  is Complete (fail on Shutdown, give up after 20 minutes), mirroring
  web-app-zammad's init-job wait. Compose keeps relying on depends_on.
- env.j2: add libpq TCP keepalives (idle 60s, interval 10s, count 6)
  and tcp_user_timeout=120000 to DATABASE_URL, so a connection whose
  peer vanished errors out within about two minutes instead of hanging.
  The seeder then exits non-zero and swarm's on-failure restart policy
  reruns the seed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:51:56 +01:00
kevinveenbirkenbach ed1fbbed76 Merge remote-tracking branch 'origin/main' into fix/svc-bkp-volume-2-local/restore-into-resolved-mountpoint 2026-10-30 16:51:47 +01:00
kevinveenbirkenbachandClaude Opus 5.5 b894db0a75 fix(svc-bkp-volume-2-local): restore into the resolved volume mountpoint
rsync 3.5.0 (Debian security update 3.5.0+ds1-0+deb13u1) refuses a
destination symlink owned by neither root nor the calling user.
svc-opt-ssd-hdd turns a volume's `_data` into a symlink to /mnt/hdd or
/mnt/ssd. The restore drill empties the volume and runs `compose create`;
docker repopulates it and lchowns the `_data` symlink to the image
directory's owner (e.g. www-data). The restore then failed with
"refusing to follow a symlink owned by an untrusted user" and
"change_dir#1 .../_data/ failed: Too many levels of symbolic links",
the drill left its subjects down, and the dependent checks timed out
(CI run 40979252521, ssd-hdd#0, on feature/store-i18n; recover.py is
identical on main).

VolumeRecovery now resolves the mountpoint before handing it to rsync:
os.path.realpath locally, `ssh <host> realpath -e -- <mountpoint>` for
--docker-host, so rsync writes into the real directory and never meets
the symlink. `--insecure-links` was not used because older rsync builds
on other distributions lack it. Two new unit tests (local symlinked
mountpoint, remote resolution); both fail against the previous code.

Root cause and fix by the i18n session (feature/store-i18n triage of
ssd-hdd#0), ported to main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:51:44 +01:00
kevinveenbirkenbach 143873a54e Merge pull request #1296 from infinito-nexus/update/docker-image-versions-web-app-funkwhale-20261030-f4a2d75
update(images): update Docker image versions (web-app-funkwhale)
2026-10-30 15:20:00 +01:00
infinito-nexus-updater[bot] f0513f32d7 update(images): update Docker image versions (web-app-funkwhale) 2026-10-30 13:55:43 +00:00
kevinveenbirkenbach 8c2ee35911 Merge remote-tracking branch 'origin/main' into fix/sys-svc-webserver-core/proxy-worker-limits 2026-10-30 14:53:59 +01:00
kevinveenbirkenbachandClaude Opus 5.5 69a0dfa9b9 fix(sys-svc-webserver-core): size proxy workers from the proxy alone
The shared OpenResty nginx.conf took worker_processes and worker_connections
from WEBSERVER_WORKER_*, which are the min() of svc-prx-openresty's limits and
the current play's application_id. The file renders once, in the scope of
whichever role loads the proxy first, so that role's limits capped every vhost:
on feature/store-i18n web-svc-mirror (pids_limit 64) loaded it first, every
vhost got worker_connections 64, and openresty raised 555 "64
worker_connections are not enough while connecting to upstream" alerts while a
single openwebui page fires ~150-170 chunk requests (CI run 40979252521,
homeassistant#1). Main carries the same wiring.

Add WEBSERVER_PROXY_WORKER_PROCESSES and WEBSERVER_PROXY_WORKER_CONNECTIONS,
computed from svc-prx-openresty's own openresty service only (same
resource_filter fallbacks, at least one worker), and render nginx.conf from
them. WEBSERVER_WORKER_* keep pairing the proxy with the play for app-internal
nginx such as Nextcloud's. The values can only stay equal or rise.

Found by the i18n session's triage of homeassistant#1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:53:54 +01:00
kevinveenbirkenbach 22ff50c9b1 Merge pull request #1294 from infinito-nexus/fix/web-app-akaunting/stale-php81-todo/1119
docs(web-app-akaunting): drop the stale PHP 8.1 to-do
2026-10-30 14:20:30 +01:00
kevinveenbirkenbach bfeeb948ac Merge pull request #1289 from infinito-nexus/update/docker-image-versions-web-app-socialhome-20261030-76d61fd
update(images): update Docker image versions (web-app-socialhome)
2026-10-30 12:00:43 +01:00
kevinveenbirkenbachandClaude Opus 5.5 204aa37278 fix(ci): merge the matrix row's disable tokens with the caller's list
Both deploy steps set `disable: ${{ matrix.disable || inputs.disable }}`.
A row carries tokens of its own whenever its network mode needs them (a
clearnet row disables Tor), so the caller's list never reached the
deploy. On feature/store-i18n (CI run 40979252521) the workspace swarm
zombie for svc-db-mariadb/postgres deployed 19 apps instead of 7 on its
clearnet row (fedora: 4h06 for one step, job cancelled at 345 min). main
carries the same expression; it bites as soon as a caller's disable list
meets a clearnet row.

The steps now pass format('{0} {1}', matrix.disable, inputs.disable);
every reader of `disable` splits on spaces and commas. Both input
descriptions follow. test_deploy_disable_merge.py reads the live
expressions; against the old fallback it fails two subtests.

Ported from feature/store-i18n 57e574ac2d (store-i18n's extra `network:`
step env stays there).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:13:55 +01:00
kevinveenbirkenbachandClaude Opus 5.5 d3f3800ed8 docs(web-app-akaunting): drop the stale PHP 8.1 to-do
The role builds akaunting/docker at master. Upstream moved that
Dockerfile to `FROM php:8.2.35-apache` (akaunting/docker#123, merged
2026-10-26), a release with the fixes for CVE-2026-109618 and
CVE-2026-109619, so the to-do that asked to move off PHP 8.1.34 no
longer describes the image the role builds.

Closes #1119

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 10:27:34 +01:00
kevinveenbirkenbach 13a7753e09 Merge pull request #1293 from infinito-nexus/fix/web-app-matrix/element-force-verification-variant-1
fix(web-app-matrix): turn off Element's forced verification in variant 1
2026-10-30 09:19:32 +01:00
kevinveenbirkenbach 9da596aab8 Merge remote-tracking branch 'origin/main' into fix/web-app-matrix/element-force-verification-variant-1 2026-10-30 09:17:08 +01:00
kevinveenbirkenbachandClaude Opus 5.5 df00ff0abf fix(web-app-matrix): turn off Element's forced verification in variant 1
4a56b4c19c set services.element.force_verification to false only for
the SSO variants 0 and 2, on the reasoning that only the SSO specs log
the same account in twice. The deploy's second pass logs the variant 1
administrator (ansible flavor, SSO off, password login) in again. PASS 1
bootstraps the account's cross-signing identity, so in PASS 2 Element
stops on "Confirm your digital identity" ("Use another device" / "Can't
confirm?" / "Remove this device", no skip), and the password-login spec
times out at _shared.js:436 (fork run 40979252521, job 123823820263,
Discourse#1 with web-app-matrix variant 1, all three retries).

Variant 1 now sets force_verification to false like the other two. The
services.yml default stays true, so production keeps forced
verification. No variant exercises true end to end any more; the
follow-up issue restores one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:17:06 +01:00
kevinveenbirkenbach a81967fb66 Merge pull request #1290 from infinito-nexus/fix/web-app-bigbluebutton/apps-akka-transaction-isolation
fix(web-app-bigbluebutton): pin apps-akka's transaction isolation
2026-10-30 09:16:42 +01:00
kevinveenbirkenbach 1f87c98eca Merge pull request #1291 from infinito-nexus/fix/web-app-fusiondirectory/php-memory-unlimited
fix(web-app-fusiondirectory): lift the PHP memory_limit in the FPM pool
2026-10-30 09:14:00 +01:00
kevinveenbirkenbach facb27e86e Merge remote-tracking branch 'origin/main' into fix/web-app-fusiondirectory/php-memory-unlimited 2026-10-30 08:57:49 +01:00
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
kevinveenbirkenbach 6bca206c16 Merge remote-tracking branch 'origin/main' into fix/web-app-bigbluebutton/apps-akka-transaction-isolation 2026-10-30 08:57:36 +01:00
kevinveenbirkenbachandClaude Opus 5.5 c1ff8e5d11 fix(web-app-bigbluebutton): pin apps-akka's transaction isolation
At BBB boot, bbb-graphql-server's start.sh runs pg_terminate_backend and
drops bbb_graphql. When that kills apps-akka's first HikariCP connection
while the pool detects the driver's default transaction isolation,
HikariCP 4.0.3 swallows the 08xxx error, marks detection as done and
keeps isolation -1 for the pool's lifetime. Every later connection setup
then calls setTransactionIsolation(-1), which pgjdbc rejects with
"Transaction isolation level -1 not supported", so meetings never reach
the database and the client shows "Oops" (about 1 in 8 boots).

Pin the isolation explicitly so HikariCP never falls back to the
detected value: slick-hikaricp reads postgres.transactionIsolation,
prepends TRANSACTION_ and hands it to HikariCP, hence the value must be
exactly READ_COMMITTED (the PostgreSQL default, so normal boots behave
as before). The flag goes into apps-akka's own compose environment as
JAVA_OPTS, which the sbt-native-packager start script honours, instead
of env.j2, because compose_mods pins env.j2 onto every bbb service and
would hand the flag to bbb-web and fsesl-akka as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 08:57:32 +01:00
kevinveenbirkenbach 85f47fdbf8 Merge remote-tracking branch 'origin/main' into feature/sys-ctl-hlth-runtime/vulnerable-runtimes/1127 2026-10-30 08:57:26 +01:00
kevinveenbirkenbachandClaude Opus 5.5 284b0873dd fix(sys-ctl-hlth-runtime): harden LAM CLI, catch apk options, drop vars comment
Addresses three CodeRabbit findings on PR #1265.

1. LAM hardening invisible to the probe (thread 4413764929): the runtime
   check probes PHP with `php -r`, the CLI SAPI. web-app-lam mounted the
   hardening ini only into /etc/php/8.4/apache2/conf.d, which the Debian
   CLI does not scan, so the probe read unhardened CLI settings and the
   check failed for LAM. The php_hardening entry now also mounts the ini
   into /etc/php/8.4/cli/conf.d. No other role mounts it into a Debian
   per-SAPI directory; the rest use the shared scan dir of the official
   image or of Alpine. The TODO entry now names the remaining gap: the
   probe reads only the CLI copy.

2. Explanatory comment above HEALTH_RUNTIME_FLOORS (thread 4413764949):
   removed. The README already states the end-of-life rule and now also
   defines a floor as the lowest patched release of each line.

3. `apk --no-cache add` missed (thread 4415018662): PACKAGE_INSTALL_PATTERN
   required `add` right after `apk`, so `RUN apk --no-cache add php7`
   passed as an image without PHP. The apk branch now accepts options
   before `add`, like the apt branch. New tests cover the option form and
   guard that `apk` in a path or a comment is no package install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 08:57:21 +01:00
kevinveenbirkenbach bbe75cf4ed Merge remote-tracking branch 'origin/main' into fix/web-app-keycloak/admin-network-allowlist/1121 2026-10-30 08:57:15 +01:00