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>
90 lines
4.7 KiB
Docker
90 lines
4.7 KiB
Docker
# Base image. CI passes BASE_IMAGE=almalinux/10-base@sha256:<digest>, resolved
|
|
# DIRECTLY from Docker Hub in the same run (.gitea/scripts/resolve-base-image.sh),
|
|
# so the pkg-cache registry mirror can only serve content-addressed blobs.
|
|
# Local builds use the tag. docs/pkg-cache.md "Base-image digest pinning".
|
|
ARG BASE_IMAGE=almalinux/10-base
|
|
FROM ${BASE_IMAGE}
|
|
ARG PHPVER=83
|
|
# Per-CI-run value: the first RUN below (dnf update) and everything after it can
|
|
# never be a layer-cache hit, so every build gets the repos' current packages.
|
|
# Local builds: --build-arg CACHE_BUST=$(date +%s) or --no-cache.
|
|
ARG CACHE_BUST=
|
|
# php.net's current release for this branch (CI); the build fails on older PHP.
|
|
ARG EXPECT_PHP_MIN=
|
|
|
|
# OPTIONAL internal package cache, e.g. --build-arg PKG_CACHE=https://192.168.1.40
|
|
# (CT130 pkg-cache, https only). Unset = upstream repositories. Release RPMs are
|
|
# GPG-verified against keys/pkg-cache/ either way. Repo files
|
|
# are restored at the end of every RUN, so no layer keeps the cache address.
|
|
# See scripts/pkg-cache-repos.sh.
|
|
ARG PKG_CACHE=
|
|
COPY ./scripts/pkg-cache-repos.sh /usr/local/sbin/pkg-cache-repos.sh
|
|
COPY ./keys/pkg-cache/ /usr/local/share/pkg-cache/
|
|
# Install repos, update, install only needed packages (no httpd/mod_ssl), clean up in one layer
|
|
RUN /usr/local/sbin/pkg-cache-repos.sh rpm && \
|
|
/usr/local/sbin/pkg-cache-repos.sh release-install epel remi && \
|
|
# Use Remi's origin, not the mirrorlist: during the 2026-10-21 PHP security
|
|
# release the mirrors lagged hours behind (still 8.2.34 when 8.2.35 was out),
|
|
# so builds shipped unpatched PHP. HTTPS first; plain http only as a fallback
|
|
# because the origin's HTTPS dropped/timed out under that day's load. A
|
|
# replayed (old) http index can't ship old PHP: packages stay GPG-checked and
|
|
# the EXPECT_PHP_MIN gate below fails the build on anything older than php.net.
|
|
sed -i -e 's|^#baseurl=http://\(.*\)$|baseurl=https://\1 http://\1|' -e 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/remi*.repo && \
|
|
/usr/local/sbin/pkg-cache-repos.sh rpm && \
|
|
printf 'retries=10\ntimeout=60\n' >> /etc/dnf/dnf.conf && \
|
|
dnf update -y && \
|
|
dnf install -y openssl wget procps cronie iproute postgresql-devel microdnf less git \
|
|
nano rsync unzip zip mariadb bind-utils jq patch nc tree dos2unix fcgi && \
|
|
/usr/local/sbin/pkg-cache-repos.sh restore && \
|
|
dnf clean all && \
|
|
rm -rf /var/cache/dnf /usr/share/doc /usr/share/man /usr/share/locale/*
|
|
|
|
# Copy scripts into the image and set permissions
|
|
COPY ./scripts/ /scripts/
|
|
RUN chmod +x /scripts/*
|
|
|
|
# Install ImageMagick from EPEL with HEIC/HEIF/AVIF support
|
|
RUN /usr/local/sbin/pkg-cache-repos.sh rpm && \
|
|
dnf install -y ImageMagick ImageMagick-libs ImageMagick-heic && \
|
|
/usr/local/sbin/pkg-cache-repos.sh restore && \
|
|
dnf clean all
|
|
|
|
# Create needed dirs, install PHP, clean up (no SSL cert, no httpd)
|
|
RUN mkdir -p /run/php-fpm/ && \
|
|
/usr/local/sbin/pkg-cache-repos.sh rpm && \
|
|
/scripts/install-php$PHPVER.sh && \
|
|
/usr/local/sbin/pkg-cache-repos.sh restore && \
|
|
# CI passes php.net's current release for the branch; never ship older PHP.
|
|
if [ -n "$EXPECT_PHP_MIN" ]; then \
|
|
php -r 'exit(version_compare(PHP_VERSION, getenv("EXPECT_PHP_MIN"), ">=") ? 0 : 1);' || \
|
|
{ echo "FATAL: built PHP $(php -r 'echo PHP_VERSION;') is older than php.net $EXPECT_PHP_MIN"; exit 1; }; \
|
|
else echo "WARNING: no EXPECT_PHP_MIN (local build) - PHP version not gated"; fi && \
|
|
echo "PHP version report:" && php -v && rpm -q php-cli php-common php-fpm && \
|
|
rm -rf /tmp/*
|
|
|
|
# Download and install wp-cli
|
|
RUN curl -L -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
|
|
chmod +x /usr/local/bin/wp
|
|
|
|
# Download and install Composer
|
|
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer && \
|
|
chmod +x /usr/local/bin/composer
|
|
|
|
# Copy configs (PHP only, no Apache configs)
|
|
COPY ./configs/prod-php.ini /etc/php.ini
|
|
# php2shell mitigation (CVE-2026-109618/-109619). Named zz- so it sorts after
|
|
# every other scan-dir ini (incl. runtime-written 99-*) and wins. Remove once
|
|
# all images ship PHP >= 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12.
|
|
COPY ./configs/zz-php2shell-mitigation.ini /etc/php.d/zz-php2shell-mitigation.ini
|
|
COPY ./configs/mariadb.repo /etc/yum.repos.d/
|
|
|
|
# Set up cron job for log rotation
|
|
RUN echo "15 */12 * * * root /scripts/log-rotate.sh" >> /etc/crontab
|
|
|
|
EXPOSE 9000
|
|
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
|
|
CMD SCRIPT_FILENAME=/fpm-ping SCRIPT_NAME=/fpm-ping REQUEST_METHOD=GET cgi-fcgi -bind -connect 127.0.0.1:9000 | grep -q pong || exit 1
|
|
|
|
ENTRYPOINT [ "/scripts/entrypoint-fpm.sh" ]
|