- Honor ignore/control files first: respect
.gitignore,.aiignore, and other*ignorerules (for example.dockerignore) when selecting files to read, modify, or generate unless the user explicitly overrides this. - This repository builds and publishes custom PHP container images to GHCR (
ghcr.io/toshy/php) and publishes docs to GitHub Pages. - Existing AI guidance discovered from the requested glob search:
README.mdonly. - Treat build/workflow/doc config files below as canonical behavior.
docker-bake.hclis the release matrix brain: PHP versions, flavor/OS compatibility, targets, tags, and OCI labels are generated here.Dockerfiledefines 5 stages:common->base,ffmpeg,otel,otel-ffmpeg.commoninstalls shared binaries/extensions; each target stage adds only its delta.- Build context
php-baseis injected from upstreamphp:<version>-<flavor>-<os>via bake contexts (not a local FROM alias). - Target names may contain
-(for exampleotel-ffmpeg); workflow parsing inrelease.ymlderivesTARGETSdirectly from bake metadata (.target[].target | unique) and strips suffixes longest-first —docker-bake.hclremains the single source of truth for the target list.
- Tag pattern is
<version>-<flavor>-<os>(-<target>);baseis default and has no-basesuffix. latestis emitted only for default tuple (8.5+fpm+trixie+base) indocker-bake.hcl.- Short tags (for example
fpm-trixie-ffmpeg) are emitted only for the default PHP version. - Allowed flavor/OS pairs are constrained by
FLAVOR_OS_MAP; avoid introducing unsupported combinations.
release.ymlpipeline isprepare->build->merge.prepareresolves concrete upstream patch versions withskopeo inspect docker://docker.io/library/php:<minor>and computes the bake matrix.buildruns per-platform builds and pushes by digest.mergeassembles multi-arch manifest lists and assigns final tags from bake metadata.security.ymlperforms scheduled Trivy scans of published GHCR tags (CRITICAL, ignore unfixed).docs.ymlbuilds docs in a container and deploys/siteto GitHub Pages onmainpushes.
- List tasks:
task --list. - Build docs:
task docs; live docs:task docs:live p=8001. - Inspect generated bake matrix/tags before CI edits:
task bake:print pv="8.2.30,8.3.30,8.4.17,8.5.2". - Local amd64 bake run:
task bake pv="8.2.30,8.3.30,8.4.17,8.5.2". - Local target vulnerability scan:
task trivy pv="8.5.2-fpm-trixie" t="ffmpeg". - Workflow simulation uses
acttasks inTaskfile.yml(act:push,act:job:prepare,act:job:build,act:job:merge).
- Keep docs and build config synchronized: if extensions/packages/stages change in
Dockerfile, updatedocs/images.mdanddocs/usage.mdexamples. - Default OS is
trixie;docs/usage.mdstill referencesbookwormas deprecated context. - Docs tooling is containerized (
docker.io/zensical/zensical:0.0); avoid host-only assumptions. - Dependency/security automation is GitHub-native (
.github/dependabot.ymland scheduled workflows).
- If changing defaults (
DEFAULT_*,PHP_VERSIONS, targets), updatedocker-bake.hcl,.github/workflows/release.yml, and docs together. - If changing target contents, verify tag examples in docs still match real output from
task bake:print. - Prefer validating matrix/tag behavior locally before modifying workflow logic.
docker-bake.hclis the single source of truth for targets. Thepreparejob inrelease.ymlderivesTARGETSfrom bake metadata via[.target[].target] | unique— do NOT reintroduce a hardcodedTARGETSenv list.- The
buildjob is fully metadata-driven: aDerive bake argsstep buildstargets:and per-targetcache-from/cache-tooverrides fromneeds.prepare.outputs.targets, and digests are uploaded as a single bundled artifactdigest--<variant>--<platform>containing the full<target>/<sha>tree. Themergejob downloads the bundle andcds into/tmp/digest/${{ matrix.target }}. Adding a target requires no edits torelease.yml. - Bake target naming convention is
php-<ver-with-dashes>-<flavor>-<os>-<target>and<target>may itself contain-(for exampleotel-ffmpeg). Always strip the target suffix using the metadata-derived list with a longest-first regex; never use positionalsplit("-")indexes on the full target name. - Per-platform digest artifacts use a
--(double-hyphen) delimiter:digest--<variant>--<platform>. The merge job'sactions/download-artifactpattern(digest--<variant>--*) relies on this so variant boundaries are unambiguous. Do not introduce a variant or platform name containing--. - When adding a new target: update the
Dockerfilestage anddocker-bake.hclTARGETS. Therelease.ymlworkflow picks it up automatically. Then updatesecurity.ymlscan matrix and docs (docs/usage.md,docs/images.md). docker-bake.hcldeclares the desired platforms (linux/amd64,linux/386,linux/arm/v7,linux/arm64), but upstreamphp:<version>-<flavor>-<os>images do not always publish all of them: an arch disappears from the manifest list when its Debian base image is missing for that build (see docker-library/php#1683 — e.g.php:8.5.10-zts-trixiehas nolinux/386whilephp:8.5.10-cli-trixiedoes). Thepreparejob therefore inspects each variant'sphp-basemanifest withskopeo inspect --raw, intersects it with the bake platforms and emitsbuild_matrix(an explicit{variant, platform}include-matrix). Missing platforms are skipped with a::warning::instead of failing the run withno match for platform in manifest. Keep thebuildjob onmatrix.include— do NOT go back to a fullvariant x platformcross product.mergestays avariant x targetmatrix (a manifest list is platform-agnostic and is assembled from whatever digestsbuilduploaded), but its variant axis comes frombuild_variants(unique variants ofbuild_matrix), notvariants. A variant with zero available platforms is skipped everywhere instead of producing a merge job that fails on missing digest artifacts.
- Symptom:
task trivy:remote(orsecurity.yml) reportsfixedCRITICALs (e.g.ffmpeg/libav*,libgnutls30t64) on some PHP lines (commonly older ones like 8.2/8.3) but not others (8.4/8.5). - Root cause is NOT the
Dockerfile. Thepreparejob inrelease.yml(Check if PHP images already exists) skips rebuilding any version whose resolved patch tag already exists, unlessforce=true. So an image is only rebuilt when the PHP patch version bumps — Debian base/security package updates (gnutls from the base image, ffmpeg from theffmpeg/otel-ffmpegapt install) do NOT trigger a rebuild while PHP stays the same. Lines parked on an old patch ship stale packages. - Distinguish real findings from scanner false positives by comparing versions: if installed < fixed (e.g. gnutls
u2<u4, ffmpeg7.1.3<7.1.4) the finding is real and a rebuild fixes it. Debian backports fixes without bumping the upstream version, so a scanner flagging an already-patched build (installed == fixed) is the false positive — do NOT add those to a.trivyignore. - Fix: rebuild and republish the affected lines (Release workflow via
workflow_dispatchwith the PHP version andforce: true). A fresh rebuild pulls the updated base (gnutls) and re-runs apt install (ffmpeg). Do NOT addapt-get upgradeto theDockerfile— it fights the curated base image and the fix belongs in the base rebuild.