Skip to content
Merged
Show file tree
Hide file tree
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
128 changes: 15 additions & 113 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,121 +11,23 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
IMAGE_NAME: json
MAJOR_VERSION: 11

permissions: {}

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15

docker:
permissions:
contents: read

strategy:
fail-fast: false
matrix:
platform: [linux/amd64, linux/arm64]

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up QEMU
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
platforms: ${{ matrix.platform }}
build-args: MAJOR_VERSION=${{ env.MAJOR_VERSION }}
load: true
tags: ${{ env.IMAGE_NAME }}
cache-from: type=gha,scope=${{ matrix.platform }}
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}

- name: Test
run: cat test.json | docker run -i --rm --platform ${{ matrix.platform }} ${{ env.IMAGE_NAME }} -ag name value

push:
# Ensure test job passes before pushing image.
needs: test

runs-on: ubuntu-latest
timeout-minutes: 15
if: github.event_name == 'push'

permissions:
contents: read
packages: write
id-token: write
attestations: write

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up QEMU
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Docker meta
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
flavor: latest=true
images: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}, ghcr.io/chorrell/${{ env.IMAGE_NAME }}
tags: ${{ env.MAJOR_VERSION }}

- name: Login to DockerHub
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Login to GitHub Container Registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
id: build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
platforms: linux/amd64,linux/arm64
build-args: MAJOR_VERSION=${{ env.MAJOR_VERSION }}
push: true
provenance: mode=max
sbom: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Attest Docker Hub image
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-name: index.docker.io/${{ secrets.DOCKERHUB_USERNAME }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true

- name: Attest GHCR image
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-name: ghcr.io/chorrell/${{ env.IMAGE_NAME }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
packages: write # push to GHCR with GITHUB_TOKEN
id-token: write # sign the provenance attestations
attestations: write # store the attestations
uses: chorrell/workflows/.github/workflows/docker-publish.yml@v1
with:
image-name: json
test-command: docker run -i --rm "$IMAGE" -ag name value < test.json
test-platforms: '["linux/amd64", "linux/arm64"]'
# MAJOR_VERSION: keep the build arg and the tag in step (and the Dockerfile ARG default)
build-args: MAJOR_VERSION=11
tags: "11"
secrets:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
8 changes: 8 additions & 0 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Allow my own reusable workflows (chorrell/workflows) to be called by tag;
# everything else keeps zizmor's default hash-pin policy.
rules:
unpinned-uses:
config:
policies:
"chorrell/*": ref-pin
30 changes: 17 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ npx markdownlint-cli2 <file>

### Version Management

- Maintain version in one place: `MAJOR_VERSION` env var in workflow
- Use build args to pass version to Dockerfile:
`--build-arg MAJOR_VERSION=${{ env.MAJOR_VERSION }}`
- The workflow passes the version to the Dockerfile as a build arg
(`build-args: MAJOR_VERSION=11`) and publishes it as an image tag (`tags: "11"`)
- Update version in these locations:
- `.github/workflows/docker-publish.yml` (MAJOR_VERSION env var)
- `.github/workflows/docker-publish.yml` (both `build-args` and `tags`; the
reusable-workflow call can't read a workflow `env` var)
- Dockerfile (ARG default)

## Project Structure
Expand All @@ -135,17 +135,21 @@ npx markdownlint-cli2 <file>

## CI/CD Pipeline

The GitHub Actions workflow (`docker-publish.yml`):
The GitHub Actions workflow (`docker-publish.yml`) calls the shared
[chorrell/workflows](https://github.com/chorrell/workflows) `docker-publish` workflow:

1. **Test job**: Builds image and runs test against `test.json`
2. **Push job**: Runs after test passes, pushes to Docker Hub and GHCR
1. **Test jobs** (`docker / test (linux/amd64)`, `docker / test (linux/arm64)`): build
the image per platform and run it against `test.json`
2. **Push job** (`docker / push`): on `main`, pushes to Docker Hub and GHCR and
attests build provenance in both

### Workflow Environment Variables
### Workflow Inputs

| Variable | Value | Description |
|---------------|-------|--------------------------------------|
| IMAGE_NAME | json | Image name |
| MAJOR_VERSION | 11 | Major version for json package |
| Input | Value | Description |
|--------------|------------------|--------------------------------|
| image-name | json | Image name |
| build-args | MAJOR_VERSION=11 | Major version for json package |
| tags | 11 | Published version tag |

## Security Considerations

Expand All @@ -159,7 +163,7 @@ The GitHub Actions workflow (`docker-publish.yml`):

### Update Node.js Version

1. Update `MAJOR_VERSION` in `.github/workflows/docker-publish.yml`
1. Update the version in `.github/workflows/docker-publish.yml` (`build-args` and `tags`)
2. Update base image tags in Dockerfile (e.g., `node:lts-alpine3.23` -> `node:lts-alpine3.24`)
3. Update Alpine version if needed

Expand Down
Loading