feat(images): upgrade lsphp from the LiteSpeed repo at build time; label PHP version

cac-litespeed and cac-lsphp start FROM litespeedtech/openlitespeed:1.8.4-lsphpNN,
which ships lsphp85 8.5.0 / lsphp84 8.4.15 (built 2025-12). lsphp only moved
forward as a side effect of installing lsphpNN-ldap. lsphp-apt-upgrade.sh now
sweeps every installed lsphpNN* package (and OS packages) to the repo's current
release on every build and fails the build if the repo is unreachable or the
result doesn't match what CI resolved from the repo index. CI passes a per-run
CACHE_BUST so the upgrade layer is never a cache hit, and images carry
org.whp.php-version / org.whp.lsphp-package-version labels.

Tested on .148 (2026-10-21): cac-lsphp php85/php84 and cac-litespeed php85 built
from this branch report the same PHP (8.5.11 / 8.4.26), identical module lists
and OLS 1.8.4 as the current registry images; with the hardening flags each
serves/runs PHP as the customer uid, restarts, and stops cleanly (exit 0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shadowdaoandClaude Opus 5.5 committed 2026-10-21 06:07:48 -07:00
1 parent 74e12407f8
commit 71ca114529
6 files changed
+242 -10

No files matched your search

+97
View File
@@ -0,0 +1,97 @@
#!/bin/bash
## lsphp-apt-upgrade.sh — BUILD-TIME ONLY. Brings every installed lsphp${PHPVER}*
## package (and, by default, the Ubuntu OS packages) up to what the repos offer
## RIGHT NOW, then proves it.
##
## Why this exists: cac-litespeed / cac-lsphp start FROM the LiteSpeed prebuilt
## image litespeedtech/openlitespeed:<OLS>-lsphpNN, which LiteSpeed republishes
## rarely (the 1.8.4 tags were built 2025-12-16 and ship lsphp85 8.5.0 /
## lsphp84 8.4.15, measured 2026-10-21, while rpms.litespeedtech.com/debian
## offers 8.5.11 / 8.4.26). The base image already carries that apt repo, so a
## PHP security release reaches us the moment LiteSpeed publishes the .deb —
## provided every build actually asks for it. Before this script the lsphp core
## only moved forward as a SIDE EFFECT of `apt-get install lsphpNN-ldap` (whose
## exact-version dependency on lsphpNN-common drags the family along); lsphp
## extension packages without that coupling (e.g. lsphpNN-msgpack) and every
## Ubuntu package stayed at the base image's December versions.
##
## Fails LOUDLY — never ships the base image's PHP by accident:
## * `apt-get update --error-on=any`: plain `apt-get update` only WARNS when a
## repo is unreachable and carries on with no/old lists, exit 0.
## * the LiteSpeed repo must be the candidate source for lsphp${PHPVER}.
## * after upgrading, no lsphp${PHPVER}* package may remain upgradable.
## * if CI passed the version it resolved from the repo index (EXPECT_LSPHP_PKG,
## EXPECT_PHP_VERSION), the installed package / running PHP must match it;
## that same value becomes the image LABEL, so the label cannot lie.
##
## Usage: lsphp-apt-upgrade.sh [--no-os-upgrade] PHPVER [extra apt packages / pkg=ver pins...]
## Extra packages are installed in the same transaction set (after the OS
## upgrade, before the lsphp sweep). Does NOT clean apt lists — the caller
## decides (multi-stage builders want them; shipped layers delete them).
set -euo pipefail
OS_UPGRADE=1
if [ "${1:-}" = "--no-os-upgrade" ]; then OS_UPGRADE=0; shift; fi
PHPVER="${1:?usage: lsphp-apt-upgrade.sh [--no-os-upgrade] PHPVER [pkgs...]}"
shift
export DEBIAN_FRONTEND=noninteractive
APT=(apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold)
LSPHP="/usr/local/lsws/lsphp${PHPVER}/bin/lsphp"
PHPCLI="/usr/local/lsws/lsphp${PHPVER}/bin/php"
die() { echo "FATAL(lsphp-apt-upgrade): $*" >&2; exit 1; }
echo "lsphp-apt-upgrade: PHPVER=${PHPVER} os_upgrade=${OS_UPGRADE} cache_bust=${CACHE_BUST:-<none>}"
echo "lsphp-apt-upgrade: base image lsphp${PHPVER}=$(dpkg-query -W -f='${Version}' "lsphp${PHPVER}" 2>/dev/null || echo none)"
"${APT[@]}" update --error-on=any || die "apt-get update failed (repo unreachable?). Refusing to build with stale package lists."
# The candidate for lsphpNN must come from the LiteSpeed repo — not "none", and
# not merely whatever is already installed.
if ! apt-cache madison "lsphp${PHPVER}" | grep -q 'rpms.litespeedtech.com'; then
apt-cache policy "lsphp${PHPVER}" >&2 || true
die "the LiteSpeed apt repo does not offer lsphp${PHPVER} (repo missing from sources, or its index is empty)."
fi
CAND=$(apt-cache policy "lsphp${PHPVER}" | awk '/Candidate:/ {print $2; exit}')
echo "lsphp-apt-upgrade: repo candidate lsphp${PHPVER}=${CAND}"
if [ "$OS_UPGRADE" = 1 ]; then
# --with-new-pkgs: let an upgrade pull in a new dependency instead of being
# silently "kept back". Never removes packages (that would be dist-upgrade).
"${APT[@]}" upgrade --with-new-pkgs
fi
if [ $# -gt 0 ]; then
"${APT[@]}" install --no-install-recommends "$@"
fi
# Sweep EVERY installed lsphpNN* package (core + all extensions) to the candidate.
mapfile -t PKGS < <(dpkg-query -W -f='${db:Status-Abbrev} ${Package}\n' "lsphp${PHPVER}*" 2>/dev/null | awk '$1 == "ii" {print $2}')
[ "${#PKGS[@]}" -gt 0 ] || die "no lsphp${PHPVER}* packages installed — wrong base image?"
"${APT[@]}" install --only-upgrade --no-install-recommends "${PKGS[@]}"
LEFT=$(apt list --upgradable 2>/dev/null | grep "^lsphp${PHPVER}" || true)
[ -z "$LEFT" ] || die "lsphp packages still upgradable after the sweep:
$LEFT"
INST=$(dpkg-query -W -f='${Version}' "lsphp${PHPVER}")
RUNV=$("$PHPCLI" -r 'echo PHP_VERSION;') || die "lsphp${PHPVER} CLI does not run"
if [ -n "${EXPECT_LSPHP_PKG:-}" ] && [ "$INST" != "$EXPECT_LSPHP_PKG" ]; then
die "installed lsphp${PHPVER}=$INST but CI resolved $EXPECT_LSPHP_PKG from the repo index (repo changed mid-build? re-run)."
fi
if [ -n "${EXPECT_PHP_VERSION:-}" ] && [ "$RUNV" != "$EXPECT_PHP_VERSION" ]; then
die "lsphp${PHPVER} reports PHP $RUNV but the image will be labelled $EXPECT_PHP_VERSION."
fi
if [ -z "${EXPECT_PHP_VERSION:-}" ]; then
echo "lsphp-apt-upgrade: WARNING no EXPECT_PHP_VERSION build-arg — image label will read 'unverified' (fine for local builds; CI always sets it)." >&2
fi
printf '%s\n' "$RUNV" > /etc/cac-php-version
echo "lsphp-apt-upgrade: ===== version report ====="
dpkg-query -W -f=' ${Package} ${Version}\n' "lsphp${PHPVER}*"
echo " lsphp -v: $("$LSPHP" -v | head -n1)"
echo " OS packages still upgradable: $(apt list --upgradable 2>/dev/null | grep -vc '^Listing' || true)"
echo "lsphp-apt-upgrade: OK lsphp${PHPVER}=${INST} (PHP ${RUNV})"