mirror of
https://github.com/ghndrx/github-actions-library.git
synced 2026-02-10 06:45:02 +00:00
feat(docker): add Docker CI/CD reusable workflow
- OIDC authentication to GHCR (keyless, no secrets required) - Multi-platform builds (linux/amd64, linux/arm64) - SBOM generation and attestation - Build provenance attestation - Trivy vulnerability scanning with SARIF upload - GitHub Actions cache for layer reuse - Semantic version tagging from git refs - All actions pinned to SHA for supply chain security Follows 2026 GitHub Actions security best practices: - Pin dependencies by SHA - Generate software attestations - Scan for vulnerabilities before push
This commit is contained in:
206
.github/workflows/docker-ci.yml
vendored
Normal file
206
.github/workflows/docker-ci.yml
vendored
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Docker CI/CD Reusable Workflow
|
||||||
|
# Builds, scans, and pushes container images with attestations
|
||||||
|
#
|
||||||
|
# Features:
|
||||||
|
# - OIDC authentication (no secrets required for GHCR)
|
||||||
|
# - Multi-platform builds (linux/amd64, linux/arm64)
|
||||||
|
# - SBOM generation and attestation
|
||||||
|
# - Trivy vulnerability scanning
|
||||||
|
# - Build provenance attestation
|
||||||
|
# - Smart caching with GitHub Actions cache
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# jobs:
|
||||||
|
# docker:
|
||||||
|
# uses: ghndrx/github-actions-library/.github/workflows/docker-ci.yml@main
|
||||||
|
# with:
|
||||||
|
# image-name: my-app
|
||||||
|
# push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
# permissions:
|
||||||
|
# contents: read
|
||||||
|
# packages: write
|
||||||
|
# id-token: write
|
||||||
|
# attestations: write
|
||||||
|
|
||||||
|
name: Docker CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
image-name:
|
||||||
|
description: 'Image name (without registry prefix)'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
context:
|
||||||
|
description: 'Docker build context path'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: '.'
|
||||||
|
dockerfile:
|
||||||
|
description: 'Path to Dockerfile'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: 'Dockerfile'
|
||||||
|
push:
|
||||||
|
description: 'Push image to registry'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
platforms:
|
||||||
|
description: 'Target platforms (comma-separated)'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: 'linux/amd64,linux/arm64'
|
||||||
|
build-args:
|
||||||
|
description: 'Build arguments (newline-separated KEY=value)'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
target:
|
||||||
|
description: 'Docker build target stage'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: ''
|
||||||
|
scan-severity:
|
||||||
|
description: 'Trivy scan severity threshold (CRITICAL,HIGH,MEDIUM,LOW)'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
default: 'CRITICAL,HIGH'
|
||||||
|
fail-on-vuln:
|
||||||
|
description: 'Fail workflow if vulnerabilities found'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
generate-sbom:
|
||||||
|
description: 'Generate SBOM attestation'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
generate-provenance:
|
||||||
|
description: 'Generate build provenance attestation'
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
outputs:
|
||||||
|
image-digest:
|
||||||
|
description: 'Image digest (sha256:...)'
|
||||||
|
value: ${{ jobs.build.outputs.digest }}
|
||||||
|
image-tags:
|
||||||
|
description: 'Generated image tags (JSON array)'
|
||||||
|
value: ${{ jobs.build.outputs.tags }}
|
||||||
|
sbom-attestation-id:
|
||||||
|
description: 'SBOM attestation bundle ID'
|
||||||
|
value: ${{ jobs.build.outputs.sbom-id }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build & Push
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
outputs:
|
||||||
|
digest: ${{ steps.build.outputs.digest }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
sbom-id: ${{ steps.sbom-attest.outputs.bundle-id }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
if: inputs.push
|
||||||
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}
|
||||||
|
tags: |
|
||||||
|
# Branch name
|
||||||
|
type=ref,event=branch
|
||||||
|
# PR number
|
||||||
|
type=ref,event=pr
|
||||||
|
# Semantic version tags
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}},enable=${{ !startsWith(github.ref, 'refs/tags/v0.') }}
|
||||||
|
# Short SHA
|
||||||
|
type=sha,prefix=sha-,format=short
|
||||||
|
# Latest on default branch
|
||||||
|
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
id: build
|
||||||
|
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
|
||||||
|
with:
|
||||||
|
context: ${{ inputs.context }}
|
||||||
|
file: ${{ inputs.context }}/${{ inputs.dockerfile }}
|
||||||
|
platforms: ${{ inputs.platforms }}
|
||||||
|
push: ${{ inputs.push }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: ${{ inputs.build-args }}
|
||||||
|
target: ${{ inputs.target }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
provenance: ${{ inputs.generate-provenance }}
|
||||||
|
sbom: ${{ inputs.generate-sbom }}
|
||||||
|
|
||||||
|
- name: Generate SBOM attestation
|
||||||
|
if: inputs.push && inputs.generate-sbom
|
||||||
|
id: sbom-attest
|
||||||
|
uses: actions/attest-sbom@115c3be05ff3974bcbd596578934b3f9ce39bf68 # v2.1.0
|
||||||
|
with:
|
||||||
|
subject-name: ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}
|
||||||
|
subject-digest: ${{ steps.build.outputs.digest }}
|
||||||
|
sbom-path: ${{ runner.temp }}/sbom.spdx.json
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Run Trivy vulnerability scanner
|
||||||
|
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # v0.29.0
|
||||||
|
with:
|
||||||
|
image-ref: ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}@${{ steps.build.outputs.digest }}
|
||||||
|
format: 'sarif'
|
||||||
|
output: 'trivy-results.sarif'
|
||||||
|
severity: ${{ inputs.scan-severity }}
|
||||||
|
exit-code: ${{ inputs.fail-on-vuln && '1' || '0' }}
|
||||||
|
if: inputs.push
|
||||||
|
|
||||||
|
- name: Upload Trivy scan results
|
||||||
|
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||||
|
with:
|
||||||
|
sarif_file: 'trivy-results.sarif'
|
||||||
|
if: inputs.push && always()
|
||||||
|
|
||||||
|
- name: Output summary
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "## 🐳 Docker Build Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Image | \`ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Digest | \`${{ steps.build.outputs.digest }}\` |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Platforms | ${{ inputs.platforms }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Pushed | ${{ inputs.push }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Provenance | ${{ inputs.generate-provenance }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| SBOM | ${{ inputs.generate-sbom }} |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Tags" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||||
75
README.md
75
README.md
@@ -10,6 +10,7 @@ Reusable GitHub Actions workflows and composite actions for CI/CD pipelines.
|
|||||||
| Workflow | Description |
|
| Workflow | Description |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
| [`python-ci.yml`](.github/workflows/python-ci.yml) | Python CI with UV (lint, type-check, test, security) |
|
| [`python-ci.yml`](.github/workflows/python-ci.yml) | Python CI with UV (lint, type-check, test, security) |
|
||||||
|
| [`docker-ci.yml`](.github/workflows/docker-ci.yml) | Docker CI/CD with OIDC, attestations, and security scanning |
|
||||||
|
|
||||||
## Composite Actions
|
## Composite Actions
|
||||||
|
|
||||||
@@ -106,6 +107,80 @@ pythonVersion = "3.12"
|
|||||||
typeCheckingMode = "standard"
|
typeCheckingMode = "standard"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker CI Workflow Features
|
||||||
|
|
||||||
|
The `docker-ci.yml` reusable workflow provides production-ready container builds:
|
||||||
|
|
||||||
|
- **OIDC authentication** - Keyless auth to GHCR (no secrets needed)
|
||||||
|
- **Multi-platform builds** - linux/amd64 + linux/arm64 by default
|
||||||
|
- **SBOM generation** - Software Bill of Materials attestation
|
||||||
|
- **Build provenance** - Cryptographic proof of build origin
|
||||||
|
- **Trivy scanning** - Vulnerability detection with SARIF upload
|
||||||
|
- **Smart caching** - GitHub Actions cache for layer reuse
|
||||||
|
- **Semantic tagging** - Auto-tags from git refs and versions
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# .github/workflows/docker.yml
|
||||||
|
name: Docker
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
tags: ['v*']
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
uses: ghndrx/github-actions-library/.github/workflows/docker-ci.yml@main
|
||||||
|
with:
|
||||||
|
image-name: my-app
|
||||||
|
push: ${{ github.event_name != 'pull_request' }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inputs
|
||||||
|
|
||||||
|
| Input | Type | Default | Description |
|
||||||
|
|-------|------|---------|-------------|
|
||||||
|
| `image-name` | string | *required* | Image name (without registry) |
|
||||||
|
| `context` | string | `.` | Docker build context path |
|
||||||
|
| `dockerfile` | string | `Dockerfile` | Dockerfile path relative to context |
|
||||||
|
| `push` | boolean | `false` | Push image to GHCR |
|
||||||
|
| `platforms` | string | `linux/amd64,linux/arm64` | Target platforms |
|
||||||
|
| `build-args` | string | `''` | Build args (newline-separated) |
|
||||||
|
| `target` | string | `''` | Multi-stage build target |
|
||||||
|
| `scan-severity` | string | `CRITICAL,HIGH` | Trivy severity threshold |
|
||||||
|
| `fail-on-vuln` | boolean | `false` | Fail on vulnerabilities |
|
||||||
|
| `generate-sbom` | boolean | `true` | Generate SBOM attestation |
|
||||||
|
| `generate-provenance` | boolean | `true` | Generate provenance attestation |
|
||||||
|
|
||||||
|
### Outputs
|
||||||
|
|
||||||
|
| Output | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `image-digest` | Image digest (sha256:...) |
|
||||||
|
| `image-tags` | Generated tags (JSON array) |
|
||||||
|
| `sbom-attestation-id` | SBOM attestation bundle ID |
|
||||||
|
|
||||||
|
### Security Features
|
||||||
|
|
||||||
|
All actions are **pinned to SHA** for supply chain security:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Images pushed to GHCR include:
|
||||||
|
- **SBOM attestation** - Full dependency manifest
|
||||||
|
- **Build provenance** - Verifiable build metadata
|
||||||
|
- **Vulnerability scan results** - Uploaded as SARIF to Security tab
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
Reference in New Issue
Block a user