Rebuild Latest Release #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Rebuild Latest Release | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 9 * * 2" | |
| env: | |
| GHCR_REPO: ghcr.io/${{ github.repository }} | |
| DOCKERHUB_REPO_NAME: ${{ vars.DOCKER_REPO }} | |
| DOCKERHUB_REPO: docker.io/${{ vars.DOCKER_REPO }} | |
| GOTOOLCHAIN: local | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| concurrency: | |
| group: rebuild-latest-release | |
| cancel-in-progress: false | |
| jobs: | |
| rebuild: | |
| name: Rebuild Latest Release Images | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Resolve latest release tag | |
| id: release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| TAG=$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name') | |
| if [[ -z "${TAG}" || "${TAG}" == "null" ]]; then | |
| echo "No latest release tag found" | |
| exit 1 | |
| fi | |
| VERSION="${TAG#v}" | |
| if ! [[ "${VERSION}" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then | |
| echo "Unsupported release tag: ${TAG}" | |
| exit 1 | |
| fi | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| echo "minor=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" >> "$GITHUB_OUTPUT" | |
| echo "major=${BASH_REMATCH[1]}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout latest release | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ steps.release.outputs.tag }} | |
| persist-credentials: 'false' | |
| - name: Resolve Go patch series | |
| id: go-version | |
| run: | | |
| set -euo pipefail | |
| GO_DIRECTIVE=$(awk '$1 == "go" { print $2; exit }' go.mod) | |
| if ! [[ "${GO_DIRECTIVE}" =~ ^([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]]; then | |
| echo "Unsupported go directive: ${GO_DIRECTIVE}" | |
| exit 1 | |
| fi | |
| echo "version=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.x" >> "$GITHUB_OUTPUT" | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ steps.go-version.outputs.version }} | |
| check-latest: true | |
| cache: true | |
| - name: Verify dependencies | |
| run: | | |
| go mod download | |
| go mod verify | |
| - name: Run tests | |
| run: go test -count 1 -v ./... | |
| - name: Validate registry configuration | |
| env: | |
| DOCKERHUB_USERNAME: ${{ vars.DOCKERHUB_USERNAME }} | |
| DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| test -n "${DOCKERHUB_REPO_NAME}" || { echo "DOCKER_REPO is not configured"; exit 1; } | |
| test -n "${DOCKERHUB_USERNAME}" || { echo "DOCKERHUB_USERNAME is not configured"; exit 1; } | |
| test -n "${DOCKERHUB_TOKEN}" || { echo "DOCKERHUB_TOKEN is not configured"; exit 1; } | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ github.token }} | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ vars.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Setup ko | |
| uses: ko-build/setup-ko@v0.9 | |
| - name: Install crane | |
| run: go install github.com/google/go-containerregistry/cmd/crane@v0.21.6 | |
| - name: Rebuild exact version in GHCR | |
| id: image | |
| env: | |
| KO_DOCKER_REPO: ${{ env.GHCR_REPO }} | |
| run: | | |
| set -euo pipefail | |
| IMAGE_REF=$(ko build --bare \ | |
| --platform=all \ | |
| --tags "${{ steps.release.outputs.version }}" \ | |
| .) | |
| if [[ "${IMAGE_REF}" != *@sha256:* ]]; then | |
| echo "ko image reference did not include a digest: ${IMAGE_REF}" | |
| exit 1 | |
| fi | |
| echo "digest=${IMAGE_REF##*@}" >> "$GITHUB_OUTPUT" | |
| - name: Copy rebuilt exact version to Docker Hub | |
| env: | |
| DIGEST: ${{ steps.image.outputs.digest }} | |
| VERSION: ${{ steps.release.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| crane copy "${GHCR_REPO}@${DIGEST}" "${DOCKERHUB_REPO}:${VERSION}" | |
| DOCKERHUB_DIGEST=$(crane digest "${DOCKERHUB_REPO}:${VERSION}") | |
| if [[ "${DOCKERHUB_DIGEST}" != "${DIGEST}" ]]; then | |
| echo "Registry digest mismatch: GHCR=${DIGEST}, Docker Hub=${DOCKERHUB_DIGEST}" | |
| exit 1 | |
| fi | |
| - name: Publish all release tags | |
| env: | |
| DIGEST: ${{ steps.image.outputs.digest }} | |
| VERSION: ${{ steps.release.outputs.version }} | |
| MINOR: ${{ steps.release.outputs.minor }} | |
| MAJOR: ${{ steps.release.outputs.major }} | |
| run: | | |
| set -euo pipefail | |
| for repository in "${GHCR_REPO}" "${DOCKERHUB_REPO}"; do | |
| crane tag "${repository}@${DIGEST}" "${VERSION}" | |
| crane tag "${repository}@${DIGEST}" "${MINOR}" | |
| crane tag "${repository}@${DIGEST}" "${MAJOR}" | |
| crane tag "${repository}@${DIGEST}" latest | |
| done | |
| - name: Install Cosign | |
| uses: sigstore/cosign-installer@v4.1.0 | |
| - name: Sign images | |
| env: | |
| DIGEST: ${{ steps.image.outputs.digest }} | |
| run: | | |
| set -euo pipefail | |
| cosign sign --yes "${GHCR_REPO}@${DIGEST}" | |
| cosign sign --yes "${DOCKERHUB_REPO}@${DIGEST}" | |
| - name: Attest GHCR build provenance | |
| uses: actions/attest-build-provenance@v4 | |
| with: | |
| subject-name: ${{ env.GHCR_REPO }} | |
| subject-digest: ${{ steps.image.outputs.digest }} | |
| push-to-registry: true | |
| - name: Attest Docker Hub build provenance | |
| uses: actions/attest-build-provenance@v4 | |
| with: | |
| subject-name: ${{ env.DOCKERHUB_REPO }} | |
| subject-digest: ${{ steps.image.outputs.digest }} | |
| push-to-registry: true |