Skip to content

Release

Release #167

Workflow file for this run

#
# SPDX-FileCopyrightText: 2023-2025 Jens A. Koch
# SPDX-License-Identifier: MIT
#
# This file is part of https://github.com/jakoch/cpp-devbox
#
name: Release
on:
# You can manually run this workflow.
workflow_dispatch:
# This workflow runs on pushing a semantic versioned tag (e.g. v1.0.0).
# This workflow does not run when pushing to the main branch.
push:
#branches:
# - main
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
# This workflow runs on schedule: every Sunday at 1 am.
schedule:
- cron: "0 1 * * 0"
env:
DOCKERHUB_IMAGE: ${{ github.repository }}
GHCR_IMAGE: ghcr.io/${{ github.repository }}
jobs:
# ---------------------------------------------------------------------------------------
build:
# ---------------------------------------------------------------------------------------
name: "Build Container"
# https://github.com/actions/runner-images
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
security-events: write # required for trivy-action
id-token: write # required for attest-build-provenance
attestations: write # required for attest-build-provenance
strategy:
fail-fast: false
matrix:
config:
- { platform: "linux/amd64", debian_version: "12", debian_codename: "bookworm"}
- { platform: "linux/amd64", debian_version: "13", debian_codename: "trixie" }
- { platform: "linux/amd64", debian_version: "14", debian_codename: "forky" }
- { platform: "linux/amd64", debian_version: "sid", debian_codename: "unstable" }
continue-on-error: ${{ matrix.config.debian_codename == 'forky' }}
steps:
- name: ✂️ Free Disk Space
uses: jlumbroso/free-disk-space@v1.3.1 # https://github.com/jlumbroso/free-disk-space
with:
tool-cache: true
docker-images: false
- name: 🤘 Checkout Code
uses: actions/checkout@v5 # https://github.com/actions/checkout
- name: 🔍 Run hadolint
uses: hadolint/hadolint-action@v3.3.0 # https://github.com/hadolint/hadolint-action
with:
dockerfile: .devcontainer/debian/${{ matrix.config.debian_version }}-${{ matrix.config.debian_codename }}/Dockerfile
no-fail: true
- name: 🔒 Login to DockerHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3 # https://github.com/docker/login-action
with:
username: ${{ github.actor }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 🔒 Login to Github Container Registry (GHCR)
if: github.event_name != 'pull_request'
uses: docker/login-action@v3 # https://github.com/docker/login-action
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 🔽 Setup QEMU
uses: docker/setup-qemu-action@v3 # https://github.com/docker/setup-qemu-action
with:
platforms: ${{ matrix.config.platform }}
- name: 🔽 Setup Docker Buildx
uses: docker/setup-buildx-action@v3 # https://github.com/docker/setup-buildx-action
# cpp-devbox:{debian_codename}-{{date}} # only on scheduled builds
# cpp-devbox:{debian_codename}-{{version}} # only on git tag
# cpp-devbox:{debian_codename}-{{major}}.{{minor}} # only on git tag
# cpp-devbox:{debian_codename}-latest # always
- name: ✏ Setup Docker Metadata ➔ Stage cpp-devbox-base
id: metadata-base
uses: docker/metadata-action@v5 # https://github.com/docker/metadata-action
with:
images: |
${{ env.GHCR_IMAGE }}
${{ env.DOCKERHUB_IMAGE }}
flavor: |
latest=auto
prefix=${{ matrix.config.debian_codename }}-
tags: |
type=schedule,pattern={{ date 'YYYYMMDD' }}
type=semver,pattern={{ version }}
type=semver,pattern={{ major }}.{{ minor }}
type=raw,value=latest
# cpp-devbox:{debian_codename}-with-vulkansdk-{{date}} # only on scheduled builds
# cpp-devbox:{debian_codename}-with-vulkansdk-{{version}} # only on git tag
# cpp-devbox:{debian_codename}-with-vulkansdk-{{major}}.{{minor}} # only on git tag
# cpp-devbox:{debian_codename}-with-vulkansdk-latest # always
- name: ✏ Setup Docker Metadata ➔ Stage cpp-devbox-base-with-vulkansdk
id: metadata-base-with-vulkansdk
uses: docker/metadata-action@v5 # https://github.com/docker/metadata-action
with:
images: |
${{ env.GHCR_IMAGE }}
${{ env.DOCKERHUB_IMAGE }}
flavor: |
latest=auto
prefix=${{ matrix.config.debian_codename }}-with-vulkansdk-
tags: |
type=schedule,pattern={{ date 'YYYYMMDD' }}
type=semver,pattern={{ version }}
type=semver,pattern={{ major }}.{{ minor }}
type=raw,value=latest
- name: ✏ Create info.json
run: |
jq -n --arg version "${{ github.ref_name }}" \
--arg commit "${{ github.sha }}" \
--arg date "$(date -u +%F)" \
'{ version: $version, commit: $commit, date: $date }' > info-${{ matrix.config.debian_codename }}.json
- name: Check show-tool-versions.sh and make executable
run: |
ls -l ${{ github.workspace }}/.devcontainer/scripts/show-tool-versions.sh
chmod +x ${{ github.workspace }}/.devcontainer/scripts/show-tool-versions.sh
# Build Image -> Stage: cpp-devbox-base
- name: 📦 🚀 Build Image ➔ Stage cpp-devbox-base
id: build-base
uses: docker/build-push-action@v6 # https://github.com/docker/build-push-action
with:
context: .
file: .devcontainer/debian/${{ matrix.config.debian_version }}-${{ matrix.config.debian_codename }}/Dockerfile
target: cpp-devbox-base
platforms: ${{ matrix.config.platform }}
tags: ${{ steps.metadata-base.outputs.tags }}
labels: ${{ steps.metadata-base.outputs.labels }}
push: false
load: true
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:${{ matrix.config.debian_codename }}-latest-cache
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:${{ matrix.config.debian_codename }}-latest-cache,mode=max
# Build Image -> Stages: cpp-devbox-base + cpp-devbox-with-vulkansdk = with-vulkansdk
- name: 📦 🚀 Build Image ➔ Stage cpp-devbox-with-vulkansdk
id: build-base-with-vulkansdk
uses: docker/build-push-action@v6 # https://github.com/docker/build-push-action
with:
context: .
file: .devcontainer/debian/${{ matrix.config.debian_version }}-${{ matrix.config.debian_codename }}/Dockerfile
target: cpp-devbox-with-vulkansdk
platforms: ${{ matrix.config.platform }}
tags: ${{ steps.metadata-base-with-vulkansdk.outputs.tags }}
labels: ${{ steps.metadata-base-with-vulkansdk.outputs.labels }}
push: false
load: true
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:${{ matrix.config.debian_codename }}-with-vulkansdk-latest-cache
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:${{ matrix.config.debian_codename }}-with-vulkansdk-latest-cache,mode=max
# This provides: ${{ steps.get_image_name_base.outputs.name }}
- name: Get image name (base)
id: get_image_name_base
run: |
name=$(echo '${{ steps.build-base.outputs.metadata }}' | jq -r '."image.name" | split(",") | .[0]')
echo "name=$name" >> $GITHUB_OUTPUT
# This provides: ${{ steps.get_image_name_base_with_vulkan.outputs.name }}
- name: Get image name (with-vulkansdk)
id: get_image_name_base_with_vulkan
run: |
name=$(echo '${{ steps.build-base-with-vulkansdk.outputs.metadata }}' | jq -r '."image.name" | split(",") | .[0]')
echo "name=$name" >> $GITHUB_OUTPUT
- name: Generate SBOM (base)
id: generate-sbom-for-base-image
uses: anchore/sbom-action@v0
with:
image: ${{ steps.get_image_name_base.outputs.name }}
output-file: ${{ matrix.config.debian_codename }}-sbom.json
- name: Generate SBOM (with-vulkan)
id: generate-sbom-for-with-vulkan-image
uses: anchore/sbom-action@v0
with:
image: ${{ steps.get_image_name_base_with_vulkan.outputs.name }}
output-file: ${{ matrix.config.debian_codename }}-with-vulkansdk-sbom.json
- name: 🔐 Attest build provenance (base)
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v3
with:
subject-name: ${{ steps.get_image_name_base.outputs.name }}
subject-digest: ${{ steps.build-base.outputs.digest }}
- name: 🔐 Attest build provenance (with-vulkansdk)
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v3
with:
subject-name: ${{ steps.get_image_name_base_with_vulkan.outputs.name }}
subject-digest: ${{ steps.build-base-with-vulkansdk.outputs.digest }}
- name: ℹ️ Run cpp-devbox Container to grab version info
id: run-container-base
run: |
README="README-${{ matrix.config.debian_codename }}-base.md"
VERSIONS="versions-${{ matrix.config.debian_codename }}-base.md"
echo "# cpp-devbox ${{ github.ref_name }} ($(date '+%Y-%m-%d'))" >> $README
echo -e "\n" >> $README
echo "OS Version: Debian ${{ matrix.config.debian_version }} ${{ matrix.config.debian_codename }}" >> $README
echo "Image Version: ${{ steps.get_image_name_base.outputs.name }}" >> $README
echo -e "\n" >> $README
docker run --rm -v ${{ github.workspace }}/.devcontainer/scripts:/workspace ${{ steps.get_image_name_base.outputs.name }} /bin/zsh -c "cat /etc/os-release; pwd; ls -l /workspace"
docker run --rm -v ${{ github.workspace }}/.devcontainer/scripts:/workspace ${{ steps.get_image_name_base.outputs.name }} /bin/zsh -c "/workspace/show-tool-versions.sh" > $VERSIONS
cat $VERSIONS >> $README
- name: ℹ️ Run cpp-devbox-with-vulkansdk Container to grab version info
id: run-container-with-vulkan
run: |
README="README-${{ matrix.config.debian_codename }}-with-vulkansdk.md"
VERSIONS="versions-${{ matrix.config.debian_codename }}-with-vulkan.md"
echo "# cpp-devbox ${{ github.ref_name }} ($(date '+%Y-%m-%d'))" >> $README
echo -e "\n" >> $README
echo "OS Version: Debian ${{ matrix.config.debian_version }} ${{ matrix.config.debian_codename }} with Vulkan SDK" >> $README
echo "Image Version: ${{ steps.get_image_name_base_with_vulkan.outputs.name }}" >> $README
echo -e "\n" >> $README
docker run --rm -v ${{ github.workspace }}/.devcontainer/scripts:/workspace ${{ steps.get_image_name_base_with_vulkan.outputs.name }} /bin/zsh -c "cat /etc/os-release; pwd; ls -l /workspace"
docker run --rm -v ${{ github.workspace }}/.devcontainer/scripts:/workspace ${{ steps.get_image_name_base_with_vulkan.outputs.name }} /bin/zsh -c "/workspace/show-tool-versions.sh" > $VERSIONS
cat $VERSIONS >> $README
- name: Push all images and all tags
run: |
docker push --all-tags ${{ env.GHCR_IMAGE }}
docker push --all-tags ${{ env.DOCKERHUB_IMAGE }}
- name: List Docker Images
run: |
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
docker images --digests
- name: Test Docker Image (base)
run: |
docker run --rm -v "${PWD}/devbox-test:/src" -w /src ghcr.io/jakoch/cpp-devbox:${{ matrix.config.debian_codename }}-latest zsh -c "./build.sh"
- name: Test Docker Image (with-vulkansdk)
run: |
docker run --rm -v "${PWD}/devbox-test:/src" -w /src ghcr.io/jakoch/cpp-devbox:${{ matrix.config.debian_codename }}-with-vulkansdk-latest zsh -c "./build.sh"
- name: 📦 Provide the version info and info.json as a release asset
uses: actions/upload-artifact@v5 # https://github.com/actions/upload-artifact
with:
name: version-info-${{ matrix.config.debian_codename }}
path: |
info-${{ matrix.config.debian_codename }}.json
versions-${{ matrix.config.debian_codename }}-base.md
versions-${{ matrix.config.debian_codename }}-with-vulkan.md
README-${{ matrix.config.debian_codename }}-base.md
README-${{ matrix.config.debian_codename }}-with-vulkansdk.md
${{ matrix.config.debian_codename }}-sbom.json
${{ matrix.config.debian_codename }}-with-vulkansdk-sbom.json
- name: 🛡️🔍 Scan Image for Vulnerabilities using Trivy
uses: aquasecurity/trivy-action@master # https://github.com/aquasecurity/trivy-action
with:
#image-ref: '${{ env.GHCR_IMAGE }}:latest'
image-ref: '${{ steps.get_image_name_base.outputs.name }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
skip-files: /etc/ssh/ssh_host_rsa_key
skip-dirs: gcc-13.2.0,gcc-13.3.0,usr/lib64
# Notes for the skips:
# - skip-files: /etc/ssh/ssh_host_rsa_key
# The file is skipped, because its reported as "Asymmetric Private Key" alert.
# This is a false positive, because the file is a private key, which is intended to be there.
# - skip-dirs: gcc-13.2.0,usr/lib64
# The folders are skipped, because the folders contain many files, which
# are not relevant for the image security. The scan is faster without them.
- name: 🛡️🔼 Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4 # https://github.com/github/codeql-action
with:
sarif_file: 'trivy-results.sarif'
- name: 🛡️🔍 Scan Image for Vulnerabilities using Dockle
if: always()
uses: goodwithtech/dockle-action@v0.4.15 # https://github.com/goodwithtech/dockle-action
with:
#image: '${{ env.GHCR_IMAGE }}:latest'
image: '${{ steps.get_image_name_base.outputs.name }}'
format: 'list'
exit-code: '0'
exit-level: 'warn'
# - name: 🛡️🔍 Scan Image for Vulnerabilities using Docker Scout
# uses: docker/scout-action@v1 # https://github.com/docker/scout-action
# with:
# command: cves,recommendations
# only-severities: critical,high
# image: ${{ steps.metadata-base.outputs.tags }}
# format: 'json'
# sarif-file: 'scout-results.sarif.json'
# summary: true
# - name: 🛡️🔼 Upload Docker Scout scan results to GitHub Security tab
# uses: github/codeql-action/upload-sarif@v4 # https://github.com/github/codeql-action
# with:
# sarif_file: 'scout-results.sarif.json'
# ---------------------------------------------------------------------------------------
publish-docs:
# ---------------------------------------------------------------------------------------
name: "Publish Docs to gh-pages"
needs: build
runs-on: ubuntu-latest
# run this job only on main branch or on tags, this avoids running on PRs
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
steps:
- name: 🤘 Checkout gh-pages branch
uses: actions/checkout@v5
with:
ref: gh-pages
fetch-depth: 1
- name: 🔽 Download all docs artifacts
uses: actions/download-artifact@v6
with:
pattern: version-info-*
merge-multiple: true
path: tmp
- name: 📝 Merge both READMEs into a Github Pages index.md
run: |
cd tmp
echo "# cpp-devbox ${{ github.ref_name }} ($(date '+%Y-%m-%d'))" > index.md
echo "" >> index.md
echo "## Images" >> index.md
echo "" >> index.md
for codename in bookworm trixie forky unstable; do
if [ -f README-${codename}-base.md ]; then
echo "### Base Image (${codename})" >> index.md
grep -A2 '^OS Version:' README-${codename}-base.md >> index.md
echo "" >> index.md
fi
if [ -f README-${codename}-with-vulkansdk.md ]; then
echo "### With VulkanSDK (${codename})" >> index.md
grep -A2 '^OS Version:' README-${codename}-with-vulkansdk.md >> index.md
echo "" >> index.md
fi
done
- name: ✔ Commit index.md to gh-pages branch
run: |
cp tmp/index.md index.md
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add index.md
git commit -m "Publish docs from ${GITHUB_REPOSITORY}@${GITHUB_SHA:0:9}"
- name: 🚀 Push to gh-pages branch
run: |
git push origin gh-pages