96eb3e8185
rc.2 proved the grype gate was decorative — buildx pushed before the scan ran, so a red run still shipped the image (and rc tags moved :latest). Build amd64 locally, scan that, then run the multi-arch push from the warm builder cache. :latest now only moves on non-rc tags. mirror-release: poll until the Gitea asset count is stable across two polls (GoReleaser uploads sequentially — assets>0 could mirror a partial set) and stretch the timeout to 20 min since the release run can queue behind the Docker job on the single runner.
105 lines
3.3 KiB
YAML
105 lines
3.3 KiB
YAML
name: Release Docker
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v[0-9]*"
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Image tag (e.g. 1.0.0, no v prefix). Defaults to latest commit SHA."
|
|
required: false
|
|
|
|
jobs:
|
|
docker:
|
|
runs-on: docker-builder
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Resolve image tag
|
|
id: meta
|
|
run: |
|
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
|
echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT"
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
TAG="${{ github.event.inputs.tag }}"
|
|
if [ -z "$TAG" ]; then
|
|
TAG="${{ github.sha }}"
|
|
fi
|
|
else
|
|
# Docker convention: git tag v1.2.3 -> image tag 1.2.3
|
|
TAG="${{ github.ref_name }}"
|
|
TAG="${TAG#v}"
|
|
fi
|
|
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
|
|
TAGS="lerkolabs/uptop:${TAG}"
|
|
TAGS="${TAGS},lerkolabs/uptop:sha-${SHORT_SHA}"
|
|
# :latest only for real releases — rc rehearsal tags must not move it
|
|
if [ "${{ github.ref_type }}" = "tag" ]; then
|
|
case "$TAG" in
|
|
*-*) ;;
|
|
*) TAGS="${TAGS},lerkolabs/uptop:latest" ;;
|
|
esac
|
|
fi
|
|
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Log in to Docker Hub
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
# Scan must gate the push: build amd64 locally, scan it, and only then run
|
|
# the multi-arch push (amd64 layers come from the builder cache, so the
|
|
# second build only adds the arm64 work).
|
|
- name: Build for scan (amd64, local)
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
load: true
|
|
platforms: linux/amd64
|
|
tags: uptop-scan:${{ steps.meta.outputs.tag }}
|
|
build-args: |
|
|
VERSION=${{ steps.meta.outputs.tag }}
|
|
COMMIT=${{ github.sha }}
|
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
|
|
|
- name: Scan image for CVEs
|
|
run: |
|
|
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.114.0
|
|
grype uptop-scan:${{ steps.meta.outputs.tag }} --fail-on critical --output table
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
push: true
|
|
platforms: linux/amd64,linux/arm64
|
|
sbom: true
|
|
provenance: mode=max
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
build-args: |
|
|
VERSION=${{ steps.meta.outputs.tag }}
|
|
COMMIT=${{ github.sha }}
|
|
BUILD_DATE=${{ github.event.head_commit.timestamp }}
|
|
|
|
- name: Update Docker Hub description
|
|
uses: peter-evans/dockerhub-description@v4
|
|
with:
|
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
repository: lerkolabs/uptop
|
|
|
|
- name: Cleanup Docker artifacts
|
|
if: always()
|
|
run: |
|
|
docker image prune -f
|
|
docker builder prune -f --keep-storage=2GB
|