Docker #1075
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Docker | |
on: | |
push: | |
branches: | |
- 'main' | |
- 'feature/**' | |
tags: | |
- 'v*.*.*' | |
schedule: | |
- cron: '0 06 * * *' | |
jobs: | |
docker: | |
name: Docker | |
runs-on: ubuntu-latest | |
permissions: | |
# id-token is used by cosign's OIDC based signing | |
# https://blog.chainguard.dev/zero-friction-keyless-signing-with-github-actions/ | |
id-token: 'write' | |
contents: 'write' | |
packages: 'write' | |
strategy: | |
matrix: | |
image: ["regctl", "regsync", "regbot"] | |
type: ["scratch", "alpine"] | |
steps: | |
- name: Check out code | |
uses: actions/checkout@v3 | |
- name: Prepare | |
id: prep | |
run: | | |
mkdir -p "output/${{matrix.image}}" | |
EXT="" | |
if [ "${{ matrix.type }}" != "scratch" ]; then | |
EXT="-${{ matrix.type }}" | |
fi | |
HUB_IMAGE=regclient/${{ matrix.image }} | |
GHCR_IMAGE=ghcr.io/regclient/${{ matrix.image }} | |
VERSION=noop | |
if [ "${{ github.event_name }}" = "schedule" ]; then | |
VERSION=edge | |
elif [[ $GITHUB_REF == refs/tags/* ]]; then | |
VERSION="${GITHUB_REF#refs/tags/}" | |
elif [[ $GITHUB_REF == refs/heads/* ]]; then | |
VERSION="${GITHUB_REF#refs/heads/}" | |
if [ "${{ github.event.repository.default_branch }}" = "$VERSION" ]; then | |
VERSION=edge | |
fi | |
elif [[ $GITHUB_REF == refs/pull/* ]]; then | |
VERSION="pr-${{ github.event.number }}" | |
fi | |
VERSION="$(echo "${VERSION}" | sed -r 's#/+#-#g')" | |
TAGS="${HUB_IMAGE}:${VERSION}${EXT},${GHCR_IMAGE}:${VERSION}${EXT}" | |
if [[ $VERSION =~ ^v[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then | |
MINOR="${VERSION%.*}" | |
MAJOR="${MINOR%.*}" | |
TAGS="${TAGS},${HUB_IMAGE}:${MINOR}${EXT},${HUB_IMAGE}:${MAJOR}${EXT}" | |
TAGS="${TAGS},${GHCR_IMAGE}:${MINOR}${EXT},${GHCR_IMAGE}:${MAJOR}${EXT}" | |
if [ "${{ matrix.type }}" == "scratch" ]; then | |
TAGS="${TAGS},${HUB_IMAGE}:latest" | |
TAGS="${TAGS},${GHCR_IMAGE}:latest" | |
else | |
TAGS="${TAGS},${HUB_IMAGE}:${{ matrix.type }}" | |
TAGS="${TAGS},${GHCR_IMAGE}:${{ matrix.type }}" | |
fi | |
fi | |
VCS_DATE="$(date -d "@$(git log -1 --format=%at)" +%Y-%m-%dT%H:%M:%SZ --utc)" | |
REPO_URL="${{github.server_url}}/${{github.repository}}.git" | |
echo "version=${VERSION}" >>$GITHUB_OUTPUT | |
echo "image_hub=${HUB_IMAGE}" >>$GITHUB_OUTPUT | |
echo "image_ghcr=${GHCR_IMAGE}" >>$GITHUB_OUTPUT | |
echo "tags=${TAGS}" >>$GITHUB_OUTPUT | |
echo "created=${VCS_DATE}" >>$GITHUB_OUTPUT | |
echo "repo_url=${REPO_URL}" >>$GITHUB_OUTPUT | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v2 | |
- name: Login to DockerHub | |
if: github.repository_owner == 'regclient' | |
uses: docker/login-action@v2 | |
with: | |
username: ${{ secrets.DOCKERHUB_USERNAME }} | |
password: ${{ secrets.DOCKERHUB_TOKEN }} | |
- name: Login to GHCR | |
if: github.repository_owner == 'regclient' | |
uses: docker/login-action@v2 | |
with: | |
registry: ghcr.io | |
username: ${{ secrets.GHCR_USERNAME }} | |
password: ${{ secrets.GHCR_TOKEN }} | |
- name: Build | |
uses: docker/build-push-action@v4 | |
id: build | |
with: | |
context: . | |
file: ./build/Dockerfile.${{ matrix.image }}.buildkit | |
platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x | |
target: release-${{ matrix.type }} | |
outputs: type=oci,dest=output/${{matrix.image}}-${{matrix.type}}.tar | |
labels: | | |
org.opencontainers.image.created=${{ steps.prep.outputs.created }} | |
org.opencontainers.image.source=${{ steps.prep.outputs.repo_url }} | |
org.opencontainers.image.version=${{ steps.prep.outputs.version }} | |
org.opencontainers.image.revision=${{ github.sha }} | |
- name: Install cosign | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
uses: sigstore/cosign-installer@v2.8.1 | |
with: | |
cosign-release: "v2.0.0" | |
- name: Install syft | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
uses: anchore/sbom-action/download-syft@v0.13.3 | |
id: syft | |
with: | |
syft-version: "v0.73.0" | |
# Dogfooding, use regctl to modify regclient images to improve reproducibility | |
- name: Install regctl | |
uses: regclient/actions/regctl-installer@main | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
with: | |
release: main | |
- name: Mutate | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
id: mutate | |
run: | | |
vcs_date="${{ steps.prep.outputs.created }}" | |
base_name="" | |
mkdir -p "output/${{matrix.image}}" | |
if [ "${{matrix.type}}" = "alpine" ]; then | |
base_name="alpine:3" | |
base_digest="$(regctl image digest "${base_name}")" | |
fi | |
# mutate the image locally | |
local_tag="ocidir://output/${{matrix.image}}:${{matrix.type}}" | |
echo "Loading ${local_tag} from output/${{matrix.image}}-${{matrix.type}}.tar" | |
regctl image import "${local_tag}" "output/${{matrix.image}}-${{matrix.type}}.tar" | |
echo "Modifying image for reproducibility" | |
regctl image mod "${local_tag}" --replace \ | |
--to-oci-referrers \ | |
--time-max "${vcs_date}" \ | |
--annotation "oci.opencontainers.image.created=${vcs_date}" \ | |
--annotation "oci.opencontainers.image.source=${{ steps.prep.outputs.repo_url }}" \ | |
--annotation "oci.opencontainers.image.revision=${{ github.sha }}" | |
if [ -n "$base_name" ] && [ -n "$base_digest" ]; then | |
regctl image mod "${local_tag}" --replace \ | |
--annotation "oci.opencontainers.image.base.name=${base_name}" \ | |
--annotation "oci.opencontainers.image.base.digest=${base_digest}" | |
fi | |
echo "digest=$(regctl image digest ${local_tag})" >>$GITHUB_OUTPUT | |
- name: Attach SBOMs | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
id: sbom | |
run: | | |
now_date="$(date +%Y-%m-%dT%H:%M:%SZ --utc)" | |
for digest in $(regctl manifest get ocidir://output/${{matrix.image}}:${{matrix.type}} \ | |
--format '{{range .Manifests}}{{printf "%s\n" .Digest}}{{end}}'); do | |
echo "Attaching SBOMs for ${{matrix.image}}@${digest}" | |
regctl image copy ocidir://output/${{matrix.image}}@${digest} ocidir://output/${{matrix.image}}-sbom | |
${{steps.syft.outputs.cmd}} packages -q "oci-dir:output/${{matrix.image}}-sbom" \ | |
--name "docker:docker.io/regclient/${{matrix.image}}@${digest}" -o cyclonedx-json \ | |
| regctl artifact put --subject "ocidir://output/${{matrix.image}}@${digest}" \ | |
--artifact-type application/vnd.cyclonedx+json \ | |
-m application/vnd.cyclonedx+json \ | |
--annotation "org.opencontainers.artifact.created=${now_date}" \ | |
--annotation "org.opencontainers.artifact.description=CycloneDX JSON SBOM" | |
${{steps.syft.outputs.cmd}} packages -q "oci-dir:output/${{matrix.image}}-sbom" \ | |
--name "docker:docker.io/regclient/${{matrix.image}}@${digest}" -o spdx-json \ | |
| regctl artifact put --subject "ocidir://output/${{matrix.image}}@${digest}" \ | |
--artifact-type application/spdx+json \ | |
-m application/spdx+json \ | |
--annotation "org.opencontainers.artifact.created=${now_date}" \ | |
--annotation "org.opencontainers.artifact.description=SPDX JSON SBOM" | |
rm -r output/${{matrix.image}}-sbom | |
done | |
- name: Push | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
id: push | |
run: | | |
# loop over the tags | |
image_hub="${{ steps.prep.outputs.image_hub }}" | |
for tag in $(echo ${{ steps.prep.outputs.tags }} | tr , ' '); do | |
echo "Pushing ${tag}" | |
# TODO: push referrers to Hub once this is fixed: https://github.com/docker/hub-feedback/issues/2307 | |
if [ "$tag" != "${tag#$image_hub}" ]; then | |
regctl image copy "ocidir://output/${{matrix.image}}:${{matrix.type}}" "${tag}" | |
else | |
regctl image copy --referrers "ocidir://output/${{matrix.image}}:${{matrix.type}}" "${tag}" | |
fi | |
done | |
- name: Sign the container image | |
if: github.event_name != 'pull_request' && github.repository_owner == 'regclient' | |
run: | | |
cosign sign -y -r ${{ steps.prep.outputs.image_hub }}@${{ steps.mutate.outputs.digest }} | |
cosign sign -y -r ${{ steps.prep.outputs.image_ghcr }}@${{ steps.mutate.outputs.digest }} |