chore: update CozyStack upstream to 62d2516 #97
This file contains hidden or 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: Build CozyStack ARM64 Images (Upstream Integration) | |
| # 10/30/2025 - Rebuild for 0.38.1 Cozystack release | |
| on: | |
| push: | |
| branches: [ main ] | |
| paths: | |
| - 'patches/**' | |
| - '.github/workflows/build-talos-images.yml' | |
| - 'tests/**' | |
| - 'validate-*.sh' | |
| - 'crane' | |
| # Exclude documentation-only changes | |
| - '!docs/**' | |
| - '!README.md' | |
| - '!TODO.md' | |
| - '!CONTEXT-HANDOFF.md' | |
| - '!**/*.md' | |
| - '!index.md' | |
| - '!_config.yml' | |
| - '!attic/**' | |
| pull_request: | |
| branches: [ main ] | |
| paths: | |
| - 'patches/**' | |
| - '.github/workflows/build-talos-images.yml' | |
| - 'tests/**' | |
| - 'validate-*.sh' | |
| - 'crane' | |
| # Exclude documentation-only changes | |
| - '!docs/**' | |
| - '!README.md' | |
| - '!TODO.md' | |
| - '!CONTEXT-HANDOFF.md' | |
| - '!**/*.md' | |
| - '!index.md' | |
| - '!_config.yml' | |
| - '!attic/**' | |
| workflow_dispatch: | |
| inputs: | |
| cozystack_commit: | |
| description: 'CozyStack upstream commit (for reproducible builds)' | |
| required: false | |
| default: '62d2516' # Use latest main | |
| # Auto-updated 2026-04-27 to upstream 62d2516 | |
| extension_variant: | |
| description: 'Extension variant to build' | |
| required: false | |
| default: 'spin-tailscale' | |
| type: choice | |
| options: | |
| - 'spin-tailscale' | |
| - 'spin-only' | |
| build_targets: | |
| description: 'Build targets to execute' | |
| required: false | |
| default: 'upstream-images' | |
| type: choice | |
| options: | |
| - 'upstream-images' # Build image-talos + image-matchbox (recommended) | |
| - 'image' # Full build (pre-checks + matchbox + cozystack + talos) | |
| - 'assets' # Just Talos assets (kernel + initramfs) | |
| - 'image-talos' # Just Talos installer image | |
| - 'image-matchbox' # Just matchbox image | |
| # Source: https://github.com/cozystack/cozystack/blob/main/packages/core/installer/Makefile | |
| env: | |
| REGISTRY: ghcr.io/urmanac/cozystack-assets | |
| jobs: | |
| build-cozystack-upstream: | |
| runs-on: ubuntu-24.04-arm | |
| permissions: | |
| contents: read | |
| packages: write | |
| strategy: | |
| matrix: | |
| extension_variant: [spin-tailscale, spin-only] | |
| outputs: | |
| kernel-digest: ${{ steps.assets.outputs.kernel-digest }} | |
| initramfs-digest: ${{ steps.assets.outputs.initramfs-digest }} | |
| talos-version: ${{ steps.build.outputs.talos-version }} | |
| build-target: ${{ steps.build.outputs.build-target }} | |
| asset-count: ${{ steps.assets.outputs.asset-count }} | |
| image-tags: ${{ steps.meta.outputs.tags }} | |
| test-image: ${{ steps.extract-first-tag.outputs.first-tag }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Install build dependencies | |
| run: | | |
| # Install CozyStack build dependencies | |
| sudo apt-get update | |
| sudo apt-get install -y skopeo jq | |
| # Install crane (container registry tool) | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "x86_64" ]; then CRANE_ARCH="x86_64"; else CRANE_ARCH="arm64"; fi | |
| curl -L https://github.com/google/go-containerregistry/releases/latest/download/go-containerregistry_Linux_${CRANE_ARCH}.tar.gz | sudo tar xz -C /usr/local/bin crane | |
| # Install mikefarah/yq (required by CozyStack) | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "x86_64" ]; then YQ_ARCH="amd64"; else YQ_ARCH="arm64"; fi | |
| sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${YQ_ARCH} -O /usr/bin/yq | |
| sudo chmod +x /usr/bin/yq | |
| # Verify versions | |
| docker --version | |
| skopeo --version | |
| crane version | |
| jq --version | |
| yq --version | |
| - name: Clone and setup CozyStack (upstream main) | |
| run: | | |
| # Clone upstream CozyStack at main branch (clean, current) | |
| git clone https://github.com/cozystack/cozystack.git cozystack-upstream | |
| cd cozystack-upstream | |
| git checkout main | |
| # Pin to specific commit for reproducible builds | |
| COZYSTACK_COMMIT="${{ github.event.inputs.cozystack_commit || 'HEAD' }}" | |
| if [[ "$COZYSTACK_COMMIT" != "HEAD" ]]; then | |
| git reset --hard "$COZYSTACK_COMMIT" | |
| fi | |
| echo "COZYSTACK_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV | |
| echo "Building from CozyStack upstream: $(git log -1 --oneline)" | |
| - name: Apply ARM64 conversion patches | |
| run: | | |
| cd cozystack-upstream | |
| # Apply patches based on extension variant | |
| EXTENSION_VARIANT="${{ matrix.extension_variant }}" | |
| echo "Building with extension variant: $EXTENSION_VARIANT" | |
| if [ "$EXTENSION_VARIANT" = "spin-only" ]; then | |
| echo "Applying ARM64+Spin-only patches..." | |
| git apply ../patches/03-arm64-spin-only.patch || { | |
| echo "Failed to apply 03-arm64-spin-only.patch" | |
| git status | |
| exit 1 | |
| } | |
| git apply ../patches/02-makefile-architecture-variables.patch || { | |
| echo "Failed to apply 02-makefile-architecture-variables.patch" | |
| git status | |
| exit 1 | |
| } | |
| else | |
| echo "Applying ARM64+Spin+Tailscale patches..." | |
| git apply ../patches/01-arm64-spin-tailscale.patch || { | |
| echo "Failed to apply 01-arm64-spin-tailscale.patch" | |
| git status | |
| exit 1 | |
| } | |
| git apply ../patches/02-makefile-architecture-variables.patch || { | |
| echo "Failed to apply 02-makefile-architecture-variables.patch" | |
| git status | |
| exit 1 | |
| } | |
| fi | |
| # Verify patch application | |
| echo "Patches applied successfully:" | |
| git status --porcelain | |
| # Restore execute permissions on scripts (patches may remove them) | |
| chmod +x packages/core/installer/hack/gen-profiles.sh | |
| chmod +x packages/core/installer/hack/gen-versions.sh | |
| echo "" | |
| echo "Verified changes:" | |
| echo "- EXTENSIONS: $(grep EXTENSIONS= packages/core/installer/hack/gen-profiles.sh)" | |
| echo "- Architecture: $(grep 'arch:' packages/core/installer/hack/gen-profiles.sh)" | |
| - name: Update upstream dependencies and build with Makefile targets | |
| id: build | |
| env: | |
| REGISTRY: ${{ env.REGISTRY }}/talos/cozystack-${{ matrix.extension_variant }} | |
| PUSH: 1 | |
| LOAD: 0 | |
| run: | | |
| cd cozystack-upstream/packages/core/installer | |
| # Authenticate both skopeo and docker to GHCR for upstream Makefile push | |
| echo "${{ secrets.GITHUB_TOKEN }}" | skopeo login ghcr.io --username ${{ github.actor }} --password-stdin | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username ${{ github.actor }} --password-stdin | |
| # Override registry for our build with extension variant | |
| echo "Building with REGISTRY=$REGISTRY (variant: ${{ matrix.extension_variant }})" | |
| # Generate ARM64 profiles with dynamic Spin+Tailscale versions using upstream targets | |
| echo "Updating upstream dependencies and generating profiles..." | |
| make update # Run gen-profiles.sh to generate Talos profiles | |
| # Show what profile was generated for debugging | |
| echo "Generated metal profile:" | |
| cat images/talos/profiles/metal.yaml | |
| # Use upstream Makefile target based on workflow input | |
| BUILD_TARGET="${{ github.event.inputs.build_targets || 'upstream-images' }}" | |
| echo "Building with upstream target: make $BUILD_TARGET" | |
| case "$BUILD_TARGET" in | |
| "upstream-images") | |
| echo "Building upstream-compatible images: image-talos + image-matchbox..." | |
| make pre-checks | |
| echo "Building Talos image first (to establish assets)..." | |
| make image-talos | |
| echo "Building matchbox image (reusing same assets)..." | |
| make image-matchbox | |
| echo "build-outputs=talos-installer,matchbox" >> $GITHUB_OUTPUT | |
| ;; | |
| "image") | |
| echo "Running full build (pre-checks + matchbox + cozystack + talos)..." | |
| make pre-checks | |
| make image | |
| # Capture all build outputs for complete asset array | |
| echo "build-outputs=kernel,initramfs,talos-installer,matchbox,cozystack" >> $GITHUB_OUTPUT | |
| ;; | |
| "assets") | |
| echo "Building Talos assets (kernel + initramfs + iso + nocloud + metal)..." | |
| make pre-checks | |
| make assets | |
| echo "build-outputs=kernel,initramfs,iso,nocloud,metal" >> $GITHUB_OUTPUT | |
| ;; | |
| "image-talos") | |
| echo "Building Talos installer image..." | |
| make pre-checks | |
| make image-talos | |
| echo "build-outputs=talos-installer" >> $GITHUB_OUTPUT | |
| ;; | |
| "image-matchbox") | |
| echo "Building matchbox image..." | |
| make pre-checks | |
| make image-matchbox | |
| echo "build-outputs=matchbox" >> $GITHUB_OUTPUT | |
| ;; | |
| *) | |
| echo "Unknown build target: $BUILD_TARGET" | |
| exit 1 | |
| ;; | |
| esac | |
| # Get extension variant and create build variant tag | |
| EXTENSION_VARIANT="${{ matrix.extension_variant }}" | |
| # Get Talos version from build | |
| TALOS_VERSION=$(awk '/^version:/ {print $2}' images/talos/profiles/metal.yaml) | |
| echo "talos-version=$TALOS_VERSION" >> $GITHUB_OUTPUT | |
| echo "extension-variant=${{ matrix.extension_variant }}" >> $GITHUB_OUTPUT | |
| echo "build-target=$BUILD_TARGET" >> $GITHUB_OUTPUT | |
| echo "Built Talos version: $TALOS_VERSION with ${{ matrix.extension_variant }} using target: $BUILD_TARGET" | |
| - name: Extract and package complete asset array with validation | |
| id: assets | |
| run: | | |
| cd cozystack-upstream | |
| # List what files were actually generated | |
| echo "Files in _out/assets:" | |
| ls -la _out/assets/ || echo "No _out/assets directory found" | |
| # Create comprehensive output directory structure | |
| mkdir -p assets/talos/arm64/{boot,containers,validation} | |
| # Extract built ARM64 assets with validation | |
| BUILD_OUTPUTS="${{ steps.build.outputs.build-outputs }}" | |
| echo "Processing build outputs: $BUILD_OUTPUTS" | |
| # Process kernel | |
| if [[ "$BUILD_OUTPUTS" =~ "kernel" ]]; then | |
| echo "Processing kernel asset..." | |
| # Look for kernel files from upstream build | |
| KERNEL_FILE="" | |
| for candidate in kernel-arm64 vmlinuz-arm64 vmlinuz kernel; do | |
| if [ -f "_out/assets/$candidate" ]; then | |
| KERNEL_FILE="_out/assets/$candidate" | |
| break | |
| fi | |
| done | |
| if [ -n "$KERNEL_FILE" ]; then | |
| cp "$KERNEL_FILE" assets/talos/arm64/boot/vmlinuz | |
| echo "✅ Kernel asset processed: $(basename $KERNEL_FILE) → boot/vmlinuz" | |
| else | |
| echo "⚠️ Kernel not found in expected locations" | |
| ls -la _out/assets/ | grep -E -i "kernel|vmlinuz" || echo "No kernel files found" | |
| fi | |
| fi | |
| # Process initramfs | |
| if [[ "$BUILD_OUTPUTS" =~ "initramfs" ]]; then | |
| echo "Processing initramfs asset..." | |
| # Look for initramfs files from upstream build | |
| INITRAMFS_FILE="" | |
| for candidate in initramfs-metal-arm64.xz initramfs-arm64.xz initramfs.xz initramfs; do | |
| if [ -f "_out/assets/$candidate" ]; then | |
| INITRAMFS_FILE="_out/assets/$candidate" | |
| break | |
| fi | |
| done | |
| if [ -n "$INITRAMFS_FILE" ]; then | |
| cp "$INITRAMFS_FILE" assets/talos/arm64/boot/initramfs.xz | |
| echo "✅ Initramfs asset processed: $(basename $INITRAMFS_FILE) → boot/initramfs.xz" | |
| else | |
| echo "⚠️ Initramfs not found in expected locations" | |
| ls -la _out/assets/ | grep -E -i "initramfs" || echo "No initramfs files found" | |
| fi | |
| fi | |
| # Process ISO, nocloud, and metal images (from assets target) | |
| if [[ "$BUILD_OUTPUTS" =~ "iso" ]] && [ -f "_out/assets/metal-arm64.iso" ]; then | |
| cp _out/assets/metal-arm64.iso assets/talos/arm64/installer.iso | |
| echo "✅ ISO asset processed: metal-arm64.iso → installer.iso" | |
| fi | |
| if [[ "$BUILD_OUTPUTS" =~ "nocloud" ]] && [ -f "_out/assets/nocloud-arm64.raw.xz" ]; then | |
| cp _out/assets/nocloud-arm64.raw.xz assets/talos/arm64/nocloud.raw.xz | |
| echo "✅ NoCloud asset processed: nocloud-arm64.raw.xz → nocloud.raw.xz" | |
| fi | |
| if [[ "$BUILD_OUTPUTS" =~ "metal" ]] && [ -f "_out/assets/metal-arm64.raw.xz" ]; then | |
| cp _out/assets/metal-arm64.raw.xz assets/talos/arm64/metal.raw.xz | |
| echo "✅ Metal asset processed: metal-arm64.raw.xz → metal.raw.xz" | |
| fi | |
| # Process container images (from image target) | |
| if [[ "$BUILD_OUTPUTS" =~ "talos-installer" ]] && [ -f "_out/assets/installer-arm64.tar" ]; then | |
| cp _out/assets/installer-arm64.tar assets/talos/arm64/containers/talos-installer.tar | |
| fi | |
| # Generate comprehensive checksums (exclude the checksum file itself) | |
| cd assets/talos/arm64 | |
| # Create checksums for all files except checksums.sha256 | |
| find . -type f ! -name "checksums.sha256" -exec sha256sum {} \; > checksums.sha256 | |
| # Validate checksums work | |
| echo "Validating asset checksums..." | |
| if sha256sum -c checksums.sha256 2>/dev/null; then | |
| echo "✅ All asset checksums validated successfully" | |
| else | |
| echo "⚠️ Checksum validation had warnings, but files exist:" | |
| echo "Generated checksums:" | |
| cat checksums.sha256 | |
| fi | |
| # Count and summarize assets | |
| ASSET_COUNT=$(find . -type f | wc -l) | |
| echo "Total assets extracted: $ASSET_COUNT" | |
| # Generate validation report | |
| cat > validation/build-report.txt << EOF | |
| CozyStack ARM64 Asset Array Build Report | |
| ======================================== | |
| Build Target: ${{ steps.build.outputs.build-target }} | |
| Build Outputs: ${{ steps.build.outputs.build-outputs }} | |
| Total Assets: $ASSET_COUNT | |
| Talos Version: ${{ steps.build.outputs.talos-version }} | |
| CozyStack Commit: $COZYSTACK_COMMIT | |
| Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| Asset Inventory: | |
| $(find . -type f -exec ls -lh {} \;) | |
| EOF | |
| # Output validation results | |
| if [ -f "usr/install/arm64/vmlinuz.efi" ]; then | |
| KERNEL_DIGEST=$(sha256sum usr/install/arm64/vmlinuz.efi | cut -d' ' -f1) | |
| echo "kernel-digest=$KERNEL_DIGEST" >> $GITHUB_OUTPUT | |
| elif [ -f "talos/arm64/boot/vmlinuz" ]; then | |
| KERNEL_DIGEST=$(sha256sum talos/arm64/boot/vmlinuz | cut -d' ' -f1) | |
| echo "kernel-digest=$KERNEL_DIGEST" >> $GITHUB_OUTPUT | |
| elif [ -f "boot/vmlinuz" ]; then | |
| KERNEL_DIGEST=$(sha256sum boot/vmlinuz | cut -d' ' -f1) | |
| echo "kernel-digest=$KERNEL_DIGEST" >> $GITHUB_OUTPUT | |
| fi | |
| if [ -f "usr/install/arm64/systemd-boot.efi" ]; then | |
| INITRAMFS_DIGEST=$(sha256sum usr/install/arm64/systemd-boot.efi | cut -d' ' -f1) | |
| echo "initramfs-digest=$INITRAMFS_DIGEST" >> $GITHUB_OUTPUT | |
| elif [ -f "talos/arm64/boot/initramfs.xz" ]; then | |
| INITRAMFS_DIGEST=$(sha256sum talos/arm64/boot/initramfs.xz | cut -d' ' -f1) | |
| echo "initramfs-digest=$INITRAMFS_DIGEST" >> $GITHUB_OUTPUT | |
| elif [ -f "boot/initramfs.xz" ]; then | |
| INITRAMFS_DIGEST=$(sha256sum boot/initramfs.xz | cut -d' ' -f1) | |
| echo "initramfs-digest=$INITRAMFS_DIGEST" >> $GITHUB_OUTPUT | |
| fi | |
| echo "asset-count=$ASSET_COUNT" >> $GITHUB_OUTPUT | |
| echo "validation-status=success" >> $GITHUB_OUTPUT | |
| echo "✅ Successfully extracted and validated ARM64 asset array:" | |
| ls -la . | |
| - name: Verify upstream CozyStack image build and push | |
| id: upstream-verify | |
| run: | | |
| cd cozystack-upstream | |
| # Get build outputs from upstream build | |
| BUILD_OUTPUTS="${{ steps.build.outputs.build-outputs }}" | |
| TALOS_VERSION="${{ steps.build.outputs.talos-version }}" | |
| echo "✅ Upstream CozyStack build completed successfully!" | |
| echo "Built: $BUILD_OUTPUTS" | |
| echo "Talos Version: $TALOS_VERSION" | |
| # The upstream Makefile targets already pushed to our registry: | |
| echo "Images pushed to ${{ env.REGISTRY }}:" | |
| echo " - talos:v$TALOS_VERSION (if image-talos target ran)" | |
| echo " - matchbox:latest (if image-matchbox target ran)" | |
| - name: Validate ARM64 image architectures | |
| id: arm64-validation | |
| run: | | |
| echo "🧪 Validating that our container images are actually ARM64..." | |
| BUILD_OUTPUTS="${{ steps.build.outputs.build-outputs }}" | |
| # Only test container images (not OS filesystem images like Talos) | |
| if [[ "$BUILD_OUTPUTS" == *"matchbox"* ]]; then | |
| echo "🔍 Testing matchbox container image architecture and functionality..." | |
| MATCHBOX_IMAGE="${{ env.REGISTRY }}/matchbox/cozystack-${{ matrix.extension_variant }}:latest" | |
| # First check if the image actually exists | |
| echo "Checking if matchbox image exists in registry..." | |
| if ! docker manifest inspect "$MATCHBOX_IMAGE" >/dev/null 2>&1; then | |
| echo "❌ Matchbox image does not exist in registry: $MATCHBOX_IMAGE" | |
| echo "This indicates the matchbox build/push failed earlier" | |
| echo "build-outputs claimed 'matchbox' but image is not available" | |
| # Don't fail the validation if build strategy expected this | |
| if [[ "${{ github.event.inputs.build_targets || 'talos-first' }}" == "talos-first" ]]; then | |
| echo "ℹ️ Expected behavior with 'talos-first' strategy - matchbox may fail on first run" | |
| echo "🎯 ARM64 validation skipped (no images to test)" >> $GITHUB_STEP_SUMMARY | |
| exit 0 | |
| else | |
| echo "💥 Unexpected - non-talos-first build should have working matchbox image" | |
| exit 1 | |
| fi | |
| fi | |
| # Pull ARM64 variant specifically | |
| docker pull --platform linux/arm64 "$MATCHBOX_IMAGE" | |
| # Inspect image architecture | |
| MATCHBOX_ARCH=$(docker image inspect --format='{{.Architecture}}' "$MATCHBOX_IMAGE") | |
| echo "Matchbox image architecture: $MATCHBOX_ARCH" | |
| if [[ "$MATCHBOX_ARCH" == "arm64" ]]; then | |
| echo "✅ Matchbox image is ARM64" | |
| else | |
| echo "❌ Matchbox image is not ARM64: $MATCHBOX_ARCH" | |
| exit 1 | |
| fi | |
| echo "🧪 Testing matchbox server startup on ARM64..." | |
| # Test that matchbox can actually start on ARM64 | |
| timeout 10s docker run --rm --platform linux/arm64 \ | |
| "$MATCHBOX_IMAGE" -help || true | |
| if [[ $? -eq 124 ]]; then | |
| echo "✅ Matchbox server started successfully (timed out as expected)" | |
| else | |
| echo "✅ Matchbox server help command completed" | |
| fi | |
| echo "✅ Matchbox ARM64 validation completed successfully!" | |
| echo "🎯 Matchbox confirmed as ARM64-compatible" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "ℹ️ No container images to validate (Talos is filesystem image, not container)" | |
| echo "🎯 ARM64 validation skipped (no container images)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Set up Docker Buildx (for fallback asset container) | |
| if: steps.build.outputs.build-outputs == 'kernel,initramfs,iso,nocloud,metal' | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| driver: docker-container | |
| platforms: linux/arm64,linux/amd64 | |
| - name: Log in to GitHub Container Registry (for fallback) | |
| if: steps.build.outputs.build-outputs == 'kernel,initramfs,iso,nocloud,metal' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to GitHub Container Registry (for upstream images) | |
| if: steps.build.outputs.build-outputs != 'kernel,initramfs,iso,nocloud,metal' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate container metadata | |
| if: steps.build.outputs.build-outputs == 'kernel,initramfs,iso,nocloud,metal' | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/talos/cozystack-${{ matrix.extension_variant }} | |
| tags: | | |
| # Clean Talos version (variant is in repo name now) | |
| type=raw,value=${{ steps.build.outputs.talos-version }} | |
| # Date-based tag for reproducibility | |
| type=raw,value={{date 'YYYYMMDD'}}-{{sha}} | |
| # Demo stable tag (only on main branch) | |
| type=raw,value=demo-stable,enable={{is_default_branch}} | |
| # Latest tag (only on main branch) | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push asset container | |
| if: steps.build.outputs.build-outputs == 'kernel,initramfs,iso,nocloud,metal' | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: ./cozystack-upstream | |
| file: ./cozystack-upstream/Dockerfile.assets | |
| platforms: linux/arm64,linux/amd64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| # No cache export - docker driver doesn't support any cache export backends | |
| - name: Extract first tag for testing | |
| if: steps.build.outputs.build-outputs == 'kernel,initramfs,iso,nocloud,metal' | |
| id: extract-first-tag | |
| run: | | |
| # Get the first tag from the metadata output for smoke testing | |
| FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1) | |
| echo "first-tag=$FIRST_TAG" >> $GITHUB_OUTPUT | |
| echo "Using tag for smoke test: $FIRST_TAG" | |
| - name: Generate build summary | |
| run: | | |
| echo "## 🚀 Custom Talos Image Build Complete" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Image Digest:** \`${{ steps.build.outputs.digest }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tags pushed:**" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Pull commands:**" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then | |
| echo "# Pull latest build (demo-stable only available on main):" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:demo-stable" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "# For AWS bastion setup:" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:demo-stable" >> $GITHUB_STEP_SUMMARY | |
| echo "docker run --rm -v /opt/matchbox/assets:/output \\" >> $GITHUB_STEP_SUMMARY | |
| echo " ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:demo-stable \\" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "# Pull PR build (demo-stable available after merge to main):" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:$(date +%Y%m%d)-${{ github.sha }}-${{ matrix.extension_variant }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "# For testing asset extraction:" >> $GITHUB_STEP_SUMMARY | |
| echo "docker pull ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:$(date +%Y%m%d)-${{ github.sha }}-${{ matrix.extension_variant }}" >> $GITHUB_STEP_SUMMARY | |
| echo "docker run --rm -v /tmp/test-assets:/output \\" >> $GITHUB_STEP_SUMMARY | |
| echo " ${{ env.REGISTRY }}/talos-cozystack-${{ matrix.extension_variant }}:$(date +%Y%m%d)-${{ github.sha }}-${{ matrix.extension_variant }} \\" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo " extract-boot-assets /output/talos/custom/" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| test-image-smoke: | |
| runs-on: ubuntu-latest | |
| needs: build-cozystack-upstream | |
| strategy: | |
| matrix: | |
| extension_variant: [spin-tailscale, spin-only] | |
| env: | |
| REGISTRY: ghcr.io/urmanac | |
| steps: | |
| - name: Install crane for container inspection | |
| run: | | |
| # Install crane (container registry tool) for FROM scratch container testing | |
| ARCH=$(uname -m) | |
| if [ "$ARCH" = "x86_64" ]; then CRANE_ARCH="x86_64"; else CRANE_ARCH="arm64"; fi | |
| curl -L https://github.com/google/go-containerregistry/releases/latest/download/go-containerregistry_Linux_${CRANE_ARCH}.tar.gz | sudo tar xz -C /usr/local/bin crane | |
| crane version | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Test complete asset array extraction and validation | |
| run: | | |
| # Test that container can be pulled and assets extracted | |
| # Use crane for FROM scratch containers (better than docker cp) | |
| VARIANT="${{ matrix.extension_variant }}" | |
| REGISTRY="${{ env.REGISTRY }}" | |
| # Test the talos repository (correct path with new hierarchy) | |
| echo "Testing $VARIANT variant..." | |
| TALOS_REPO="$REGISTRY/talos/cozystack-$VARIANT" | |
| echo "Checking for available tags in: $TALOS_REPO" | |
| if crane ls "$TALOS_REPO" 2>/dev/null; then | |
| echo "✅ Found talos repository: $TALOS_REPO" | |
| # Try demo-stable first, fall back to latest available tag | |
| if crane manifest "$TALOS_REPO:demo-stable" >/dev/null 2>&1; then | |
| IMAGE_TAG="$TALOS_REPO:demo-stable" | |
| echo "Using demo-stable tag: $IMAGE_TAG" | |
| else | |
| LATEST_TAG=$(crane ls "$TALOS_REPO" | head -1) | |
| if [ -n "$LATEST_TAG" ]; then | |
| IMAGE_TAG="$TALOS_REPO:$LATEST_TAG" | |
| echo "demo-stable not found, using: $IMAGE_TAG" | |
| else | |
| echo "⚠️ No tags found in repository: $TALOS_REPO" | |
| exit 0 | |
| fi | |
| fi | |
| else | |
| echo "⚠️ No talos repository found for variant: $VARIANT" | |
| echo "Repository may not exist yet or be private" | |
| exit 0 | |
| fi | |
| # Test comprehensive asset extraction using crane | |
| echo "Testing image: $IMAGE_TAG" | |
| mkdir -p /tmp/test-assets-$VARIANT | |
| cd /tmp/test-assets-$VARIANT | |
| echo "Attempting to export image..." | |
| if crane export "$IMAGE_TAG" | tar -xf -; then | |
| echo "✅ Successfully exported image contents" | |
| else | |
| echo "❌ Failed to export image - may not exist yet or have wrong format" | |
| exit 0 | |
| fi | |
| # Validate core ARM64 boot assets | |
| test -f assets/talos/arm64/boot/vmlinuz || test -f assets/talos/arm64/vmlinuz || echo "⚠️ vmlinuz not found" | |
| test -f assets/talos/arm64/boot/initramfs.xz || test -f assets/talos/arm64/initramfs.xz || echo "⚠️ initramfs.xz not found" | |
| # Validate checksums | |
| test -f assets/talos/arm64/checksums.sha256 || echo "⚠️ checksums.sha256 not found" | |
| # Validate build report | |
| test -f assets/talos/arm64/validation/build-report.txt || echo "⚠️ build-report.txt not found" | |
| # Show validation results | |
| if [ -f assets/talos/arm64/validation/build-report.txt ]; then | |
| echo "Build Report:" | |
| cat assets/talos/arm64/validation/build-report.txt | |
| fi | |
| # Verify checksums if available | |
| if [ -f assets/talos/arm64/checksums.sha256 ]; then | |
| echo "Verifying asset checksums..." | |
| cd assets/talos/arm64 | |
| sha256sum -c checksums.sha256 && echo "✅ Checksums verified" || echo "⚠️ Checksum verification failed" | |
| fi | |
| echo "✅ CozyStack ARM64 complete asset array tests passed" | |
| echo "Assets found:" | |
| find /tmp/test-assets -type f | sort | |
| update-docs: | |
| runs-on: ubuntu-latest | |
| needs: [build-cozystack-upstream] | |
| if: github.ref == 'refs/heads/main' && success() | |
| permissions: | |
| contents: write # Need write permission to push docs | |
| pages: write # Need pages permission for GitHub Pages | |
| id-token: write # Need for pages deployment | |
| env: | |
| REGISTRY: ghcr.io/urmanac | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Update build documentation | |
| run: | | |
| # Update docs with latest build info | |
| TALOS_VERSION="${{ needs.build-cozystack-upstream.outputs.talos-version }}" | |
| KERNEL_DIGEST="${{ needs.build-cozystack-upstream.outputs.kernel-digest }}" | |
| INITRAMFS_DIGEST="${{ needs.build-cozystack-upstream.outputs.initramfs-digest }}" | |
| ASSET_COUNT="${{ needs.build-cozystack-upstream.outputs.asset-count || 'N/A' }}" | |
| BUILD_TARGET="${{ needs.build-cozystack-upstream.outputs.build-target }}" | |
| DATE=$(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| cat > docs/LATEST-BUILD.md << EOF | |
| # Latest CozyStack ARM64 Talos Build | |
| **Built:** $DATE | |
| **Talos Version:** \`$TALOS_VERSION\` | |
| **CozyStack Commit:** \`$COZYSTACK_COMMIT\` | |
| **Build Target:** \`$BUILD_TARGET\` | |
| **Total Assets:** $ASSET_COUNT | |
| ## Asset Digests | |
| | Asset | Digest | | |
| |-------|--------| | |
| | **Kernel** | \`${KERNEL_DIGEST:-'not found'}\` | | |
| | **Boot Loader** | \`${INITRAMFS_DIGEST:-'not found'}\` | | |
| ## Container Images | |
| Two variants are built for different use cases: | |
| ### talos/cozystack-spin-tailscale (Full Stack) | |
| Includes Spin runtime + Tailscale networking for complete demo environment. | |
| \`\`\`bash | |
| docker pull ${{ env.REGISTRY }}/talos/cozystack-spin-tailscale:demo-stable | |
| \`\`\` | |
| ### talos/cozystack-spin-only (Minimal) | |
| Includes only Spin runtime for lightweight deployments. | |
| \`\`\`bash | |
| docker pull ${{ env.REGISTRY }}/talos/cozystack-spin-only:demo-stable | |
| \`\`\` | |
| ## Asset Extraction | |
| Extract complete Talos installer assets: | |
| \`\`\`bash | |
| # Create local assets directory | |
| mkdir -p ./cozystack-assets | |
| # Extract from talos/cozystack-spin-tailscale image (recommended) | |
| docker create --name temp-extract ${{ env.REGISTRY }}/talos/cozystack-spin-tailscale:demo-stable | |
| docker cp temp-extract:/. ./cozystack-assets | |
| docker rm temp-extract | |
| # Key assets are located at: | |
| # ./cozystack-assets/usr/install/arm64/vmlinuz.efi | |
| # ./cozystack-assets/usr/install/arm64/systemd-boot.efi | |
| # ./cozystack-assets/usr/bin/installer | |
| \`\`\` | |
| EOF | |
| - name: Commit updated docs | |
| run: | | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| git add docs/LATEST-BUILD.md | |
| git commit -m "Update CozyStack ARM64 build: ${{ needs.build-cozystack-upstream.outputs.talos-version }}" || exit 0 | |
| git push |