With the pkg-cache BuildKit mirror on, `FROM almalinux/10-base` was resolved
by tag through the cache, so a compromised cache could substitute the image.
Each job using the mirror now looks up the base tag's digest DIRECTLY at
registry-1.docker.io (.gitea/scripts/resolve-base-image.sh, HTTPS, HEAD on
the manifest, regex-validated) and builds FROM image@sha256:... via the
BASE_IMAGE build-arg, so the mirror can only serve content-addressed blobs.
If the lookup fails, the mirror is NOT used for that job and the tag is pulled
straight from Docker Hub. The digest is resolved every run (no manual bumps);
local builds default to the tag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- build-push.yaml: Build-and-Push, Build-FPM-Images, Build-Shared-httpd
and Build-Shared-OLS probe https://192.168.1.40 and :5000 with the
pinned pkg-cache CA (5 s timeouts). When the cache answers they pass
PKG_CACHE and configure the BuildKit Docker Hub mirror (ca=). When it
doesn't, they build from upstream exactly as before and emit a warning.
Fallback measured from the runner bridge: refused <1 s, silent drop 10 s.
- scripts/host/pkgcache-host-repos.sh: apply/revert/status for WHP hosts.
Each rewritten repo uses baseurl=<cache> <origin> as the real fallback;
mirrorlist/metalink stay commented because measured dnf ignores baseurl
when they are present. Keeps gpgcheck=1 / repo_gpgcheck=1 and backs up
every file. Tested on 192.168.1.148, including cache-down and
silent-drop fallback.
- docs: runner firewall rule (applied), measured fallback results.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Security review follow-up for the opt-in PKG_CACHE path:
- PKG_CACHE must be https:// (http is refused). The cache's certificate
comes from a name-constrained internal CA (keys/pkg-cache/ca.crt, valid
only for 192.168.1.40 / pkg-cache.*). The CA is trusted only by the
rewritten repos (dnf sslcacert bundle, apt per-host CaInfo) and only
for the duration of the RUN.
- epel-release / remi-release are no longer installed straight from a
URL. release-install downloads them over HTTPS, checks the package name,
imports the signing keys committed in keys/pkg-cache/ and requires
`rpm -K` "signatures OK", then installs with localpkg_gpgcheck=1. This
applies with and without the cache.
- Rewritten repos get gpgcheck=1. Remi and AlmaLinux also get
repo_gpgcheck=1, since both sign repomd.xml. EPEL does not publish a
repomd signature, so it relies on end-to-end HTTPS.
- restore also deletes files it created and any new repo/apt file that
still references the cache, then fails the build if a reference remains
under /etc/yum.repos.d, /etc/dnf or /etc/apt.
- docs: trust model, replay risk, proposed openssl/httpd/ImageMagick
minimum-version gates, TLS registry mirror (BuildKit ca= / dockerd
certs.d, no insecure-registries).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds scripts/pkg-cache-repos.sh and wires it into Dockerfile,
Dockerfile.fpm, Dockerfile.shared-httpd and Dockerfile.shared-ols. With
--build-arg PKG_CACHE=http://192.168.1.40 (CT130 pkg-cache), dnf/apt go
through the LAN cache. That cache fetches from the Remi/EPEL/AlmaLinux/
Ubuntu/LiteSpeed origins over HTTPS, with fallback tiers and
stale-on-error. Without the arg the script is a no-op and builds are
unchanged.
- rpm: each baseurl becomes "<cache>/<prefix>/... <origin>/...", so dnf
fails over to the origin if the cache dies mid-build
- every RUN restores the original repo files before it ends, so no
shipped layer carries the LAN address
- EPEL/Remi release RPMs come from the cache when it is set
- the php.net version gates are untouched
Dockerfile.litespeed/.lsphp are not wired yet (see docs/pkg-cache.md).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For when a PHP security release is out and the LiteSpeed apt repo lags
(2026-10-21: php2shell CVE-2026-109618/-109619 fixed in 8.2.35/8.3.36/
8.4.27/8.5.12, LiteSpeed still on 8.2.34/8.3.35/8.4.26/8.5.11).
Dockerfile.lsphp / Dockerfile.litespeed gain an `lsphp-src` stage that is
idle unless PHP_SRC_VERSION is set; normal builds are unchanged (measured:
module list, file manifest, ldd, ini and dpkg identical to the published
images).
When set (lsphp-src-build.sh):
- tarball sha256 (php.net releases JSON) + OpenPGP signature against the
committed php.net keyring, signer pinned per branch
- configure flags replayed from the packaged lsphp's own Configure Command
- LiteSpeed's php-litespeed-8.3 SAPI (what the packages actually compile,
measured) instead of php-src's sapi/litespeed; sha256-pinned and checked
against the packaged binary's LSAPI_* names
- packaged compiled-in ini defaults reproduced (session.save_path on 8.2/
8.3) and gated (`php -n` diff)
- ABI gate (lsphp-abi-gate.sh, pahole) before reusing LiteSpeed's packaged
PECL .so files; regression-tested in Shell-Checks
lsphp-src-overlay.sh swaps only php-src-owned files (decided by dpkg) and
fails the build unless extensions, versions, effective ini and feature
lines match the packaged lsphp under both CLI and litespeed SAPIs.
CI: lsphp-source-emergency.yaml (workflow_dispatch only). build-push.yaml
refuses to overwrite a newer php.net image with an older packaged one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two judgement calls arising from the pipefail/SIGPIPE fix, reasoned through
and written up rather than decided silently:
1. Boot posture when 'lsphp -i' genuinely fails. Recommendation is fail-open
plus a machine-detectable degraded marker and one probe retry, NOT
fail-closed: a transient fork() failure during this fleet's backup windows
produces the identical empty-LSPHP_INFO signature, so fail-closed would
refuse to boot healthy sites under host pressure. Includes the caution
that degraded must not map onto Docker 'unhealthy', or a watchdog would
restart-loop a serving site over something restarts cannot fix.
Corrects a premise the fix rested on: the two entrypoints were NOT already
consistent — entrypoint-litespeed.sh fails open silently, with no warning.
2. Whether the new static check should gate releases. Recommendation is to
hard-gate, but only after back-testing the job against trunk and recent
tags to bound false positives.
Recommendations only; no implementation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>