bake all the things #20
Workflow file for this run
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: Publish Docker Image to GHCR | ||
| on: | ||
| push: | ||
| tags: | ||
| - '*-v*.*.*' # Matches hybrid tags like 17.2-v1.0.0 | ||
| - 'v*.*.*' # Also matches simple semantic tags like v1.0.0 | ||
| env: | ||
| REGISTRY: ghcr.io | ||
| permissions: | ||
| contents: write | ||
| packages: write | ||
| id-token: write | ||
| attestations: write | ||
| jobs: | ||
| build-and-push: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - service: postgres | ||
| dockerfile: postgres/Dockerfile | ||
| context: . | ||
| - service: valkey | ||
| dockerfile: docker/valkey/Dockerfile | ||
| context: . | ||
| - service: pgbouncer | ||
| dockerfile: docker/pgbouncer/Dockerfile | ||
| context: . | ||
| - service: rabbitmq | ||
| dockerfile: docker/rabbitmq/Dockerfile | ||
| context: . | ||
| - service: memcached | ||
| dockerfile: docker/memcached/Dockerfile | ||
| context: . | ||
| - service: pghero | ||
| dockerfile: docker/pghero/Dockerfile | ||
| context: . | ||
| - service: network-probe | ||
| dockerfile: docker/network-probe/Dockerfile | ||
| context: . | ||
| - service: network-guard | ||
| dockerfile: docker/network-guard/Dockerfile | ||
| context: . | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # Full history for proper versioning | ||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
| - name: Log in to GitHub Container Registry | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| registry: ${{ env.REGISTRY }} | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Extract version information | ||
| id: version | ||
| run: | | ||
| TAG_NAME="${GITHUB_REF#refs/tags/}" | ||
| { | ||
| echo "tag=${TAG_NAME}" | ||
| } >>"$GITHUB_OUTPUT" | ||
| if [[ $TAG_NAME =~ ^([0-9]+\.[0-9]+)-v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then | ||
| PG_VERSION="${BASH_REMATCH[1]}" | ||
| SEM_VERSION="${BASH_REMATCH[2]}" | ||
| PG_MAJOR="${PG_VERSION%%.*}" | ||
| SEM_MAJOR="${SEM_VERSION%%.*}" | ||
| SEM_MINOR="${SEM_VERSION%.*}" | ||
| { | ||
| echo "pg_version=${PG_VERSION}" | ||
| echo "pg_major=${PG_MAJOR}" | ||
| echo "sem_version=${SEM_VERSION}" | ||
| echo "sem_major=${SEM_MAJOR}" | ||
| echo "sem_minor=${SEM_MINOR}" | ||
| echo "is_hybrid=true" | ||
| } >>"$GITHUB_OUTPUT" | ||
| else | ||
| echo "is_hybrid=false" >>"$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Derive image metadata | ||
| id: image-meta | ||
| run: | | ||
| case "${{ matrix.service }}" in | ||
| postgres) | ||
| title="Core Data PostgreSQL" | ||
| desc="Hardened PostgreSQL 17 image with spatial/vector/graph extensions." | ||
| ;; | ||
| valkey) | ||
| title="Core Data ValKey" | ||
| desc="Managed ValKey cache tuned for the Core Data stack." | ||
| ;; | ||
| pgbouncer) | ||
| title="Core Data PgBouncer" | ||
| desc="PgBouncer pooler with Core Data authentication/allowlist wiring." | ||
| ;; | ||
| rabbitmq) | ||
| title="Core Data RabbitMQ" | ||
| desc="RabbitMQ broker + management console configured for Core Data." | ||
| ;; | ||
| memcached) | ||
| title="Core Data Memcached" | ||
| desc="Memcached cache sidecar aligned with Core Data defaults." | ||
| ;; | ||
| pghero) | ||
| title="Core Data PgHero" | ||
| desc="PgHero observability container pre-wired for Core Data Postgres." | ||
| ;; | ||
| network-probe) | ||
| title="Core Data Network Probe" | ||
| desc="Host network discovery helper for Core Data allow lists." | ||
| ;; | ||
| network-guard) | ||
| title="Core Data Network Guard" | ||
| desc="Firewall enforcement helper for Core Data service ports." | ||
| ;; | ||
| *) | ||
| title="Core Data ${ { matrix.service } }" | ||
| desc="Core Data stack image." | ||
| ;; | ||
| esac | ||
| { | ||
| echo "title=${title}" | ||
| echo "description=${desc}" | ||
| } >>"$GITHUB_OUTPUT" | ||
| - name: Prepare build args | ||
| id: build-args | ||
| env: | ||
| PG_VERSION: ${{ steps.version.outputs.pg_major || '17' }} | ||
| run: | | ||
| if [ "${{ matrix.service }}" = "postgres" ]; then | ||
| cat <<EOF >>"$GITHUB_OUTPUT" | ||
| args<<EOT | ||
| CORE_UID=999 | ||
| CORE_GID=999 | ||
| CORE_USERNAME=postgres | ||
| CORE_GECOS=Core Data PostgreSQL Administrator | ||
| CORE_HOME=/home/postgres | ||
| PG_VERSION=${PG_VERSION} | ||
| AGE_VERSION=master | ||
| EOT | ||
| EOF | ||
| else | ||
| echo "args=" >>"$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Extract Docker metadata | ||
| id: meta | ||
| uses: docker/metadata-action@v5 | ||
| with: | ||
| images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }} | ||
| tags: | | ||
| # For hybrid tags (17.2-v1.0.0), create multiple tags | ||
| type=raw,value=${{ steps.version.outputs.tag }},enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| type=raw,value=${{ steps.version.outputs.pg_version }}-v${{ steps.version.outputs.sem_minor }},enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| type=raw,value=${{ steps.version.outputs.pg_version }}-v${{ steps.version.outputs.sem_major }},enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| type=raw,value=${{ steps.version.outputs.pg_version }},enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| type=raw,value=${{ steps.version.outputs.pg_major }},enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| type=raw,value=latest,enable=${{ steps.version.outputs.is_hybrid == 'true' }} | ||
| # For simple semantic tags (v1.0.0) | ||
| type=semver,pattern={{version}},enable=${{ steps.version.outputs.is_hybrid == 'false' }} | ||
| type=semver,pattern={{major}}.{{minor}},enable=${{ steps.version.outputs.is_hybrid == 'false' }} | ||
| type=semver,pattern={{major}},enable=${{ steps.version.outputs.is_hybrid == 'false' }} | ||
| type=raw,value=latest,enable=${{ steps.version.outputs.is_hybrid == 'false' }} | ||
| labels: | | ||
| org.opencontainers.image.title=${{ steps.image-meta.outputs.title }} | ||
| org.opencontainers.image.description=${{ steps.image-meta.outputs.description }} | ||
| org.opencontainers.image.vendor=${{ github.repository_owner }} | ||
| org.opencontainers.image.source=${{ github.repositoryUrl }} | ||
| org.opencontainers.image.revision=${{ github.sha }} | ||
| org.opencontainers.image.created=${{ steps.meta.outputs.created }} | ||
| org.opencontainers.image.url=https://github.com/${{ github.repository }} | ||
| org.opencontainers.image.documentation=https://github.com/${{ github.repository }}#published-docker-images | ||
| - name: Build and push Docker image | ||
| id: push | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: ${{ matrix.context }} | ||
| file: ./${{ matrix.dockerfile }} | ||
| platforms: linux/amd64 | ||
| push: true | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
| build-args: ${{ steps.build-args.outputs.args }} | ||
| - name: Install cosign | ||
| uses: sigstore/cosign-installer@v3.6.0 | ||
| - name: Sign image with cosign (keyless) | ||
| env: | ||
| COSIGN_YES: "true" | ||
| COSIGN_EXPERIMENTAL: "1" | ||
| run: | | ||
| image_ref="${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }}" | ||
| cosign sign "${image_ref}" | ||
| - name: Verify cosign signature | ||
| env: | ||
| COSIGN_EXPERIMENTAL: "1" | ||
| run: | | ||
| image_ref="${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }}" | ||
| cosign verify \ | ||
| --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/publish-docker.yml@${{ github.ref }}" \ | ||
| --certificate-oidc-issuer https://token.actions.githubusercontent.com \ | ||
| "${image_ref}" | ||
| - name: Generate artifact attestation | ||
| uses: actions/attest-build-provenance@v1 | ||
| with: | ||
| subject-name: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }} | ||
| subject-digest: ${{ steps.push.outputs.digest }} | ||
| push-to-registry: true | ||
| - name: Generate SBOM | ||
| uses: anchore/sbom-action@v0 | ||
| with: | ||
| image: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }} | ||
| format: cyclonedx-json | ||
| output-file: sbom.cyclonedx.json | ||
| - name: Attest SBOM | ||
| uses: actions/attest-sbom@v1 | ||
| with: | ||
| subject-name: ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }} | ||
| subject-digest: ${{ steps.push.outputs.digest }} | ||
| sbom-path: sbom.cyclonedx.json | ||
| push-to-registry: true | ||
| - name: Sign SBOM with cosign | ||
| env: | ||
| COSIGN_YES: "true" | ||
| COSIGN_EXPERIMENTAL: "1" | ||
| run: | | ||
| image_ref="${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }}" | ||
| cosign attest \ | ||
| --predicate sbom.cyclonedx.json \ | ||
| --type cyclonedx \ | ||
| "${image_ref}" | ||
| - name: Output image information | ||
| run: | | ||
| cat <<'EOF' | sed 's/^[[:space:]]\{1,\}//' >>"$GITHUB_STEP_SUMMARY" | ||
| ### 🐳 Docker Image Published | ||
| **Image:** `${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}` | ||
| **Digest:** `${{ steps.push.outputs.digest }}` | ||
| **Tags:** | ||
| ``` | ||
| ${{ steps.meta.outputs.tags }} | ||
| ``` | ||
| **Verify attestation:** | ||
| ```bash | ||
| gh attestation verify oci://${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }} --owner ${{ github.repository_owner }} | ||
| ``` | ||
| **Verify signature (cosign):** | ||
| ```bash | ||
| cosign verify \ | ||
| --certificate-identity "https://github.com/${{ github.repository }}/.github/workflows/publish-docker.yml@${{ github.ref }}" \ | ||
| --certificate-oidc-issuer https://token.actions.githubusercontent.com \ | ||
| oci://${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}@${{ steps.push.outputs.digest }} | ||
| ``` | ||
| **Pull image:** | ||
| ```bash | ||
| docker pull ${{ env.REGISTRY }}/${{ github.repository }}/${{ matrix.service }}:${{ steps.version.outputs.tag }} | ||
| ``` | ||
| EOF | ||