flashbox-l1: document BuilderNet bottom-of-block in readme (#166) #55
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
| # GitHub Actions workflow for building mkosi images using Nix. | |
| # | |
| # Triggers on: | |
| # - Pushes to main branch: Builds all images (flashbox-l1, flashbox-l2) in parallel | |
| # | |
| # - Manual dispatch: Allows specifying: | |
| # - Branch to build from (default: main) | |
| # - Images to build (default: flashbox-l1) | |
| # - "all" → builds flashbox-l1 and flashbox-l2 | |
| # - "flashbox-l1" → builds only flashbox-l1 | |
| # - "flashbox-l2" → builds only flashbox-l2 | |
| # - "flashbox-l1,flashbox-l2" → builds both | |
| # - Reproducibility test (default: false) | |
| # - Adds a second build on a separate runner and compares SHA256 hashes | |
| name: Build mkosi images | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| branch: | |
| description: 'Branch to build' | |
| required: false | |
| default: 'main' | |
| type: string | |
| images: | |
| description: 'Images to build (comma-separated: flashbox-l1,flashbox-l2 or "all")' | |
| required: false | |
| default: 'flashbox-l1' | |
| type: string | |
| reprotest: | |
| description: 'Run reproducibility test (builds on 2 machines and compares hashes)' | |
| required: false | |
| default: false | |
| type: boolean | |
| jobs: | |
| validate: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - name: Validate images | |
| id: set-matrix | |
| shell: python3 {0} | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| INPUT_IMAGES: ${{ inputs.images }} | |
| run: | | |
| import json | |
| import os | |
| import sys | |
| VALID_IMAGES = ["flashbox-l1", "flashbox-l2"] | |
| event = os.environ["EVENT_NAME"] | |
| requested = os.environ.get("INPUT_IMAGES", "all").strip() | |
| if event == "workflow_dispatch" and requested != "all": | |
| images = [img.strip() for img in requested.split(",") if img.strip()] | |
| invalid = [img for img in images if img not in VALID_IMAGES] | |
| if invalid: | |
| print(f"❌ Error: Invalid image(s): {', '.join(invalid)}") | |
| print(f"Valid images are: {', '.join(VALID_IMAGES)}") | |
| sys.exit(1) | |
| else: | |
| images = VALID_IMAGES | |
| matrix = json.dumps(images) | |
| with open(os.environ["GITHUB_OUTPUT"], "a") as f: | |
| f.write(f"matrix={matrix}\n") | |
| print(f"✓ Building images: {matrix}") | |
| build: | |
| needs: validate | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: ${{ fromJSON(needs.validate.outputs.matrix) }} | |
| name: build ${{ matrix.image }} image | |
| runs-on: warp-ubuntu-latest-x64-32x | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.branch || github.ref }} | |
| - name: Install tools | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y debian-archive-keyring | |
| - name: Install Nix | |
| uses: cachix/install-nix-action@v27 | |
| with: | |
| extra_nix_config: | | |
| experimental-features = nix-command flakes | |
| - name: Enable user namespaces | |
| run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| - name: Build ${{ matrix.image }} image | |
| run: | | |
| umask 022 | |
| nix develop --command mkosi --force -I images/${{ matrix.image }}.conf --image-id=${{ matrix.image }} | |
| - name: Fix permissions | |
| run: | | |
| sudo chown -R $(id -u):$(id -g) build/ | |
| - name: Show build artifacts | |
| run: | | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📦 Image: ${{ matrix.image }}" | |
| echo "🔖 Commit: ${{ github.sha }}" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| if [ -d "build" ]; then | |
| echo "" | |
| # Show only filename and size for matching files | |
| ls -lh build/ | grep -E "${{ matrix.image }}" | awk '{print $9, "(" $5 ")"}' | |
| else | |
| echo "⚠️ Build directory not found" | |
| fi | |
| - name: Generate SHA256 checksums | |
| run: | | |
| sha256sum build/${{ matrix.image }}_*.efi | tee build/checksum.sha256 | |
| - name: Upload checksum for reprotest | |
| if: inputs.reprotest == true | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: checksum-${{ matrix.image }}-build-1 | |
| path: build/checksum.sha256 | |
| retention-days: 1 | |
| reprotest-build: | |
| needs: validate | |
| if: inputs.reprotest == true | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: ${{ fromJSON(needs.validate.outputs.matrix) }} | |
| name: reprotest ${{ matrix.image }} | |
| runs-on: warp-ubuntu-latest-x64-32x | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.branch || github.ref }} | |
| - name: Install tools | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y debian-archive-keyring | |
| - name: Install Nix | |
| uses: cachix/install-nix-action@v27 | |
| with: | |
| extra_nix_config: | | |
| experimental-features = nix-command flakes | |
| - name: Enable user namespaces | |
| run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| - name: Build ${{ matrix.image }} image | |
| run: | | |
| umask 022 | |
| nix develop --command mkosi --force -I images/${{ matrix.image }}.conf --image-id=${{ matrix.image }} | |
| sudo chown -R $(id -u):$(id -g) build/ | |
| - name: Generate SHA256 checksum | |
| run: | | |
| sha256sum build/${{ matrix.image }}_*.efi | tee build/checksum.sha256 | |
| - name: Upload checksum | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: checksum-${{ matrix.image }}-build-2 | |
| path: build/checksum.sha256 | |
| retention-days: 1 | |
| reprotest-compare: | |
| needs: [validate, build, reprotest-build] | |
| if: inputs.reprotest == true | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: ${{ fromJSON(needs.validate.outputs.matrix) }} | |
| name: reprotest compare ${{ matrix.image }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download checksums | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: checksum-${{ matrix.image }}-* | |
| path: checksums/ | |
| - name: Compare SHA256 hashes | |
| run: | | |
| echo "=== Reproducibility Check for ${{ matrix.image }} ===" | |
| echo "Build 1 (all artifacts):" | |
| cat checksums/checksum-${{ matrix.image }}-build-1/*.sha256 | |
| echo "Build 2 (EFI only):" | |
| cat checksums/checksum-${{ matrix.image }}-build-2/checksum.sha256 | |
| # Extract only the .efi hash from build-1 to compare with build-2 | |
| hash1=$(grep '\.efi$' checksums/checksum-${{ matrix.image }}-build-1/*.sha256 | awk '{print $1}') | |
| hash2=$(awk '{print $1}' checksums/checksum-${{ matrix.image }}-build-2/checksum.sha256) | |
| echo "" | |
| echo "EFI hash build-1: $hash1" | |
| echo "EFI hash build-2: $hash2" | |
| if [ "$hash1" = "$hash2" ]; then | |
| echo "✅ SUCCESS: ${{ matrix.image }} images are identical (reproducible build verified)" | |
| else | |
| echo "❌ FAILURE: ${{ matrix.image }} images differ (reproducible build failed)" | |
| exit 1 | |
| fi |