# Build and release custom Talos CM5 image # # Triggered by pushing a version tag (e.g. v1.11.5-1) # Runs on ARM64 self-hosted runner (ASUS GX10) # # Produces: # - Installer container image → Docker Hub (svrnty/talos-rpi5:) # - Raw disk image → Gitea release (metal-arm64.raw.zst) # # Runner: Apple Silicon Mac Mini (self-hosted, macOS, arm64) name: Build Talos CM5 Image on: push: tags: - 'v*.*.*' jobs: build: runs-on: [self-hosted, macos] timeout-minutes: 180 steps: - name: Checkout uses: actions/checkout@v4 - name: Verify Docker is running run: docker info - name: Install build dependencies run: | for pkg in make gnu-sed crane cosign syft; do brew list --formula "$pkg" &>/dev/null || brew install "$pkg" done gmake --version | head -1 - name: Set up Docker Buildx run: | docker buildx version docker buildx create --name talos-builder --driver docker-container --use 2>/dev/null || docker buildx use talos-builder docker buildx inspect --bootstrap - name: Login to Docker Hub run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin - name: Extract version tag id: version run: echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT" - name: Clone upstream sources run: gmake checkouts - name: Apply patches run: gmake patches - name: Build kernel run: gmake kernel - name: Build SBC overlay run: gmake overlay - name: Build installer and disk image run: gmake installer - name: Attest installer image env: COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} run: gmake attest COSIGN_KEY=<(echo "${{ secrets.COSIGN_PRIVATE_KEY }}") - name: Tag release images env: COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} run: gmake release TAG=${{ steps.version.outputs.tag }} COSIGN_KEY=<(echo "${{ secrets.COSIGN_PRIVATE_KEY }}") - name: Compress disk image run: | # The imager outputs to checkouts/talos/_out/ DISK_IMAGE=$(find checkouts/talos/_out -name 'metal-arm64*.raw*' | head -1) if [ -z "$DISK_IMAGE" ]; then echo "Error: disk image not found in checkouts/talos/_out/" find checkouts/talos/_out -type f exit 1 fi # Copy to workspace root for release upload cp "$DISK_IMAGE" metal-arm64.raw.zst ls -lh metal-arm64.raw.zst - name: Create Gitea release and upload artifact env: GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ steps.version.outputs.tag }} run: | GITEA_URL="${GITHUB_SERVER_URL}" REPO="${GITHUB_REPOSITORY}" API="${GITEA_URL}/api/v1" # Extract component versions from tag (format: v1.12.3-k6.12.47-1) TALOS_VER=$(echo "$TAG" | sed -E 's/^(v[0-9]+\.[0-9]+\.[0-9]+)-.*/\1/') KERNEL_VER=$(echo "$TAG" | sed -E 's/.*-k([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/') RELEASE_BODY="Custom Talos Linux image for Raspberry Pi 5 / CM5 (Compute Blade) **Talos**: ${TALOS_VER} **Kernel**: RPi downstream ${KERNEL_VER} (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" # 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\":${RELEASE_BODY_JSON},\"prerelease\":true}" \ "${API}/repos/${REPO}/releases" | jq -r '.id') echo "Created release ID: ${RELEASE_ID}" curl -sf -X POST \ -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@metal-arm64.raw.zst" \ "${API}/repos/${REPO}/releases/${RELEASE_ID}/assets?name=metal-arm64.raw.zst" echo "Uploaded metal-arm64.raw.zst to release" - name: Clean up if: always() run: gmake clean