From e98c573bae0e14bdb652d05c86b5a0c87a7deaf7 Mon Sep 17 00:00:00 2001 From: Mathias Beaulieu-Duncan Date: Fri, 13 Feb 2026 14:01:13 -0500 Subject: [PATCH] Add Docker Scout CVE scanning and switch CI to gmake - Add `scout` Makefile target that scans all 5 pushed images with `docker scout quickview` and writes a summary to _out/scout-report.md - Switch all CI workflow steps from `make` to `gmake` for GNU Make 4.x - Add brew dependency step for make, gnu-sed, and crane - Include CVE summary in Gitea release notes via jq JSON escaping - Update `clean` target to remove _out/ directory Co-Authored-By: Claude Opus 4.6 --- .gitea/workflows/build.yaml | 57 +++++++++++----- Makefile | 125 +++++++++++++++++++++++++++++------- 2 files changed, 143 insertions(+), 39 deletions(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index b602d54..bb1d6a3 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -28,6 +28,13 @@ jobs: - name: Verify Docker is running run: docker info + - name: Install build dependencies + run: | + for pkg in make gnu-sed crane; do + brew list --formula "$pkg" &>/dev/null || brew install "$pkg" + done + gmake --version | head -1 + - name: Set up Docker Buildx run: | docker buildx version @@ -42,22 +49,25 @@ jobs: run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" - name: Clone upstream sources - run: make checkouts + run: gmake checkouts - name: Apply patches - run: make patches + run: gmake patches - name: Build kernel - run: make kernel + run: gmake kernel - name: Build SBC overlay - run: make overlay + run: gmake overlay - name: Build installer and disk image - run: make installer + run: gmake installer - name: Tag release images - run: make release TAG=${{ steps.version.outputs.tag }} + run: gmake release TAG=${{ steps.version.outputs.tag }} + + - name: Run Docker Scout CVE scan + run: gmake scout - name: Compress disk image run: | @@ -81,21 +91,38 @@ jobs: REPO="${GITHUB_REPOSITORY}" API="${GITEA_URL}/api/v1" - # Create release + SCOUT_SECTION="" + if [ -f _out/scout-report.md ]; then + SCOUT_SECTION=$(cat _out/scout-report.md) + fi + + RELEASE_BODY="Custom Talos Linux image for Raspberry Pi 5 / CM5 (Compute Blade) + + **Talos version**: ${TAG} + **Kernel**: RPi downstream (CM5/RP1 support) + **Extensions**: iscsi-tools, util-linux-tools + **Overclock**: 2.6GHz (arm_freq=2600) + + ## Artifacts + - \`metal-arm64.raw.zst\` — Raw disk image for eMMC flashing + - \`docker.io/svrnty/talos-rpi5:${TAG}\` — Installer image for talosctl upgrade + + ## Security Scan + ${SCOUT_SECTION}" + + # Strip leading whitespace from heredoc-style indentation + RELEASE_BODY=$(echo "$RELEASE_BODY" | sed 's/^ //') + + RELEASE_BODY_JSON=$(jq -Rs '.' <<< "$RELEASE_BODY") + RELEASE_ID=$(curl -sf -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ - -d "{ - \"tag_name\": \"${TAG}\", - \"name\": \"Talos RPi5 ${TAG}\", - \"body\": \"Custom Talos Linux image for Raspberry Pi 5 / CM5 (Compute Blade)\n\n**Talos version**: ${TAG}\n**Kernel**: RPi downstream (CM5/RP1 support)\n**Extensions**: iscsi-tools, util-linux-tools\n**Overclock**: 2.6GHz (arm_freq=2600)\n\n## Artifacts\n- \`metal-arm64.raw.zst\` — Raw disk image for eMMC flashing\n- \`docker.io/svrnty/talos-rpi5:${TAG}\` — Installer image for talosctl upgrade\", - \"prerelease\": true - }" \ + -d "{\"tag_name\":\"${TAG}\",\"name\":\"Talos RPi5 ${TAG}\",\"body\":${RELEASE_BODY_JSON},\"prerelease\":true}" \ "${API}/repos/${REPO}/releases" | jq -r '.id') echo "Created release ID: ${RELEASE_ID}" - # Upload disk image curl -sf -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@metal-arm64.raw.zst" \ @@ -105,4 +132,4 @@ jobs: - name: Clean up if: always() - run: make clean + run: gmake clean diff --git a/Makefile b/Makefile index ca830e6..f2985f0 100644 --- a/Makefile +++ b/Makefile @@ -8,17 +8,27 @@ # make kernel # Build RPi kernel (~15-30 min on ARM64) # make overlay # Build U-Boot + firmware + DTBs # make installer # Build installer image + raw disk image -# make release # Tag images for release +# make release # Tag and push release images +# make clean # Remove checkouts and build artifacts PKG_VERSION = v1.12.0 TALOS_VERSION = v1.12.3 SBCOVERLAY_VERSION = main +# Prefer GNU coreutils (macOS: brew install gnu-sed coreutils) +export PATH := /opt/homebrew/opt/gnu-sed/libexec/gnubin:$(PATH) + REGISTRY ?= docker.io REGISTRY_USERNAME ?= svrnty TAG ?= $(shell git describe --tags --exact-match 2>/dev/null || echo dev) +# Docker Hub image names (project-specific) +KERNEL_IMAGE = $(REGISTRY)/$(REGISTRY_USERNAME)/talos-rpi5-kernel +OVERLAY_IMAGE = $(REGISTRY)/$(REGISTRY_USERNAME)/talos-rpi5-overlay +IMAGER_IMAGE = $(REGISTRY)/$(REGISTRY_USERNAME)/talos-rpi5-imager +INSTALLER_IMAGE = $(REGISTRY)/$(REGISTRY_USERNAME)/talos-rpi5-installer + # Public image name on Docker Hub (used by talosctl upgrade) IMAGE_NAME ?= talos-rpi5 @@ -40,6 +50,13 @@ SBCOVERLAY_TAG = $(shell cd $(CHECKOUTS_DIRECTORY)/sbc-raspberrypi5 && git descr # Build the --system-extension-image flags from the EXTENSIONS list EXTENSION_FLAGS = $(foreach ext,$(EXTENSIONS),--system-extension-image=$(ext)) +# Common imager flags for overlay and extensions +IMAGER_COMMON_FLAGS = \ + --overlay-name="rpi5" \ + --overlay-image="$(OVERLAY_IMAGE):$(SBCOVERLAY_TAG)" \ + --overlay-option="configTxtAppend=$$(cat $(PWD)/config/config.txt.append)" \ + $(EXTENSION_FLAGS) + # # Help # @@ -54,6 +71,7 @@ help: @echo " overlay — Build SBC overlay (U-Boot, firmware, DTBs)" @echo " installer — Build Talos installer image + raw disk image" @echo " release — Tag and push release images" + @echo " scout — Run Docker Scout CVE scan on all images" @echo " clean — Remove checkouts and build artifacts" @echo "" @echo "Variables:" @@ -61,6 +79,12 @@ help: @echo " PKG_VERSION = $(PKG_VERSION)" @echo " REGISTRY = $(REGISTRY)" @echo " REGISTRY_USERNAME = $(REGISTRY_USERNAME)" + @echo "" + @echo "Images:" + @echo " KERNEL_IMAGE = $(KERNEL_IMAGE)" + @echo " OVERLAY_IMAGE = $(OVERLAY_IMAGE)" + @echo " IMAGER_IMAGE = $(IMAGER_IMAGE)" + @echo " INSTALLER_IMAGE = $(INSTALLER_IMAGE)" # # Checkouts @@ -91,63 +115,116 @@ patches-talos: patches: patches-pkgs patches-talos # -# Kernel +# Kernel — build and push the RPi downstream kernel # .PHONY: kernel kernel: cd "$(CHECKOUTS_DIRECTORY)/pkgs" && \ - $(MAKE) \ - REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) PUSH=true \ - PLATFORM=linux/arm64 \ - kernel + $(MAKE) docker-kernel \ + TARGET_ARGS="--tag=$(KERNEL_IMAGE):$(PKGS_TAG) --push=true" \ + PLATFORM=linux/arm64 # -# Overlay +# Overlay — build U-Boot + firmware + DTBs +# +# The overlay's pkg.yaml references the kernel as PKGS_PREFIX/kernel:PKGS. +# We rewrite it to point to our project-specific kernel image name. # .PHONY: overlay overlay: @echo "SBCOVERLAY_TAG = $(SBCOVERLAY_TAG)" + @sed -i.bak 's|{{ .BUILD_ARG_PKGS_PREFIX }}/kernel:{{ .BUILD_ARG_PKGS }}|$(KERNEL_IMAGE):$(PKGS_TAG)|' \ + "$(CHECKOUTS_DIRECTORY)/sbc-raspberrypi5/internal/base/pkg.yaml" && \ + rm -f "$(CHECKOUTS_DIRECTORY)/sbc-raspberrypi5/internal/base/pkg.yaml.bak" cd "$(CHECKOUTS_DIRECTORY)/sbc-raspberrypi5" && \ - $(MAKE) \ - REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) IMAGE_TAG=$(SBCOVERLAY_TAG) PUSH=true \ - PKGS_PREFIX=$(REGISTRY)/$(REGISTRY_USERNAME) PKGS=$(PKGS_TAG) \ - INSTALLER_ARCH=arm64 PLATFORM=linux/arm64 \ - sbc-raspberrypi5 + $(MAKE) docker-sbc-raspberrypi5 \ + TARGET_ARGS="--tag=$(OVERLAY_IMAGE):$(SBCOVERLAY_TAG) --push=true" \ + INSTALLER_ARCH=arm64 PLATFORM=linux/arm64 # # Installer / Disk Image # +# Builds the imager, installer-base, and installer images step by step, +# pushing each to our project-specific Docker Hub repos. +# .PHONY: installer installer: cd "$(CHECKOUTS_DIRECTORY)/talos" && \ $(MAKE) \ - REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) PUSH=true \ - PKG_KERNEL=$(REGISTRY)/$(REGISTRY_USERNAME)/kernel:$(PKGS_TAG) \ + REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) \ + PKG_KERNEL=$(KERNEL_IMAGE):$(PKGS_TAG) \ INSTALLER_ARCH=arm64 PLATFORM=linux/arm64 \ - IMAGER_ARGS="--overlay-name=rpi5 --overlay-image=$(REGISTRY)/$(REGISTRY_USERNAME)/sbc-raspberrypi5:$(SBCOVERLAY_TAG) $(EXTENSION_FLAGS)" \ - kernel initramfs imager installer-base installer && \ + kernel initramfs && \ + $(MAKE) \ + REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) \ + PKG_KERNEL=$(KERNEL_IMAGE):$(PKGS_TAG) \ + INSTALLER_ARCH=arm64 PLATFORM=linux/arm64 \ + target-imager \ + TARGET_ARGS="--output type=image,name=$(IMAGER_IMAGE):$(TALOS_TAG),push=true" && \ + $(MAKE) \ + REGISTRY=$(REGISTRY) USERNAME=$(REGISTRY_USERNAME) \ + PKG_KERNEL=$(KERNEL_IMAGE):$(PKGS_TAG) \ + INSTALLER_ARCH=arm64 PLATFORM=linux/arm64 \ + target-installer-base \ + TARGET_ARGS="--output type=image,name=$(INSTALLER_IMAGE):base-$(TALOS_TAG),push=true" && \ + docker pull $(IMAGER_IMAGE):$(TALOS_TAG) && \ + docker run --rm -t -v ./_out:/out --privileged --network=host \ + $(IMAGER_IMAGE):$(TALOS_TAG) \ + installer --arch arm64 \ + --base-installer-image="$(INSTALLER_IMAGE):base-$(TALOS_TAG)" \ + $(IMAGER_COMMON_FLAGS) && \ + crane push ./_out/installer-arm64.tar $(INSTALLER_IMAGE):$(TALOS_TAG) && \ docker \ run --rm -t -v ./_out:/out -v /dev:/dev --privileged \ - $(REGISTRY)/$(REGISTRY_USERNAME)/imager:$(TALOS_TAG) \ + $(IMAGER_IMAGE):$(TALOS_TAG) \ metal --arch arm64 \ - --base-installer-image="$(REGISTRY)/$(REGISTRY_USERNAME)/installer:$(TALOS_TAG)" \ - --overlay-name="rpi5" \ - --overlay-image="$(REGISTRY)/$(REGISTRY_USERNAME)/sbc-raspberrypi5:$(SBCOVERLAY_TAG)" \ - --overlay-option="configTxtAppend=$$(cat $(PWD)/config/config.txt.append)" \ - $(EXTENSION_FLAGS) + --base-installer-image="$(INSTALLER_IMAGE):$(TALOS_TAG)" \ + $(IMAGER_COMMON_FLAGS) # # Release — tag images with the Git tag for stable references # .PHONY: release release: - docker pull $(REGISTRY)/$(REGISTRY_USERNAME)/installer:$(TALOS_TAG) && \ - docker tag $(REGISTRY)/$(REGISTRY_USERNAME)/installer:$(TALOS_TAG) $(REGISTRY)/$(REGISTRY_USERNAME)/$(IMAGE_NAME):$(TAG) && \ + docker pull $(INSTALLER_IMAGE):$(TALOS_TAG) && \ + docker tag $(INSTALLER_IMAGE):$(TALOS_TAG) $(REGISTRY)/$(REGISTRY_USERNAME)/$(IMAGE_NAME):$(TAG) && \ docker push $(REGISTRY)/$(REGISTRY_USERNAME)/$(IMAGE_NAME):$(TAG) +# +# Scout — Docker Scout CVE scan on all pushed images +# +SCOUT_REPORT := _out/scout-report.md +SCOUT_IMAGES := \ + $(KERNEL_IMAGE):$(PKGS_TAG) \ + $(OVERLAY_IMAGE):$(SBCOVERLAY_TAG) \ + $(IMAGER_IMAGE):$(TALOS_TAG) \ + $(INSTALLER_IMAGE):base-$(TALOS_TAG) \ + $(INSTALLER_IMAGE):$(TALOS_TAG) + +.PHONY: scout +scout: + @mkdir -p _out + @if ! docker scout version >/dev/null 2>&1; then \ + echo "Docker Scout not available -- skipping CVE scan." > $(SCOUT_REPORT); \ + exit 0; \ + fi + @echo "# Docker Scout CVE Summary" > $(SCOUT_REPORT) + @echo "" >> $(SCOUT_REPORT) + @for image in $(SCOUT_IMAGES); do \ + echo "Scanning $$image ..."; \ + echo "### $${image##*/}" >> $(SCOUT_REPORT); \ + echo '```' >> $(SCOUT_REPORT); \ + docker scout quickview "$$image" --platform linux/arm64 2>&1 >> $(SCOUT_REPORT) || \ + echo "Scout scan failed for $$image" >> $(SCOUT_REPORT); \ + echo '```' >> $(SCOUT_REPORT); \ + echo "" >> $(SCOUT_REPORT); \ + done + @echo "Scout report written to $(SCOUT_REPORT)" + # # Clean # .PHONY: clean clean: checkouts-clean + rm -rf _out rm -rf checkouts/_out