From cc5eecbbd312fb131ba3a741883de334660d392e Mon Sep 17 00:00:00 2001 From: Richard McDaniel <1130888+rmcdaniel@users.noreply.github.com> Date: Thu, 5 Nov 2026 21:26:02 +0000 Subject: [PATCH 1/2] Propose fixed Bookworm PHP parents and shared early APT preflight --- docker/apt/README.md | 70 +++++++++++ docker/apt/php-8.4.27-cli-bookworm.v1.json | 136 +++++++++++++++++++++ docker/apt/require-fixed-bookworm-apt.sh | 64 ++++++++++ tests/test_bookworm_apt_source.py | 112 +++++++++++++++++ tests/test_ci_trust.py | 6 +- 5 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 docker/apt/README.md create mode 100644 docker/apt/php-8.4.27-cli-bookworm.v1.json create mode 100644 docker/apt/require-fixed-bookworm-apt.sh create mode 100644 tests/test_bookworm_apt_source.py diff --git a/docker/apt/README.md b/docker/apt/README.md new file mode 100644 index 0000000..5c6137d --- /dev/null +++ b/docker/apt/README.md @@ -0,0 +1,70 @@ +# Shared Bookworm parent and early APT preflight proposal + +This source-only profile covers PHP **8.4.27 CLI / Debian 12 / amd64 and arm64**. +It does not qualify an installed image or select a build, pull, publisher, or +consumer adoption. The Ubuntu 26.04 / PHP 8.3 hosted setup profile is separate. + +The official [Debian advisory](https://lists.debian.org/debian-lts-announce/2026/11/msg00004.html) +sets the Bookworm fixed floor to **2.6.2**. Both +[apt](https://packages.debian.org/bookworm/apt) and +[libapt-pkg6.0](https://packages.debian.org/bookworm/libapt-pkg6.0) must meet it. +`php-8.4.27-cli-bookworm.v1.json` records the exact official index, both native +child manifests, configs, attestation manifests and SPDX statements for the old +and proposed fixed parent. Descriptor bytes/sizes/SHA-256 and SPDX child subjects +were checked with bounded stock public Registry v2 metadata GETs. No rootfs layer +was fetched. The mutable tag was used only to discover the candidate; it is not +a permitted build selector. + +| Parent | Index SHA-256 | Publisher APT/libapt records, both architectures | +| --- | --- | --- | +| Existing | `54b467ede1db96c66675e7b78457dd43729d0e7be31978d4a1e5c069ceabcf76` | 2.6.1 / 2.6.1 | +| Proposed | `b3e907a1108629c562c4bb313ce3449e34d49991f6bb2487913f6146f47200fe` | 2.6.2 / 2.6.2 | + +The candidate config retains PHP_VERSION=8.4.27 on each native architecture. +These publisher records are source inventory. Actual fixed pair, architecture, +executable availability and affected consumer behavior still need a separately +selected original image qualification. + +## Reuse before Python exists + +`require-fixed-bookworm-apt.sh` is a single central read-only shell preflight. +It reads the effective Debian release as data, queries the installed native +APT/libapt pair and uses stock dpkg version comparison. It refuses other releases, +architectures, malformed/incomplete/duplicate rows, non-installed status and +either unfixed member. It accepts no overrides, acquires nothing and performs no +repair. It requires only `/bin/sh`, `/usr/bin/env`, `/usr/bin/dpkg-query` and +`/usr/bin/dpkg`; the package-query subprocesses receive an empty environment plus +fixed PATH/locale. It needs neither Python nor an APT operation to start. + +The initial consumer source target is Sample App +`.devcontainer/docker/Dockerfile`, observed at commit +`42d9af5957832ed2b0413c7fea1853e4d47ed3f4`, blob +`11d349d36a7d26d6e8cd9abb99fd2a94c876aa73`. Its Brotli build and final stages both +use the old PHP index. Both run the APT-using Brotli helper before the later +obvious APT block; the final stage also runs Playwright with `--with-deps`. + +The proposed narrow adoption, after central acceptance and owner selection, is: + +1. Keep both existing PHP stage versions and both amd64/arm64 platforms; replace + only their index with the exact proposed fixed index above. +2. Check out an accepted immutable central source commit without persisted + credentials into `.central-apt-source` inside the disposable build context. + Verify actual HEAD equals that literal before the build. Use the same central + file directly; do not commit a repository-local guard implementation. +3. In each PHP stage, before its first RUN, copy the central file with ordinary + Docker `COPY` from + `.central-apt-source/docker/apt/require-fixed-bookworm-apt.sh` and run it with + `/bin/sh` before the Brotli helper. A missing local context/file fails COPY; + this route has no external-image/named-context fallback. +4. Invoke that same guard immediately before the later direct APT block and + Playwright `--with-deps`, so earlier stage operations cannot silently replace + the accepted effective pair. Preserve all current product/helper pins, source + graphs, trust gates, test behavior and platform selection. + +No action or caller currently invokes this profile. The exact accepted central +commit/file SHA and complete consumer diff are future immutable recipe inputs. +Docker context inclusion and both first-RUN orders must be checked on that +consumer diff before any selected build. Source tests use inert package/release +records and stock offline version comparison; they do not run a container or APT. +The existing Python host guard remains separate and unwired. No historical root +bootstrap or package-manager transaction is restored. diff --git a/docker/apt/php-8.4.27-cli-bookworm.v1.json b/docker/apt/php-8.4.27-cli-bookworm.v1.json new file mode 100644 index 0000000..1b69891 --- /dev/null +++ b/docker/apt/php-8.4.27-cli-bookworm.v1.json @@ -0,0 +1,136 @@ +{ + "schema": "durable-workflow.php-bookworm-apt-parent.v1", + "scope": "publisher-source-inventory-only", + "repository": "docker.io/library/php", + "discovery_tag": "8.4.27-cli-bookworm", + "php_version": "8.4.27", + "os": { + "id": "debian", + "version_id": "12" + }, + "architectures": [ + "amd64", + "arm64" + ], + "fixed": { + "apt": "2.6.2", + "libapt-pkg6.0": "2.6.2" + }, + "authority": [ + "https://lists.debian.org/debian-lts-announce/2026/11/msg00004.html", + "https://packages.debian.org/bookworm/apt", + "https://packages.debian.org/bookworm/libapt-pkg6.0" + ], + "inventory": { + "layer_fetch": false, + "image_execution": false, + "rootfs_inspection": false, + "installed_qualification": false + }, + "parents": { + "predecessor": { + "index": { + "digest": "sha256:54b467ede1db96c66675e7b78457dd43729d0e7be31978d4a1e5c069ceabcf76", + "size": 6501 + }, + "platforms": { + "linux/amd64": { + "child": { + "digest": "sha256:dd0e2b902f1edfb6ca02fbcb391c28b1554c7d35a4e36e5925876b90aa804851", + "size": 2878 + }, + "config": { + "digest": "sha256:12f6d2ea136f247580f3dc42bda86b27af080fa8f04ea5ec9b581238702093ff", + "size": 9007 + }, + "attestation": { + "digest": "sha256:ab7746990035696c58dc15c84923a2164212106d49a72d38b4d887d2efcc88b9", + "size": 841 + }, + "spdx": { + "digest": "sha256:f56402e73d62fcdd665a7152bcd1aaa5e0da7e85b2ba7a42c9d306cd475a2672", + "size": 6407897 + }, + "packages": { + "apt": "2.6.1", + "libapt-pkg6.0": "2.6.1" + } + }, + "linux/arm64": { + "child": { + "digest": "sha256:ec3adc33ae9801f3cb9291c3f343c12ae1e9f3879d866c1517cd32160a74fa23", + "size": 2879 + }, + "config": { + "digest": "sha256:ca2f912b5fc4cee612b0863e15e3a23a087f1446ec51136a64f3527809b7dd59", + "size": 9020 + }, + "attestation": { + "digest": "sha256:1f2b9e200944bd584ad1c39e036031fb81fa26fab8c7ad9f97f0ddfb600c24f9", + "size": 841 + }, + "spdx": { + "digest": "sha256:34eab70d705d37508cca2b6a93d1d448807c2ed4f966959f7755b77548aad6ee", + "size": 6436288 + }, + "packages": { + "apt": "2.6.1", + "libapt-pkg6.0": "2.6.1" + } + } + } + }, + "candidate": { + "index": { + "digest": "sha256:b3e907a1108629c562c4bb313ce3449e34d49991f6bb2487913f6146f47200fe", + "size": 6501 + }, + "platforms": { + "linux/amd64": { + "child": { + "digest": "sha256:5d3eebbd478bc102494c539d43be98a885984b33f929c6081f1c59033a878d6a", + "size": 2878 + }, + "config": { + "digest": "sha256:3db89bf1e580bf2a2767ea5bdeb168f4f053bf275188a103744e97c47bf0edaa", + "size": 9007 + }, + "attestation": { + "digest": "sha256:bf3bf52ff7e0e21a244116b0d31eb2490b9b0a6fc5fb914d08e562d61c92a792", + "size": 841 + }, + "spdx": { + "digest": "sha256:169f54509152a0455c7c7ab21d3a90834b6208f298ea78e5392decc7028ea53b", + "size": 6407951 + }, + "packages": { + "apt": "2.6.2", + "libapt-pkg6.0": "2.6.2" + } + }, + "linux/arm64": { + "child": { + "digest": "sha256:f4501edd9c94d75fe90c78a81e9db9e5147170398619258165dff01607cec592", + "size": 2879 + }, + "config": { + "digest": "sha256:2b040a3b56b4b844d9992dff098a3302811007cdb759fc1b8daf6c4f094a9d29", + "size": 9022 + }, + "attestation": { + "digest": "sha256:3adad572ed13aadfc7bfcd0d50c714c29ce52e4ac2ccd113ee415b57e0362b49", + "size": 841 + }, + "spdx": { + "digest": "sha256:939898a2aefda54caa35d0d25b27b8db2da9cbc314aad87e19de3dfde9d0bdb5", + "size": 6436342 + }, + "packages": { + "apt": "2.6.2", + "libapt-pkg6.0": "2.6.2" + } + } + } + } + } +} diff --git a/docker/apt/require-fixed-bookworm-apt.sh b/docker/apt/require-fixed-bookworm-apt.sh new file mode 100644 index 0000000..46ab3fb --- /dev/null +++ b/docker/apt/require-fixed-bookworm-apt.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# Shared read-only image preflight. No Python, APT, download, or repair path. +set -eu +LC_ALL=C +export LC_ALL +RELEASE=/etc/os-release +QUERY=/usr/bin/dpkg-query +DPKG=/usr/bin/dpkg +readonly RELEASE QUERY DPKG + +refuse() { + printf '%s\n' 'fixed_bookworm_apt=false: effective Debian 12 native APT pair did not prove the 2.6.2 floor' >&2 + exit 1 +} + +[ "$#" -eq 0 ] || refuse +os= +release= +while IFS= read -r line || [ -n "$line" ]; do + case "$line" in + ID=*) + [ -z "$os" ] || refuse + case "$line" in ID=debian|ID=\"debian\") os=debian ;; *) refuse ;; esac + ;; + VERSION_ID=*) + [ -z "$release" ] || refuse + case "$line" in VERSION_ID=12|VERSION_ID=\"12\") release=12 ;; *) refuse ;; esac + ;; + esac +done < "$RELEASE" +[ "$os:$release" = debian:12 ] || refuse + +rows=$(/usr/bin/env -i PATH=/usr/bin:/bin LC_ALL=C "$QUERY" --show \ + '--showformat=${Package}|${Status}|${Version}|${Architecture}\n' apt libapt-pkg6.0) || refuse +apt= +library= +architecture= +while IFS= read -r line; do + case "$line" in *'|'*'|'*'|'*'|'*) refuse ;; *'|'*'|'*'|'*) ;; *) refuse ;; esac + IFS='|' read -r package status version arch < Date: Thu, 5 Nov 2026 21:34:03 +0000 Subject: [PATCH 2/2] Make Bookworm guard default shell cases explicit --- docker/apt/require-fixed-bookworm-apt.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/apt/require-fixed-bookworm-apt.sh b/docker/apt/require-fixed-bookworm-apt.sh index 46ab3fb..5d76f64 100644 --- a/docker/apt/require-fixed-bookworm-apt.sh +++ b/docker/apt/require-fixed-bookworm-apt.sh @@ -26,6 +26,7 @@ while IFS= read -r line || [ -n "$line" ]; do [ -z "$release" ] || refuse case "$line" in VERSION_ID=12|VERSION_ID=\"12\") release=12 ;; *) refuse ;; esac ;; + *) : ;; esac done < "$RELEASE" [ "$os:$release" = debian:12 ] || refuse @@ -41,7 +42,7 @@ while IFS= read -r line; do $line EOF [ "$status" = 'install ok installed' ] || refuse - case "$version" in ''|[!0-9]*|*[!0-9A-Za-z.+:~\-]*) refuse ;; esac + case "$version" in ''|[!0-9]*|*[!0-9A-Za-z.+:~\-]*) refuse ;; *) : ;; esac [ "${#version}" -le 100 ] || refuse case "$arch" in amd64|arm64) ;; *) refuse ;; esac [ -z "$architecture" ] || [ "$architecture" = "$arch" ] || refuse