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
35 changes: 22 additions & 13 deletions .github/actions/docker/build_and_push/action.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
name: Build and Push Multi-arch Docker Image
description: "Build a multi-arch image and push it to a GCP or Docker Hub registry"

inputs:
registry:
Expand Down Expand Up @@ -59,40 +60,48 @@ runs:
using: "composite"
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
if: ${{ contains(inputs.platforms, 'linux/arm64') }}

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

- name: Set HEAD commit hash
id: sha_tag
uses: pubky/ci-workflows/.github/actions/docker/get_head_commit_hash@main
with:
path: ${{ inputs.context }}
shell: bash
env:
CONTEXT_PATH: ${{ inputs.context }}
run: |
cd "$CONTEXT_PATH"
echo "hash=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
if: ${{ inputs.sha_tag }}

- name: Set cache values
shell: bash
id: cache
env:
CACHE_FROM_INPUT: ${{ inputs.cache_from }}
CACHE_TO_INPUT: ${{ inputs.cache_to }}
REGISTRY: ${{ inputs.registry }}
IMAGE: ${{ inputs.image }}
run: |
CACHE_FROM="${{ inputs.cache_from }}"
CACHE_TO="${{ inputs.cache_to }}"
CACHE_FROM="$CACHE_FROM_INPUT"
CACHE_TO="$CACHE_TO_INPUT"

if [ -z "$CACHE_FROM" ]; then
CACHE_FROM="type=registry,ref=${{ inputs.registry }}/${{ inputs.image }}:cache"
CACHE_FROM="type=registry,ref=$REGISTRY/$IMAGE:cache"
fi

if [ -z "$CACHE_TO" ]; then
CACHE_TO="type=registry,ref=${{ inputs.registry }}/${{ inputs.image }}:cache,mode=max"
CACHE_TO="type=registry,ref=$REGISTRY/$IMAGE:cache,mode=max"
fi

echo "from=$CACHE_FROM" >> $GITHUB_OUTPUT
echo "to=$CACHE_TO" >> $GITHUB_OUTPUT
echo "from=$CACHE_FROM" >> "$GITHUB_OUTPUT"
echo "to=$CACHE_TO" >> "$GITHUB_OUTPUT"

- name: Set image tags
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
with:
images: |
${{ inputs.registry }}/${{ inputs.image }}
Expand All @@ -103,7 +112,7 @@ runs:

- name: Build and push image
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
push: ${{ inputs.push }}
platforms: ${{ inputs.platforms }}
Expand Down
10 changes: 7 additions & 3 deletions .github/actions/docker/check_if_image_exists/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ runs:
using: "composite"
steps:
- id: check_image
env:
IMAGE: ${{ inputs.image }}
TAG: ${{ inputs.tag }}
ARCH: ${{ inputs.arch }}
run: |
if docker manifest inspect ${{ inputs.image }}:${{ inputs.tag }} | jq '.manifests[].platform | [.os, .architecture] | join("/")' | grep -qi "${{ inputs.arch }}"; then
echo "exists=true" >> $GITHUB_OUTPUT
if docker manifest inspect "$IMAGE:$TAG" | jq '.manifests[].platform | [.os, .architecture] | join("/")' | grep -qi "$ARCH"; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
shell: bash
8 changes: 5 additions & 3 deletions .github/actions/docker/get_head_commit_hash/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "Get HEAD commit hash"
description: "Get HEAD commit hash"
description: "Get HEAD commit hash. Deprecated: build_and_push resolves the hash itself"

inputs:
path:
Expand All @@ -14,7 +14,9 @@ runs:
using: "composite"
steps:
- id: get_hash
env:
TARGET_PATH: ${{ inputs.path }}
run: |
cd ${{ inputs.path }}
echo "value=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
cd "$TARGET_PATH"
echo "value=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
shell: bash
12 changes: 7 additions & 5 deletions .github/actions/docker/registry_login/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,25 @@ runs:
- name: Set registry type
id: registry
shell: bash
env:
REGISTRY: ${{ inputs.registry }}
run: |
if [[ ${{ inputs.registry }} =~ ^.*-docker.pkg.dev.*$ ]]; then
echo "type=gcp" >> $GITHUB_OUTPUT
if [[ "$REGISTRY" =~ ^.*-docker.pkg.dev.*$ ]]; then
echo "type=gcp" >> "$GITHUB_OUTPUT"
else
echo "type=dockerhub" >> $GITHUB_OUTPUT
echo "type=dockerhub" >> "$GITHUB_OUTPUT"
fi

