Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Release Pipeline

on:
release:
types: [created]
workflow_dispatch: # Added for easier iterative testing as we discussed

env:
REGISTRY: ghcr.io
# This dynamically sets the base image name to your repo path
IMAGE_BASE: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Modernized to handle both components mentioned in your bootstrap script
include:
- service: backend
context: ./backend
image: ghcr.io/${{ github.repository }}/backend
- service: frontend
context: ./frontend
image: ghcr.io/${{ github.repository }}/frontend

permissions:
contents: read
packages: write
id-token: write # Required for Keyless Cosign signing
security-events: write # Required to upload Trivy scan results to Security tab

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ matrix.image }}
tags: |
type=semver,pattern={{version}}
type=sha,prefix=sha-
type=raw,value=latest,enable=${{ github.event_name == 'release' }}

- name: Build and push Docker image
id: build-push
uses: docker/build-push-action@v5
with:
context: ${{ matrix.context }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Modern Feature: GitHub Actions Cache to speed up iterative builds
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.20.0
with:
image-ref: ${{ matrix.image }}@${{ steps.build-push.outputs.digest }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'

- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
category: ${{ matrix.service }}

- name: Install Cosign
uses: sigstore/cosign-installer@v3.5.0

- name: Sign image and Attest SBOM
env:
DIGEST: ${{ steps.build-push.outputs.digest }}
run: |
# Keyless signing via GitHub OIDC
cosign sign --yes "${{ matrix.image }}@${{ env.DIGEST }}"

# Modern Feature: Instead of just 'attaching', we create a signed attestation
# This makes the SBOM part of the image's verifiable transparency log
cosign attest --yes --type cyclonedx --predicate <(trivy image --format cyclonedx "${{ matrix.image }}@${{ env.DIGEST }}") "${{ matrix.image }}@${{ env.DIGEST }}"

- name: Generate SLSA Provenance
# This provides a non-falsifiable record of where and how the image was built
uses: github-early-access/generate-build-provenance@v1
with:
subject-name: ${{ matrix.image }}
subject-digest: ${{ steps.build-push.outputs.digest }}
push-to-registry: true
Loading