Opt-in PKG_CACHE build arg pointing dnf/apt at the internal package cache, CT130 pkg-cache, https://192.168.1.40. Without the arg, builds use upstream repositories as before. The one change in that path is that the release RPMs are now GPG-verified. Update 2026-10-21 (Josh approved):
The runner firewall exception is applied on pve and pve3 (443/5000 to 192.168.1.40 only) and verified from the runner bridges.
The workflow now enables PKG_CACHE through a TLS probe with measured fall-back: <1 s when the cache is refused, 10 s on a silent drop.
Added scripts/host/pkgcache-host-repos.sh for WHP hosts, tested on .148 including cache-down fall-back.
See docs/pkg-cache.md.
What changes
scripts/pkg-cache-repos.sh, with four modes:
rpm: rewrites AlmaLinux/EPEL/Remi baseurls to <cache> <origin> (dnf fails over to the origin), adds a scoped sslcacert, gpgcheck=1, and repo_gpgcheck=1 for Remi and AlmaLinux.
apt: rewrites Ubuntu and LiteSpeed URIs and sets a per-host CaInfo.
release-install: HTTPS download, package-name check, keys from keys/pkg-cache/, rpm -K must say "signatures OK", then localpkg_gpgcheck=1.
restore: puts back rewritten files, deletes created files and any new file referencing the cache, and fails if a reference remains.
The script is wired into Dockerfile, Dockerfile.fpm, Dockerfile.shared-httpd and Dockerfile.shared-ols. Dockerfile.litespeed and Dockerfile.lsphp are not wired yet (multi-stage plus the madison check; see docs).
keys/pkg-cache/:
the name-constrained pkg-cache CA (IP 192.168.1.40 / pkg-cache.* only);
the EPEL 10 key, with its fingerprint checked against fedoraproject.org/security;
the Remi 2024 key, checked only against Remi's own servers: fingerprint CF1D F005 7CE8 5DFF 5B2F 2A37 C2FD 3B2C 2A09 48E4confirmed by Josh.
docs/pkg-cache.md: cache rules, trust model, the CI plan (firewall exception, probe step, BuildKit mirror with ca=), the WHP host plan, and operations.
Tested on 192.168.1.193 (measured, 2026-10-21)
Build
Result
Dockerfile PHPVER=85, PKG_CACHE via http (first version), cold cache
the repo+update step alone took 1031.5 s (BaseOS 84 kB/s, remi-release 2.0 kB/s); then I killed the run by removing its builder, so a full completion was not observed
Opt-in `PKG_CACHE` build arg pointing dnf/apt at the internal package cache, **CT130 `pkg-cache`, https://192.168.1.40**. Without the arg, builds use upstream repositories as before. The one change in that path is that the release RPMs are now GPG-verified. **Update 2026-10-21 (Josh approved):**
- The runner firewall exception is applied on pve and pve3 (443/5000 to 192.168.1.40 only) and verified from the runner bridges.
- The workflow now enables `PKG_CACHE` through a TLS probe with measured fall-back: <1 s when the cache is refused, 10 s on a silent drop.
- Added `scripts/host/pkgcache-host-repos.sh` for WHP hosts, tested on .148 including cache-down fall-back.
See `docs/pkg-cache.md`.
## What changes
- `scripts/pkg-cache-repos.sh`, with four modes:
- `rpm`: rewrites AlmaLinux/EPEL/Remi `baseurl`s to `<cache> <origin>` (dnf fails over to the origin), adds a scoped `sslcacert`, `gpgcheck=1`, and `repo_gpgcheck=1` for Remi and AlmaLinux.
- `apt`: rewrites Ubuntu and LiteSpeed URIs and sets a per-host CaInfo.
- `release-install`: HTTPS download, package-name check, keys from `keys/pkg-cache/`, `rpm -K` must say "signatures OK", then `localpkg_gpgcheck=1`.
- `restore`: puts back rewritten files, deletes created files and any new file referencing the cache, and **fails** if a reference remains.
- The script is wired into `Dockerfile`, `Dockerfile.fpm`, `Dockerfile.shared-httpd` and `Dockerfile.shared-ols`. `Dockerfile.litespeed` and `Dockerfile.lsphp` are not wired yet (multi-stage plus the madison check; see docs).
- `keys/pkg-cache/`:
- the name-constrained pkg-cache CA (IP 192.168.1.40 / pkg-cache.* only);
- the EPEL 10 key, with its fingerprint checked against fedoraproject.org/security;
- the Remi 2024 key, checked only against Remi's own servers: fingerprint `CF1D F005 7CE8 5DFF 5B2F 2A37 C2FD 3B2C 2A09 48E4` **confirmed by Josh**.
- `docs/pkg-cache.md`: cache rules, trust model, the CI plan (firewall exception, probe step, BuildKit mirror with `ca=`), the WHP host plan, and operations.
## Tested on 192.168.1.193 (measured, 2026-10-21)
| Build | Result |
|---|---|
| `Dockerfile` PHPVER=85, PKG_CACHE via http (first version), cold cache | rc=0, 181 s; repo+update step 39.8 s; PHP 8.5.12, passed EXPECT_PHP_MIN=8.5.12 |
| same, warm, `--no-cache` | rc=0, 72 s |
| same, **no PKG_CACHE** (upstream) | the repo+update step alone took **1031.5 s** (BaseOS 84 kB/s, remi-release 2.0 kB/s); then I killed the run by removing its builder, so a full completion was not observed |
| `Dockerfile` PHPVER=85, **https** PKG_CACHE (final code), TLS registry mirror | rc=0, 89 s; release RPMs "digests signatures OK"; 3× "no reference to 192.168.1.40 left" |
| `Dockerfile.shared-ols` 1.8.4/85, https PKG_CACHE | rc=0, 26 s (http version: 41 s cold, 15 s warm) |
| final images | 0 cache references in /etc/yum.repos.d, /etc/dnf, /etc/apt; no state dir; no apt drop-in |
| release-install **without** PKG_CACHE | both RPMs verified from the HTTPS origins; restore is a no-op |
Script checks in a throwaway container:
- `http://` PKG_CACHE is refused.
- A wrong signing key gives `SIGNATURES NOT OK` and a hard fail.
- `repo_gpgcheck=1` dnf installs php-cli 8.5.12.
- A new cache-referencing repo file is removed by restore.
- A leftover reference in a pre-existing file makes restore FATAL.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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>
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>
- 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>
jknapp
merged commit cb0cecb557 into trunk2026-10-21 23:46:40 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Opt-in
PKG_CACHEbuild arg pointing dnf/apt at the internal package cache, CT130pkg-cache, https://192.168.1.40. Without the arg, builds use upstream repositories as before. The one change in that path is that the release RPMs are now GPG-verified. Update 2026-10-21 (Josh approved):PKG_CACHEthrough a TLS probe with measured fall-back: <1 s when the cache is refused, 10 s on a silent drop.scripts/host/pkgcache-host-repos.shfor WHP hosts, tested on .148 including cache-down fall-back.See
docs/pkg-cache.md.What changes
scripts/pkg-cache-repos.sh, with four modes:rpm: rewrites AlmaLinux/EPEL/Remibaseurls to<cache> <origin>(dnf fails over to the origin), adds a scopedsslcacert,gpgcheck=1, andrepo_gpgcheck=1for Remi and AlmaLinux.apt: rewrites Ubuntu and LiteSpeed URIs and sets a per-host CaInfo.release-install: HTTPS download, package-name check, keys fromkeys/pkg-cache/,rpm -Kmust say "signatures OK", thenlocalpkg_gpgcheck=1.restore: puts back rewritten files, deletes created files and any new file referencing the cache, and fails if a reference remains.Dockerfile,Dockerfile.fpm,Dockerfile.shared-httpdandDockerfile.shared-ols.Dockerfile.litespeedandDockerfile.lsphpare not wired yet (multi-stage plus the madison check; see docs).keys/pkg-cache/:CF1D F005 7CE8 5DFF 5B2F 2A37 C2FD 3B2C 2A09 48E4confirmed by Josh.docs/pkg-cache.md: cache rules, trust model, the CI plan (firewall exception, probe step, BuildKit mirror withca=), the WHP host plan, and operations.Tested on 192.168.1.193 (measured, 2026-10-21)
DockerfilePHPVER=85, PKG_CACHE via http (first version), cold cache--no-cacheDockerfilePHPVER=85, https PKG_CACHE (final code), TLS registry mirrorDockerfile.shared-ols1.8.4/85, https PKG_CACHEScript checks in a throwaway container:
http://PKG_CACHE is refused.SIGNATURES NOT OKand a hard fail.repo_gpgcheck=1dnf installs php-cli 8.5.12.🤖 Generated with Claude Code