Commit Graph
5 Commits
Author SHA1 Message Date
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
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
kevinveenbirkenbachandClaude Opus 5.5 d116dde659 fix(sys-ctl-hlth-runtime): bound the engine calls and catch hidden PHP runtimes
Three CodeRabbit findings on PR #1265:

- script.py listed the running containers with `container ps` and
  `container inspect` without a timeout, so a hung engine kept the daily
  unit active forever and blocked the next timer run. Both calls now use
  EXEC_TIMEOUT_SECONDS; main turns a timeout or engine error into a
  one-line failure and exit 1 instead of a traceback.

- runtime.py's PHP_PACKAGE_PATTERN requires a digit after "php", so an
  image installing an unversioned interpreter package (`php-cli`) and
  setting no PHP_VERSION was reported as PHP-free. The interpreter
  packages php, php-cli, php-fpm, php-cgi, php-phpdbg and
  libapache2-mod-php are now recorded as PhpRuntime.packages and reported
  with an unknown patch level; extension and library packages
  (php-mysql, php-pear, php-common, phpmyadmin) and paths do not count.

- php_finding returned early for a patched PHP_VERSION, so an end-of-life
  package line installed next to it (e.g. php7) was never reported. The
  version only returns a finding now; otherwise the lines are judged too.

Every finding has unit tests that fail on the previous code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:32:57 +01:00
kevinveenbirkenbachandClaude Opus 5.5 feac35a5ea fix(sys-ctl-hlth-runtime): deploy only on container hosts and drop the bare Docker Hub API literal
Two CI failures on PR #1265 (run 40834164415):

- Chunk 0 / SuiteCRM#2 (swarm): the post-load flush included
  sys-ctl-hlth-runtime on every play host, the NFS server too, which never
  gets sys-svc-container and therefore has no `container` CLI. The unit
  died with FileNotFoundError: 'container'. The role entry now runs only
  where a container runtime exists: in compose mode, or on swarm nodes
  ('svc-swarm-node' in group_names), the same role-entry host scoping that
  sys-ctl-hlth-csp and sys-ctl-hlth-webserver use with IS_STACK_HOST.
  Workers stay covered because PHP replicas can run there.

- Workspace (ubuntu): tests/external/repository/test_urls_reachable.py
  probed the literal "https://hub.docker.com/v2" from
  utils/docker/image/runtime.py:20 and got HTTP 404. The constant is gone;
  the endpoint is written as one f-string at the call site, the way
  utils/update/docker.py:104 and utils/update/source.py do, which the URL
  test skips as a template. With the scheme now visible in the literal,
  ruff reported the noqa: S310 on urllib.request.Request as unused.

Both test files that imported unittest twice (CodeQL) now use one
`from unittest import ...` form.

The run_once queue leak that spreads the stack host's post-load queue to
every host is fixed separately on the updater line (70ed8a2e98); when it
meets main, sys-ctl-hlth-runtime moves into sys-svc-container's queue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 11:47:41 +01:00
kevinveenbirkenbachandClaude Opus 5.5 3c743736a8 feat(sys-ctl-hlth-runtime): alert on EOL or unpatched PHP and missing PHP hardening
Answering "which deployed containers run a vulnerable PHP?" after
CVE-2026-109618/109619 took a manual inventory of registry metadata, and
nothing noticed a hardening ini that an image never loads.

- New role sys-ctl-hlth-runtime, routed through sys-svc-compose next to
  sys-ctl-hlth-container. A daily timer runs `php` in every running
  container and fails, alerting through sys-ctl-alm-compose, when PHP is
  below the floor of its line or on a line older than every floor (7.4,
  8.1). Every service that mounts php_hardening in meta/volumes.yml fails
  while expose_php or session.upload_progress.enabled is on; other PHP
  containers of such a stack are listed as info. Compose and swarm
  containers are matched by their project/stack and service labels. The
  check is not run at deploy time, so a finding never fails a deploy.
- The floors (8.2.35, 8.3.36, 8.4.27, 8.5.12) live once, in
  HEALTH_RUNTIME_FLOORS of the role's vars/main.yml.
- `make security-runtimes` lists the PHP of every pinned role image
  without pulling: Docker Hub tags through the Hub API, which no pull rate
  limit meters, other registries through the OCI config blob (new
  registry.config_blob, which the healthcheck probe now reuses).
  PHP_VERSION, distro PHP packages and a PHP_BASE build argument count. It
  exits 1 on an image below its floor or one the registry did not answer.
  Today it flags nfrastack/fusiondirectory:1.5 (line 7.4) and
  shopware/docker-base:8.3 (8.3.25).

The role TODO.md keeps the follow-ups: further runtimes, the split web
SAPI of web-app-lam, a scheduled CI run of the report and the CVE scan.

Refs #1127

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 00:12:25 +01:00