- name: Login to GCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ inputs.registry }}
username: _json_key_base64
password: ${{ inputs.gcp_service_account_key }}
if: steps.registry.outputs.type == 'gcp'

- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ inputs.dockerhub_login }}
password: ${{ inputs.dockerhub_password }}
Expand Down
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: github-actions
directories:
- /
- /.github/actions/**
schedule:
interval: weekly
cooldown:
default-days: 7
commit-message:
prefix: "fix"
90 changes: 90 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: smoke

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
build_and_push:
name: build_and_push (${{ matrix.platforms }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platforms:
- linux/amd64
- linux/amd64,linux/arm64
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Build without pushing
uses: $/.github/actions/docker/build_and_push
with:
registry: localhost:5000
image: smoke
context: tests/smoke
platforms: ${{ matrix.platforms }}
push: false
cache_from: type=gha
cache_to: type=gha,mode=max

check_if_image_exists:
name: check_if_image_exists
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Look up a tag that exists
id: present
uses: $/.github/actions/docker/check_if_image_exists
with:
image: docker.io/library/alpine
tag: "3.22"
arch: linux/amd64

- name: Look up a tag that does not exist
id: absent
uses: $/.github/actions/docker/check_if_image_exists
with:
image: docker.io/library/alpine
tag: "0.0.0-no-such-tag"
arch: linux/amd64

- name: Assert
env:
PRESENT: ${{ steps.present.outputs.exists }}
ABSENT: ${{ steps.absent.outputs.exists }}
run: |
test "$PRESENT" = "true"
test "$ABSENT" = "false"

get_head_commit_hash:
name: get_head_commit_hash (deprecated)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Resolve HEAD
id: hash
uses: $/.github/actions/docker/get_head_commit_hash
with:
path: .

- name: Assert
env:
HASH: ${{ steps.hash.outputs.hash }}
run: echo "$HASH" | grep -qE '^[0-9a-f]{40}$'
28 changes: 28 additions & 0 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: zizmor

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
zizmor:
name: zizmor
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Run zizmor
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
with:
version: 1.30.0
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# ci-workflows

Shared GitHub Actions for the Pubky organisation. Changing anything here changes the
builds of every consuming repository, so read the policy below before opening a PR.

## Actions

| Action | Purpose |
|---|---|
| `docker/build_and_push` | Build a multi-arch image and push it to GCP Artifact Registry or Docker Hub |
| `docker/registry_login` | Log in to either registry, chosen from the registry hostname |
| `docker/check_if_image_exists` | Check whether a tag already exists for a given architecture |
| `docker/get_head_commit_hash` | **Deprecated.** `build_and_push` resolves the hash itself |

```yaml
- uses: pubky/ci-workflows/.github/actions/docker/registry_login@main
with:
registry: europe-west6-docker.pkg.dev/infra-464608/synonym-private-repo
gcp_service_account_key: ${{ secrets.GCR_JSON_KEY }}

- uses: pubky/ci-workflows/.github/actions/docker/build_and_push@main
with:
registry: europe-west6-docker.pkg.dev/infra-464608/synonym-private-repo
image: my-service
context: .
```

## Policy

**Third-party actions are pinned to a commit SHA**, with the version in a trailing comment:

```yaml
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
```

A tag can be moved by its owner; a SHA cannot. The comment is not decoration — Dependabot
reads it to work out which version a pin corresponds to, and raises bump PRs weekly with a
7-day cooldown so a freshly published release is never proposed the moment it lands.

**No action here may reference another action in this repository.** Doing so reintroduces a
floating `@main` that a consumer cannot pin past.

**`zizmor` runs on every pull request and blocks the merge.** Results are uploaded to the
repository's Security tab as SARIF. To reproduce locally:

```
docker run --rm -e GH_TOKEN="$(gh auth token)" -v "$PWD:/src:ro" -w /src \
ghcr.io/zizmorcore/zizmor:1.30.0 .
```

## Versioning

Releases are tagged from `v1.0.0`. Consumers currently reference `@main`; the tags exist so
that a later migration to pinned references has real version history to pin against.
6 changes: 6 additions & 0 deletions tests/smoke/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM alpine:3.22

ARG TARGETARCH
RUN echo "smoke ${TARGETARCH}" > /smoke

CMD ["cat", "/smoke"]
Loading