From a4e09f9772639efa2f0d869bbad9f5b2f0ef5b44 Mon Sep 17 00:00:00 2001 From: Bui Huy Hoang Date: Mon, 26 Oct 2026 20:46:19 +0700 Subject: [PATCH 1/3] feat: add php 8.1.34 alpine3.22 build from ghcr base Build 8.1 from ghcr.io/sun-asterisk-research/php:8.1.34-nginx-alpine3.22 pinned by digest, via a dedicated versions_8.1.yml: one exact tag (8.1.34-alpine3.22), linux/amd64 only, no Docker Hub step. 8.1.9 is dropped from versions.yml. Generator: new base_image, base_image_sha256, exact_tags_only and dockerhub_push keys, validated before anything is written or removed. base_image is required, and base_image_sha256 is required when exact_tags_only is true. Other versions keep their output; their workflows only gain 'if: true' on the Docker Hub steps. Makefile: fix the clean loop (missing ls) so make all removes stale version directories, stop on the first failing versions file instead of masking it, and validate every versions file before cleaning. --- .github/workflows/7.3.yml | 2 + .github/workflows/7.4.yml | 2 + .github/workflows/8.0.yml | 2 + .github/workflows/8.1.yml | 11 +- .github/workflows/8.2.yml | 2 + 8.1/alpine3.16/Dockerfile | 15 --- .../usr/local/bin/docker-php-ext-disable | 4 - 8.1/{alpine3.15 => alpine3.22}/Dockerfile | 2 +- .../usr/local/bin/docker-php-ext-disable | 0 8.1/bullseye/Dockerfile | 15 --- .../usr/local/bin/docker-php-ext-disable | 4 - 8.1/buster/Dockerfile | 15 --- .../usr/local/bin/docker-php-ext-disable | 4 - Dockerfile-00.template | 2 +- Makefile | 14 ++- ci.yml.template | 2 + docker-bake.hcl | 90 +++------------ generate.sh | 105 ++++++++++++++++-- versions.yml | 2 +- versions_7.3.yml | 1 + versions_8.1.yml | 19 ++++ versions_8.2.yml | 1 + 22 files changed, 161 insertions(+), 153 deletions(-) delete mode 100644 8.1/alpine3.16/Dockerfile delete mode 100755 8.1/alpine3.16/rootfs/usr/local/bin/docker-php-ext-disable rename 8.1/{alpine3.15 => alpine3.22}/Dockerfile (77%) rename 8.1/{alpine3.15 => alpine3.22}/rootfs/usr/local/bin/docker-php-ext-disable (100%) delete mode 100644 8.1/bullseye/Dockerfile delete mode 100755 8.1/bullseye/rootfs/usr/local/bin/docker-php-ext-disable delete mode 100644 8.1/buster/Dockerfile delete mode 100755 8.1/buster/rootfs/usr/local/bin/docker-php-ext-disable create mode 100644 versions_8.1.yml diff --git a/.github/workflows/7.3.yml b/.github/workflows/7.3.yml index 3ea4f68..6b177e5 100644 --- a/.github/workflows/7.3.yml +++ b/.github/workflows/7.3.yml @@ -54,6 +54,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: true - name: GHCR Login uses: docker/login-action@v1 with: @@ -67,6 +68,7 @@ jobs: set: | *.platform=linux/amd64,linux/arm,linux/arm64 push: ${{ github.event_name == 'push' }} + if: true - name: GHCR build and push uses: docker/bake-action@v2 env: diff --git a/.github/workflows/7.4.yml b/.github/workflows/7.4.yml index ed42b53..7c0824e 100644 --- a/.github/workflows/7.4.yml +++ b/.github/workflows/7.4.yml @@ -54,6 +54,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: true - name: GHCR Login uses: docker/login-action@v1 with: @@ -67,6 +68,7 @@ jobs: set: | *.platform=linux/amd64,linux/arm,linux/arm64 push: ${{ github.event_name == 'push' }} + if: true - name: GHCR build and push uses: docker/bake-action@v2 env: diff --git a/.github/workflows/8.0.yml b/.github/workflows/8.0.yml index 42f8fb3..4d556f6 100644 --- a/.github/workflows/8.0.yml +++ b/.github/workflows/8.0.yml @@ -54,6 +54,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: true - name: GHCR Login uses: docker/login-action@v1 with: @@ -67,6 +68,7 @@ jobs: set: | *.platform=linux/amd64,linux/arm,linux/arm64 push: ${{ github.event_name == 'push' }} + if: true - name: GHCR build and push uses: docker/bake-action@v2 env: diff --git a/.github/workflows/8.1.yml b/.github/workflows/8.1.yml index 2fcffc0..3178841 100644 --- a/.github/workflows/8.1.yml +++ b/.github/workflows/8.1.yml @@ -35,10 +35,7 @@ jobs: matrix: target: [ - "8_1_9-bullseye", - "8_1_9-buster", - "8_1_9-alpine3_16", - "8_1_9-alpine3_15", + "8_1_34-alpine3_22", ] steps: - name: Checkout @@ -54,6 +51,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: false - name: GHCR Login uses: docker/login-action@v1 with: @@ -65,8 +63,9 @@ jobs: with: targets: ${{ matrix.target }} set: | - *.platform=linux/amd64,linux/arm,linux/arm64 + *.platform=linux/amd64 push: ${{ github.event_name == 'push' }} + if: false - name: GHCR build and push uses: docker/bake-action@v2 env: @@ -75,5 +74,5 @@ jobs: with: targets: ${{ matrix.target }} set: | - *.platform=linux/amd64,linux/arm,linux/arm64 + *.platform=linux/amd64 push: ${{ github.event_name == 'push' }} diff --git a/.github/workflows/8.2.yml b/.github/workflows/8.2.yml index 72859b2..2b3d464 100644 --- a/.github/workflows/8.2.yml +++ b/.github/workflows/8.2.yml @@ -54,6 +54,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: true - name: GHCR Login uses: docker/login-action@v1 with: @@ -67,6 +68,7 @@ jobs: set: | *.platform=linux/amd64,linux/arm,linux/arm64 push: ${{ github.event_name == 'push' }} + if: true - name: GHCR build and push uses: docker/bake-action@v2 env: diff --git a/8.1/alpine3.16/Dockerfile b/8.1/alpine3.16/Dockerfile deleted file mode 100644 index 8c4730a..0000000 --- a/8.1/alpine3.16/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# NOTE: This file was generated via generate.sh. Don't edit it directly - -FROM sunasteriskrnd/php:8.1.9-nginx-alpine3.16 - -ENV COMPOSER_VERSION=2.4.1 - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --version="$COMPOSER_VERSION" - -COPY rootfs / -RUN apk add --no-cache git - -RUN apk add --update linux-headers --no-cache --virtual .ext-deps autoconf gcc musl-dev make \ - && pecl install xdebug pcov \ - && docker-php-ext-enable xdebug pcov \ - && apk del .ext-deps diff --git a/8.1/alpine3.16/rootfs/usr/local/bin/docker-php-ext-disable b/8.1/alpine3.16/rootfs/usr/local/bin/docker-php-ext-disable deleted file mode 100755 index 3622ebc..0000000 --- a/8.1/alpine3.16/rootfs/usr/local/bin/docker-php-ext-disable +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -# remove config file created by docker-php-ext-enable -rm /usr/local/etc/php/conf.d/docker-php-ext-$1.ini diff --git a/8.1/alpine3.15/Dockerfile b/8.1/alpine3.22/Dockerfile similarity index 77% rename from 8.1/alpine3.15/Dockerfile rename to 8.1/alpine3.22/Dockerfile index c251d1e..6b65032 100644 --- a/8.1/alpine3.15/Dockerfile +++ b/8.1/alpine3.22/Dockerfile @@ -1,6 +1,6 @@ # NOTE: This file was generated via generate.sh. Don't edit it directly -FROM sunasteriskrnd/php:8.1.9-nginx-alpine3.15 +FROM ghcr.io/sun-asterisk-research/php:8.1.34-nginx-alpine3.22@sha256:52414238eb01bf163d0df29bb7c10adb04559a89cdd9242c8794c35defe7e998 ENV COMPOSER_VERSION=2.4.1 diff --git a/8.1/alpine3.15/rootfs/usr/local/bin/docker-php-ext-disable b/8.1/alpine3.22/rootfs/usr/local/bin/docker-php-ext-disable similarity index 100% rename from 8.1/alpine3.15/rootfs/usr/local/bin/docker-php-ext-disable rename to 8.1/alpine3.22/rootfs/usr/local/bin/docker-php-ext-disable diff --git a/8.1/bullseye/Dockerfile b/8.1/bullseye/Dockerfile deleted file mode 100644 index 9476b5e..0000000 --- a/8.1/bullseye/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# NOTE: This file was generated via generate.sh. Don't edit it directly - -FROM sunasteriskrnd/php:8.1.9-nginx-bullseye - -ENV COMPOSER_VERSION=2.4.1 - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --version="$COMPOSER_VERSION" - -COPY rootfs / -RUN apt-get update \ - && apt-get install -y git vim \ - && rm -rf /var/lib/apt/lists/* - -RUN pecl install xdebug pcov \ - && docker-php-ext-enable xdebug pcov diff --git a/8.1/bullseye/rootfs/usr/local/bin/docker-php-ext-disable b/8.1/bullseye/rootfs/usr/local/bin/docker-php-ext-disable deleted file mode 100755 index 3622ebc..0000000 --- a/8.1/bullseye/rootfs/usr/local/bin/docker-php-ext-disable +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -# remove config file created by docker-php-ext-enable -rm /usr/local/etc/php/conf.d/docker-php-ext-$1.ini diff --git a/8.1/buster/Dockerfile b/8.1/buster/Dockerfile deleted file mode 100644 index 50b8238..0000000 --- a/8.1/buster/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# NOTE: This file was generated via generate.sh. Don't edit it directly - -FROM sunasteriskrnd/php:8.1.9-nginx-buster - -ENV COMPOSER_VERSION=2.4.1 - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --version="$COMPOSER_VERSION" - -COPY rootfs / -RUN apt-get update \ - && apt-get install -y git vim \ - && rm -rf /var/lib/apt/lists/* - -RUN pecl install xdebug pcov \ - && docker-php-ext-enable xdebug pcov diff --git a/8.1/buster/rootfs/usr/local/bin/docker-php-ext-disable b/8.1/buster/rootfs/usr/local/bin/docker-php-ext-disable deleted file mode 100755 index 3622ebc..0000000 --- a/8.1/buster/rootfs/usr/local/bin/docker-php-ext-disable +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -# remove config file created by docker-php-ext-enable -rm /usr/local/etc/php/conf.d/docker-php-ext-$1.ini diff --git a/Dockerfile-00.template b/Dockerfile-00.template index ebb1164..af830c2 100644 --- a/Dockerfile-00.template +++ b/Dockerfile-00.template @@ -1,4 +1,4 @@ -FROM sunasteriskrnd/php:{{ version }}-nginx-{{ distro_release }} +FROM {{ base_image }}:{{ version }}-nginx-{{ distro_release }}{{ base_image_digest }} ENV COMPOSER_VERSION={{ composer_version }} diff --git a/Makefile b/Makefile index ec6a6b7..7347ff3 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,19 @@ generate: @./generate.sh @for versions in $$(ls versions_*.yml); do \ - APPEND=true ./generate.sh $$versions; \ + APPEND=true ./generate.sh $$versions || exit 1; \ done clean: @./generate.sh clean - @for versions in $$(versions_*.yml); do \ - APPEND=true ./generate.sh clean $$versions; \ + @for versions in $$(ls versions_*.yml); do \ + APPEND=true ./generate.sh clean $$versions || exit 1; \ + done + +# Validate every versions file first, so a bad one stops make all before anything is removed +check: + @for versions in versions.yml $$(ls versions_*.yml); do \ + ./generate.sh check $$versions || exit 1; \ done -all: clean generate +all: check clean generate diff --git a/ci.yml.template b/ci.yml.template index 16f35d2..feb3d40 100644 --- a/ci.yml.template +++ b/ci.yml.template @@ -47,6 +47,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + if: {{ dockerhub_push }} - name: GHCR Login uses: docker/login-action@v1 with: @@ -60,6 +61,7 @@ jobs: set: | *.platform={{ platforms }} push: ${{ github.event_name == 'push' }} + if: {{ dockerhub_push }} - name: GHCR build and push uses: docker/bake-action@v2 env: diff --git a/docker-bake.hcl b/docker-bake.hcl index 6fb92a2..38eb229 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -142,82 +142,6 @@ target "8_0-alpine3_15" { inherits = ["8_0_22-alpine3_15"] } -target "8_1_9-bullseye" { - context = "./8.1/bullseye" - cache-from = [ - "${REGISTRY}/${REPO}:8.1-bullseye" - ] - tags = [ - "${REGISTRY}/${REPO}:8-bullseye", - "${REGISTRY}/${REPO}:8", - "${REGISTRY}/${REPO}:8.1-bullseye", - "${REGISTRY}/${REPO}:8.1", - "${REGISTRY}/${REPO}:8.1.9-bullseye", - "${REGISTRY}/${REPO}:8.1.9", - "${REGISTRY}/${REPO}:bullseye", - "${REGISTRY}/${REPO}:latest", - ] -} - -target "8_1-bullseye" { - inherits = ["8_1_9-bullseye"] -} - -target "8_1_9-buster" { - context = "./8.1/buster" - cache-from = [ - "${REGISTRY}/${REPO}:8.1-buster" - ] - tags = [ - "${REGISTRY}/${REPO}:8-buster", - "${REGISTRY}/${REPO}:8.1-buster", - "${REGISTRY}/${REPO}:8.1.9-buster", - "${REGISTRY}/${REPO}:buster", - ] -} - -target "8_1-buster" { - inherits = ["8_1_9-buster"] -} - -target "8_1_9-alpine3_16" { - context = "./8.1/alpine3.16" - cache-from = [ - "${REGISTRY}/${REPO}:8.1-alpine3.16" - ] - tags = [ - "${REGISTRY}/${REPO}:8-alpine3.16", - "${REGISTRY}/${REPO}:8-alpine", - "${REGISTRY}/${REPO}:8.1-alpine3.16", - "${REGISTRY}/${REPO}:8.1-alpine", - "${REGISTRY}/${REPO}:8.1.9-alpine3.16", - "${REGISTRY}/${REPO}:8.1.9-alpine", - "${REGISTRY}/${REPO}:alpine3.16", - "${REGISTRY}/${REPO}:alpine", - ] -} - -target "8_1-alpine3_16" { - inherits = ["8_1_9-alpine3_16"] -} - -target "8_1_9-alpine3_15" { - context = "./8.1/alpine3.15" - cache-from = [ - "${REGISTRY}/${REPO}:8.1-alpine3.15" - ] - tags = [ - "${REGISTRY}/${REPO}:8-alpine3.15", - "${REGISTRY}/${REPO}:8.1-alpine3.15", - "${REGISTRY}/${REPO}:8.1.9-alpine3.15", - "${REGISTRY}/${REPO}:alpine3.15", - ] -} - -target "8_1-alpine3_15" { - inherits = ["8_1_9-alpine3_15"] -} - target "7_3_33-bullseye" { context = "./7.3/bullseye" cache-from = [ @@ -282,6 +206,20 @@ target "7_3-alpine3_14" { inherits = ["7_3_33-alpine3_14"] } +target "8_1_34-alpine3_22" { + context = "./8.1/alpine3.22" + cache-from = [ + "${REGISTRY}/${REPO}:8.1-alpine3.22" + ] + tags = [ + "${REGISTRY}/${REPO}:8.1.34-alpine3.22", + ] +} + +target "8_1-alpine3_22" { + inherits = ["8_1_34-alpine3_22"] +} + target "8_2_1-bullseye" { context = "./8.2/bullseye" cache-from = [ diff --git a/generate.sh b/generate.sh index b65cd32..224a7e7 100755 --- a/generate.sh +++ b/generate.sh @@ -4,6 +4,67 @@ set -e source generate_utils.sh +# Print the value of an optional boolean key from versions*.yml, or the default when unset. +# Fails when the value is neither true nor false. +# +# Usage: bool_key +# e.g. bool_key exact_tags_only false +# +bool_key() { + local value="${!1:-$2}" + + if [ "$value" != true ] && [ "$value" != false ]; then + echo "$1 must be true or false, got '$value'" >&2 + return 1 + fi + + echo "$value" +} + +# Print "@sha256:" for an optional digest key from versions*.yml, or nothing when unset. +# The key holds the bare 64-char hex: parse_versions can't carry a ":" inside a value. +# +# Usage: digest_suffix +# e.g. digest_suffix base_image_sha256 +# +digest_suffix() { + local value="${!1}" + + if [ -z "$value" ]; then + return 0 + fi + + if ! [[ "$value" =~ ^[0-9a-f]{64}$ ]]; then + echo "$1 must be a 64-char hex sha256 without the 'sha256:' prefix, got '$value'" >&2 + return 1 + fi + + echo "@sha256:$value" +} + +# Validate the keys of the loaded versions*.yml before anything is written or removed. +# base_image is required; base_image_sha256 is required when exact_tags_only is true, +# so an exact (immutable) tag is never built from an unpinned base. +# +# Usage: validate_config +# +validate_config() { + if ! [[ "$base_image" =~ ^[a-z0-9][a-z0-9./_-]*$ ]]; then + echo "$1: base_image must be an image repository like ghcr.io/org/php, got '$base_image'" >&2 + return 1 + fi + + local exact_only + exact_only=$(bool_key exact_tags_only false) || return 1 + bool_key dockerhub_push true > /dev/null || return 1 + digest_suffix base_image_sha256 > /dev/null || return 1 + + if [ "$exact_only" = true ] && [ -z "$base_image_sha256" ]; then + echo "$1: base_image_sha256 is required when exact_tags_only is true" >&2 + return 1 + fi +} + # Generate a script that can be used with `eval` to set meta variables from a tag # # Usage: meta_from_full_tag @@ -41,6 +102,10 @@ generate_dockerfile() { local dir="$php_minor/$distro_release" local dockerfile="$dir/Dockerfile" + # Base php image digest pin (key base_image_sha256); validate_config already checked the keys + local base_image_digest + base_image_digest=$(digest_suffix base_image_sha256) + mkdir -p "$dir" write_warn_edit $dockerfile @@ -50,6 +115,8 @@ generate_dockerfile() { version=php_version \ composer_version \ distro_release \ + base_image \ + base_image_digest \ >> $dockerfile done @@ -151,6 +218,15 @@ generate_bake_file_target() { distro_tags="$distro_tags,default" fi + # Opt-in: publish only the immutable full tag, without minor/major versions or aliases + local exact_only + exact_only=$(bool_key exact_tags_only false) + + if [ "$exact_only" = true ]; then + version_tags="$php_version" + distro_tags="$distro_release" + fi + tags=$( IFS=',' generate_tags "$version_tags" "$distro_tags" \ | sed -E 's/(^|[[:space:]])/\1${REGISTRY}\/${REPO}:/g' \ @@ -207,13 +283,28 @@ generate_workflow() { local platforms=$(echo $platforms | sed 's/ /,/g') - tpl ci.yml.template php_minor targets platforms >> $workflow_file + # Docker Hub steps also need the secrets; dockerhub_push: false turns them off for this file + local dockerhub_push_enabled + dockerhub_push_enabled=$(bool_key dockerhub_push true) + + tpl ci.yml.template php_minor targets platforms dockerhub_push=dockerhub_push_enabled >> $workflow_file } -if [ "$1" = "clean" ]; then - eval $(generate_config ${2:-versions.yml}) - clean_all -else - eval $(generate_config ${1:-versions.yml}) - generate_all +# Usage: generate.sh [clean|check] [versions file] +case "$1" in + clean|check) mode="$1"; versions_file="${2:-versions.yml}" ;; + *) mode=generate; versions_file="${1:-versions.yml}" ;; +esac + +if [ ! -f "$versions_file" ]; then + echo "$versions_file: no such versions file" >&2 + exit 1 fi + +eval $(generate_config "$versions_file") +validate_config "$versions_file" + +case "$mode" in + clean) clean_all ;; + generate) generate_all ;; +esac diff --git a/versions.yml b/versions.yml index 4dee411..e17e813 100644 --- a/versions.yml +++ b/versions.yml @@ -1,9 +1,9 @@ php_versions: - 7.4.30 - 8.0.22 -- 8.1.9 composer_version: 2.4.1 +base_image: sunasteriskrnd/php alpine_releases: - alpine3.16 diff --git a/versions_7.3.yml b/versions_7.3.yml index 3e823c5..cb26ee1 100644 --- a/versions_7.3.yml +++ b/versions_7.3.yml @@ -2,6 +2,7 @@ php_versions: - 7.3.33 composer_version: 2.4.1 +base_image: sunasteriskrnd/php default_php_7_version: 7.4 default_distro: debian diff --git a/versions_8.1.yml b/versions_8.1.yml new file mode 100644 index 0000000..4a1b20c --- /dev/null +++ b/versions_8.1.yml @@ -0,0 +1,19 @@ +php_versions: +- 8.1.34 + +composer_version: 2.4.1 +base_image: ghcr.io/sun-asterisk-research/php +base_image_sha256: 52414238eb01bf163d0df29bb7c10adb04559a89cdd9242c8794c35defe7e998 + +default_php_8_version: 8.1 +default_distro: alpine +default_alpine_release: alpine3.22 + +alpine_releases: +- alpine3.22 + +platforms: +- linux/amd64 + +exact_tags_only: true +dockerhub_push: false diff --git a/versions_8.2.yml b/versions_8.2.yml index 10407f2..04bcf71 100644 --- a/versions_8.2.yml +++ b/versions_8.2.yml @@ -2,6 +2,7 @@ php_versions: - 8.2.1 composer_version: 2.4.1 +base_image: sunasteriskrnd/php default_php_8_version: 8.2 default_distro: debian From a986d3eaa144f30ede4baf3c1ba3e3c924652946 Mon Sep 17 00:00:00 2001 From: Bui Huy Hoang Date: Wed, 28 Oct 2026 08:39:27 +0700 Subject: [PATCH 2/3] ci: request packages write explicitly in the 8.1 workflow Exact-tag builds publish to ghcr with GITHUB_TOKEN, so the 8.1 workflow now declares read-only contents at the top and packages: write on the docker job instead of relying on the org default. --- .github/workflows/8.1.yml | 6 ++++++ ci.yml.template | 4 ++-- generate.sh | 13 ++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/8.1.yml b/.github/workflows/8.1.yml index 3178841..db08f3d 100644 --- a/.github/workflows/8.1.yml +++ b/.github/workflows/8.1.yml @@ -14,6 +14,9 @@ defaults: run: shell: 'bash -Eeuo pipefail -x {0}' +permissions: + contents: read + jobs: verify-templating: name: Verify templating @@ -31,6 +34,9 @@ jobs: runs-on: ubuntu-latest needs: - verify-templating + permissions: + contents: read + packages: write strategy: matrix: target: diff --git a/ci.yml.template b/ci.yml.template index feb3d40..0561f13 100644 --- a/ci.yml.template +++ b/ci.yml.template @@ -12,7 +12,7 @@ defaults: run: shell: 'bash -Eeuo pipefail -x {0}' -jobs: +{{ workflow_permissions }}jobs: verify-templating: name: Verify templating runs-on: ubuntu-latest @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest needs: - verify-templating - strategy: +{{ docker_permissions }} strategy: matrix: target: {{ targets }} diff --git a/generate.sh b/generate.sh index 224a7e7..d9f2242 100755 --- a/generate.sh +++ b/generate.sh @@ -287,7 +287,18 @@ generate_workflow() { local dockerhub_push_enabled dockerhub_push_enabled=$(bool_key dockerhub_push true) - tpl ci.yml.template php_minor targets platforms dockerhub_push=dockerhub_push_enabled >> $workflow_file + # Exact-tag builds publish to ghcr with GITHUB_TOKEN, so they ask for packages: write + # themselves rather than depend on the org default token permissions + local workflow_permissions="" + local docker_permissions="" + + if [ "$(bool_key exact_tags_only false)" = true ]; then + workflow_permissions=$'permissions:\n contents: read\n\n' + docker_permissions=$' permissions:\n contents: read\n packages: write\n' + fi + + tpl ci.yml.template php_minor targets platforms dockerhub_push=dockerhub_push_enabled \ + workflow_permissions docker_permissions >> $workflow_file } # Usage: generate.sh [clean|check] [versions file] From c330c1302bab66c4a5e1002b7ea328a45932d292 Mon Sep 17 00:00:00 2001 From: Bui Huy Hoang Date: Wed, 28 Oct 2026 09:04:24 +0700 Subject: [PATCH 3/3] fix: reject a sha256-prefixed base image digest with a clear message --- generate.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/generate.sh b/generate.sh index d9f2242..417f0a9 100755 --- a/generate.sh +++ b/generate.sh @@ -312,6 +312,12 @@ if [ ! -f "$versions_file" ]; then exit 1 fi +# generate_config cannot parse a value containing ':', so catch a prefixed digest before eval +if grep -qE "^base_image_sha256:[[:space:]]*[\"']?sha256:" "$versions_file"; then + echo "$versions_file: base_image_sha256 must be a 64-char hex sha256 without the 'sha256:' prefix" >&2 + exit 1 +fi + eval $(generate_config "$versions_file") validate_config "$versions_file"