From 03b80c4a2b7d6ad8f726bcb10b5b028313673972 Mon Sep 17 00:00:00 2001 From: Josh Sokol Date: Fri, 21 Aug 2026 14:44:06 -0500 Subject: [PATCH 1/3] ci: delete the legacy rebuild entry-point workflows Their stated deletion condition is met: the first post-cutover RC published simplerisk/simplerisk 20260820-001-jammy/-noble, and GA promoted both images from those digests (run 32507524464). There is no longer a release path that needs a rebuild, so the escape hatch has nothing left to catch. Both were already dispatch-only and unreferenced outside their own files. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/push-to-dockerhub.yml | 53 ------------------------- .github/workflows/push-to-gh-pkgs.yml | 51 ------------------------ 2 files changed, 104 deletions(-) delete mode 100644 .github/workflows/push-to-dockerhub.yml delete mode 100644 .github/workflows/push-to-gh-pkgs.yml diff --git a/.github/workflows/push-to-dockerhub.yml b/.github/workflows/push-to-dockerhub.yml deleted file mode 100644 index c9c5f02..0000000 --- a/.github/workflows/push-to-dockerhub.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Push images to DockerHub - -# LEGACY REBUILD -- manual dispatch only, retained as a transitional escape hatch. -# -# Release images are no longer built here. Under the build-once-promote model -# (code-development docs/superpowers/specs/2026-07-10-release-image-promotion-design) -# every release image is built ONCE as the RC by publish-testing.yml on the -# `testing` branch, and promote-latest.yml retags that digest at GA. Rebuilding -# from the prod bundle on a master push produced GA bytes that were never the -# tested bytes, and raced the GA bundle upload: the release PR merges here -# minutes before the bundle lands in S3, so the build failed fail-closed with a -# bare 403. -# -# The `push: master` trigger is therefore gone. These jobs remain dispatchable -# so a release cut BEFORE the full-stack RC build landed can still be produced -# by hand. Delete this workflow once the first post-cutover RC has published -# simplerisk/simplerisk -jammy/-noble digests. - -on: - workflow_dispatch: - -permissions: - contents: read - -# On a job that uses a reusable workflow, it seems you cannot -# use env on a with block (https://github.com/actions/runner/issues/1189#issuecomment-1741672276) -env: - VERSION: "20240102-001" - -jobs: - simplerisk-jammy: - name: 'Push simplerisk/simplerisk image based on Ubuntu 22.04 (Jammy)' - uses: ./.github/workflows/push-to-dockerhub_rw.yml - with: - context_path: "simplerisk" - dockerfile_path: "simplerisk/Dockerfile" - image_name: "simplerisk/simplerisk" - version: "20260820-001" - os_version: "jammy" - build_args: "ubuntu_version_code=jammy" - secrets: inherit - simplerisk-noble: - name: 'Push simplerisk/simplerisk image based on Ubuntu 24.04 (Noble)' - uses: ./.github/workflows/push-to-dockerhub_rw.yml - with: - context_path: "simplerisk" - dockerfile_path: "simplerisk/Dockerfile" - image_name: "simplerisk/simplerisk" - version: "20260820-001" - os_version: "noble" - main_image: true - build_args: "ubuntu_version_code=noble" - secrets: inherit diff --git a/.github/workflows/push-to-gh-pkgs.yml b/.github/workflows/push-to-gh-pkgs.yml deleted file mode 100644 index 6c64788..0000000 --- a/.github/workflows/push-to-gh-pkgs.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Push images to GitHub Packages - -# LEGACY REBUILD -- manual dispatch only, retained as a transitional escape hatch. -# -# GHCR release images are no longer built here. promote-latest.yml mirrors the -# promoted Docker Hub digests into ghcr.io (cosign-signed) at GA, so the GHCR -# and Docker Hub images for a version are the same bytes. Rebuilding here meant -# ghcr and dockerhub were different images sharing a name, -# and the rebuild raced the GA bundle upload the same way the Docker Hub one did. -# -# See code-development docs/superpowers/specs/2026-07-10-release-image-promotion-design. -# Delete this workflow once the first post-cutover RC has published -# simplerisk/simplerisk -jammy/-noble digests. - -on: - workflow_dispatch: - -permissions: - contents: read - packages: write # callee push-to-gh-pkgs_rw pushes to ghcr.io - id-token: write # callee cosign-signs via sigstore/fulcio - -# On a job that uses a reusable workflow, it seems you cannot -# use env on a with block (https://github.com/actions/runner/issues/1189#issuecomment-1741672276) -env: - VERSION: "20240102-001" - -jobs: - simplerisk-jammy: - name: 'Push simplerisk/simplerisk image based on Ubuntu 22.04 (Jammy)' - uses: ./.github/workflows/push-to-gh-pkgs_rw.yml - with: - context_path: "simplerisk" - dockerfile_path: "simplerisk/Dockerfile" - image_name: "simplerisk" - version: "20260820-001" - os_version: "jammy" - build_args: "ubuntu_version_code=jammy" - secrets: inherit - simplerisk-noble: - name: 'Push simplerisk/simplerisk image based on Ubuntu 24.04 (Noble)' - uses: ./.github/workflows/push-to-gh-pkgs_rw.yml - with: - context_path: "simplerisk" - dockerfile_path: "simplerisk/Dockerfile" - image_name: "simplerisk" - version: "20260820-001" - os_version: "noble" - main_image: true - build_args: "ubuntu_version_code=noble" - secrets: inherit From 159f0910183cd1ad60ad7f82a5f365ef9556782f Mon Sep 17 00:00:00 2001 From: Josh Sokol Date: Fri, 21 Aug 2026 14:44:06 -0500 Subject: [PATCH 2/3] ci: delete the now-orphaned reusable push workflows push-to-dockerhub_rw.yml and push-to-gh-pkgs_rw.yml had exactly two callers between them -- the entry points removed in the previous commit. Nothing else in the repo references either file, so they are dead code rather than reusable building blocks. Split from the previous commit so it can be dropped independently if you would rather keep the generic build-and-push blocks around. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/push-to-dockerhub_rw.yml | 100 ----------------- .github/workflows/push-to-gh-pkgs_rw.yml | 120 --------------------- 2 files changed, 220 deletions(-) delete mode 100644 .github/workflows/push-to-dockerhub_rw.yml delete mode 100644 .github/workflows/push-to-gh-pkgs_rw.yml diff --git a/.github/workflows/push-to-dockerhub_rw.yml b/.github/workflows/push-to-dockerhub_rw.yml deleted file mode 100644 index c4fe8da..0000000 --- a/.github/workflows/push-to-dockerhub_rw.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Push resulting image to DockerHub - -on: - workflow_call: - inputs: - context_path: - description: Base path to perform the build - required: true - type: string - dockerfile_path: - description: Path where Dockerfile is located - required: true - type: string - image_name: - description: What would be the name of the image - required: true - type: string - version: - description: SimpleRisk version to upload - required: true - type: string - os_version: - description: Type of base image to put on the tag - required: true - type: string - main_image: - description: Is this the latest image? - default: false - type: boolean - build_args: - description: Arguments to use on image at runtime - type: string - platforms: - description: Target platforms for the build (e.g. linux/amd64,linux/arm64) - default: linux/amd64 - type: string - secrets: - DOCKER_USERNAME: - required: true - DOCKER_TOKEN: - required: true - -jobs: - dockerhub: - environment: release - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Log in to Docker Hub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_TOKEN }} - - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: ${{ inputs.image_name }} - - - name: Build and push main Docker image - if: ${{ inputs.main_image }} - id: build-and-push-main - uses: docker/build-push-action@v7 - with: - context: ${{ inputs.context_path }} - file: ${{ inputs.dockerfile_path }} - push: ${{ github.event_name != 'pull_request' }} - build-args: ${{ inputs.build_args || '' }} - platforms: ${{ inputs.platforms }} - tags: | - ${{ inputs.image_name }} - ${{ inputs.image_name }}:${{ inputs.version }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=${{ inputs.os_version }} - cache-to: type=gha,mode=max,scope=${{ inputs.os_version }} - - - name: Build and push specific Docker image - id: build-and-push-spec - uses: docker/build-push-action@v7 - with: - context: ${{ inputs.context_path }} - file: ${{ inputs.dockerfile_path }} - push: ${{ github.event_name != 'pull_request' }} - build-args: ${{ inputs.build_args || '' }} - platforms: ${{ inputs.platforms }} - tags: | - ${{ inputs.image_name }}:${{ inputs.version }}-${{ inputs.os_version }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=${{ inputs.os_version }} - cache-to: type=gha,mode=max,scope=${{ inputs.os_version }} - diff --git a/.github/workflows/push-to-gh-pkgs_rw.yml b/.github/workflows/push-to-gh-pkgs_rw.yml deleted file mode 100644 index 1e53003..0000000 --- a/.github/workflows/push-to-gh-pkgs_rw.yml +++ /dev/null @@ -1,120 +0,0 @@ -name: Push resulting image to Github Packages - -on: - workflow_call: - inputs: - context_path: - required: true - type: string - dockerfile_path: - required: true - type: string - image_name: - required: true - type: string - version: - required: true - type: string - os_version: - required: true - type: string - main_image: - default: false - type: boolean - build_args: - type: string - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - IMAGE_NAME: "${{ github.repository_owner }}/simplerisk" - -jobs: - github_packages: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. - id-token: write - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Install cosign - if: github.event_name != 'pull_request' - uses: sigstore/cosign-installer@v3.5.0 - with: - cosign-release: 'v2.4.0' - - # Workaround: https://github.com/docker/build-push-action/issues/461 - - name: Setup Docker buildx - uses: docker/setup-buildx-action@v4 - - - name: Log into registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v6 - with: - images: "ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }}" - - - name: Build and push main Docker image - id: build-and-push-main - if: ${{ inputs.main_image }} - uses: docker/build-push-action@v7 - with: - context: ${{ inputs.context_path }} - file: ${{ inputs.dockerfile_path }} - push: ${{ github.event_name != 'pull_request' }} - build-args: ${{ inputs.build_args || '' }} - tags: | - ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }} - ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }}:${{ inputs.version }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Sign the resulting Docker image digest except on PRs. - # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish - # transparency data even for private images, pass --yes to cosign below. - # https://github.com/sigstore/cosign - - name: Sign the published Docker image - if: ${{ inputs.main_image && github.event_name != 'pull_request' }} - # This step uses the identity token to provision an ephemeral certificate - # against the sigstore community Fulcio instance. - run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {}@${{ steps.build-and-push-main.outputs.digest }} - - - name: Build and push specific Docker image - id: build-and-push-spec - uses: docker/build-push-action@v7 - with: - context: ${{ inputs.context_path }} - file: ${{ inputs.dockerfile_path }} - push: ${{ github.event_name != 'pull_request' }} - build-args: ${{ inputs.build_args || '' }} - tags: | - ghcr.io/${{ github.repository_owner }}/${{ inputs.image_name }}:${{ inputs.version }}-${{ inputs.os_version }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Sign the resulting Docker image digest except on PRs. - # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish - # transparency data even for private images, pass --yes to cosign below. - # https://github.com/sigstore/cosign - - name: Sign the published Docker image - if: ${{ github.event_name != 'pull_request' }} - # This step uses the identity token to provision an ephemeral certificate - # against the sigstore community Fulcio instance. - run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes {}@${{ steps.build-and-push-spec.outputs.digest }} From cb1f667b0857a8e5a78fe732e1d861a709ed18a5 Mon Sep 17 00:00:00 2001 From: Josh Sokol Date: Fri, 21 Aug 2026 14:45:02 -0500 Subject: [PATCH 3/3] build: drop update_workflows.sh, now that no workflow carries a version pin Deleting the push workflows would have broken `make update_version`, not just left dead code. update_workflows.sh loops over `.github/workflows/push*`; with no matches bash leaves the literal glob, sed fails on the nonexistent path, and `set -e` exits 1 -- taking down step 1 of the release bump. Verified: the loop exits 1 against the post-deletion tree. The script only ever patched `version:` pins in those four workflows, and despite its name update_stack_and_workflows.sh touches only stack.yml, so nothing else needs it. The version now lives solely in the two generated Dockerfiles (`ENV version=`), which is where promote-latest.yml and create_new_tag.yml already read it. Removed from the Makefile and from gorin.toml -- the latter generates the Makefile, so leaving it would resurrect the call on the next `make generate_makefile`. CLAUDE.md's release-step list updated to match. Verified: `make update_version VERSION=20260820-001` succeeds and is idempotent (no Dockerfile churn). Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 14 ++++++++------ Makefile | 1 - gorin.toml | 3 +-- update_workflows.sh | 12 ------------ 4 files changed, 9 insertions(+), 21 deletions(-) delete mode 100755 update_workflows.sh diff --git a/CLAUDE.md b/CLAUDE.md index 25a04c4..1b287d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,11 +48,14 @@ shellcheck simplerisk/entrypoint.sh simplerisk-minimal/entrypoint.sh make update_version VERSION=YYYYMMDD-NNN ``` -This runs four scripts in sequence: -1. `update_workflows.sh` — patches version in push workflow files -2. `simplerisk/generate_dockerfile.sh` — regenerates the full-stack Dockerfile from a template -3. `simplerisk-minimal/update_stack_and_workflows.sh` — regenerates `stack.yml` (with a fresh random password) and updates workflow files -4. `simplerisk-minimal/generate_dockerfile.sh` — regenerates the minimal Dockerfile +This runs three scripts in sequence: +1. `simplerisk/generate_dockerfile.sh` — regenerates the full-stack Dockerfile from a template +2. `simplerisk-minimal/update_stack_and_workflows.sh` — regenerates `stack.yml` +3. `simplerisk-minimal/generate_dockerfile.sh` — regenerates the minimal Dockerfile + +The version now lives only in the two generated Dockerfiles (`ENV version=`), which is +where `promote-latest.yml` and `create_new_tag.yml` read it from. No workflow carries a +version pin any more. ### Nix dev environment @@ -119,7 +122,6 @@ The entrypoint script handles: - **PRs** trigger `container-validation.yml`: builds all 4 variants (jammy, noble, php81, php83), runs Dockle (Dockerfile linter) and Grype (CVE scanner, severity cutoff: critical, only-fixed). - **Release images are built once, then promoted — never rebuilt.** A push to `testing` runs `publish-testing.yml`, which builds both images from the current testing bundle and publishes immutable tags: `simplerisk-minimal` gets `-php83/-php84/-php85` (multi-arch `linux/amd64,linux/arm64`) and `simplerisk` gets `-jammy/-noble` (amd64). Each image's default variant also takes the bare `` and the floating `:testing`. - **GA is a manual promote, not a build.** After the release merges to `master`, dispatch `promote-latest.yml`. It retags Docker Hub `:latest` to the existing RC digest (`buildx imagetools create`, multi-arch preserved), mirrors the same digests to GHCR cosign-signed, and writes SSM `/simplerisk/customers/image-tag/latest`. Nothing is rebuilt, so the bytes validated in testing are the bytes that ship. A currency guard refuses to promote a version whose digest is not the one `:testing` currently points at. -- `push-to-dockerhub.yml` / `push-to-gh-pkgs.yml` are **legacy rebuild workflows, manual dispatch only** — they no longer run on a `master` push. See their headers; they are deletable once the first post-cutover RC has published full-stack RC digests. - The reusable workflow files (`*_rw.yml`) are called by the entry-point workflows. ### Vulnerability ignore list diff --git a/Makefile b/Makefile index c2f6fac..5eda093 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,6 @@ help: @echo -e "$$HELP_MESSAGE" update_version: - ./update_workflows.sh $(VERSION) ./simplerisk/generate_dockerfile.sh $(VERSION) ./simplerisk-minimal/update_stack_and_workflows.sh $(VERSION) ./simplerisk-minimal/generate_dockerfile.sh $(VERSION) diff --git a/gorin.toml b/gorin.toml index 42b630f..c8cb283 100644 --- a/gorin.toml +++ b/gorin.toml @@ -10,8 +10,7 @@ check_dependencies [options.update_version] description = "Updates the version of Dockerfiles, stacks and others" command = """ -\n\t./update_workflows.sh $(VERSION) -\t./simplerisk/generate_dockerfile.sh $(VERSION) +\n\t./simplerisk/generate_dockerfile.sh $(VERSION) \t./simplerisk-minimal/update_stack_and_workflows.sh $(VERSION) \t./simplerisk-minimal/generate_dockerfile.sh $(VERSION) """ diff --git a/update_workflows.sh b/update_workflows.sh deleted file mode 100755 index 34e3552..0000000 --- a/update_workflows.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -SCRIPT_LOCATION="$(dirname "$(readlink -f "$0")")" -readonly SCRIPT_LOCATION - -[ -z "${1:-}" ] && echo "No release version provided. Aborting." && exit 1 || release=$1 - -for workflow in "$SCRIPT_LOCATION"/.github/workflows/push*; do - sed -i -r "s/(version:) \"[0-9]{8,}-[0-9]{3,}\"/\1 \"${release}\"/g" "$workflow" -done