Skip to content

fix(ci): pin cosign-installer to v4.1.2 #3

fix(ci): pin cosign-installer to v4.1.2

fix(ci): pin cosign-installer to v4.1.2 #3

Workflow file for this run

name: Release
# Builds and publishes a multi-arch container image to GHCR.
#
# Triggers:
# - push to main → ghcr.io/<owner>/gluco-hub:edge + :sha-<short>
# - push of a v* tag → :X.Y.Z, :X.Y, :X, :latest, :sha-<short>
# - pull_request → build-only verification on both arches (no push)
# - workflow_dispatch → manual republish
#
# Architecture: separate native-runner jobs per platform (amd64 on
# ubuntu-latest, arm64 on ubuntu-24.04-arm) push by digest, then a
# merge job assembles the multi-arch manifest, signs it keyless with
# cosign, and attaches a SLSA build-provenance attestation. This is
# materially faster than QEMU emulation for a Rust workload.
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
workflow_dispatch:
# Don't cancel a release in flight if a newer commit lands — the
# in-flight build might be the one a user is about to pull. PRs are
# safe to cancel on rebase.
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/gluco-hub
jobs:
build:
name: build (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write # push image layers by digest (no-op on PRs)
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: Compute env
run: |
echo "BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
# platform "linux/arm64" → "linux-arm64", used as artifact suffix
echo "PLATFORM_PAIR=${PLATFORM//\//-}" >> "$GITHUB_ENV"
env:
PLATFORM: ${{ matrix.platform }}
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Only labels here — tags are computed in the merge job and applied
# via `buildx imagetools create -t <tag> ...`. Per-arch builds push
# by digest and have no human-readable tag of their own.
- name: Compute image labels
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.licenses=AGPL-3.0-or-later
- name: Build & push by digest
id: build
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
GLUCO_HUB_GIT_SHA=${{ github.sha }}
BUILD_DATE=${{ env.BUILD_DATE }}
# Per-platform cache scope so the two matrix jobs don't evict
# each other.
cache-from: type=gha,scope=${{ env.PLATFORM_PAIR }}
cache-to: type=gha,mode=max,scope=${{ env.PLATFORM_PAIR }}
# PRs build but don't push. Non-PR runs push by digest only —
# the merge job assembles the multi-arch manifest with proper
# tags. `name-canonical=true` ensures the digest is recorded
# against the canonical image name.
outputs: |
${{ github.event_name == 'pull_request'
&& 'type=cacheonly'
|| format('type=image,name={0}/{1},push-by-digest=true,name-canonical=true,push=true', env.REGISTRY, env.IMAGE_NAME) }}
# Provenance default for public repos is mode=max since
# build-push-action v6 — leaving implicit. SBOM must be opted
# into explicitly.
sbom: true
- name: Export digest
if: github.event_name != 'pull_request'
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: digest-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
merge:
name: merge & publish manifest
if: github.event_name != 'pull_request'
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # push manifest list to GHCR
id-token: write # cosign keyless OIDC + attestation signing
attestations: write # GitHub Artifact Attestations
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests
pattern: digest-*
merge-multiple: true
- uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute image metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=edge,branch=main
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,format=short
- name: Create manifest list & push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
- name: Inspect manifest
run: |
docker buildx imagetools inspect \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
- name: Resolve manifest digest
id: manifest
run: |
digest=$(docker buildx imagetools inspect \
"${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}" \
--format '{{json .Manifest.Digest}}' | tr -d '"')
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
- name: Install cosign
uses: sigstore/cosign-installer@v4.1.2
# Sign the manifest-list digest. One signature covers every tag
# pointing at the same digest — re-tagging doesn't invalidate it.
- name: Sign image (keyless)
env:
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
DIGEST: ${{ steps.manifest.outputs.digest }}
run: |
cosign sign --yes \
-a "repo=${{ github.repository }}" \
-a "workflow=${{ github.workflow }}" \
-a "ref=${{ github.sha }}" \
"${IMAGE}@${DIGEST}"
# Pushes a Sigstore-signed SLSA provenance bundle to the registry,
# discoverable in the GitHub UI and verifiable via:
# gh attestation verify oci://ghcr.io/<owner>/gluco-hub:<tag> \
# --owner <owner>
- name: Attest build provenance
uses: actions/attest-build-provenance@v4
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.manifest.outputs.digest }}
push-to-registry: true