Release VM Assets #2
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: Release VM Assets | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| channel: | ||
| description: Asset channel to publish. | ||
| required: true | ||
| default: stable | ||
| profile: | ||
| description: Profile id that owns the VM image build. | ||
| required: true | ||
| default: code | ||
| dry_run: | ||
| description: Build and validate without deploying release.capsem.org. | ||
| required: true | ||
| type: boolean | ||
| default: true | ||
| permissions: | ||
| attestations: write | ||
| contents: write | ||
| id-token: write | ||
| jobs: | ||
| build-assets: | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - arch: arm64 | ||
| runner: ubuntu-24.04-arm | ||
| rust-target: aarch64-unknown-linux-musl | ||
| - arch: x86_64 | ||
| runner: ubuntu-24.04 | ||
| rust-target: x86_64-unknown-linux-musl | ||
| runs-on: ${{ matrix.runner }} | ||
| name: Build VM assets (${{ matrix.arch }}) | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| - uses: docker/setup-buildx-action@v4 | ||
| - uses: astral-sh/setup-uv@v5 | ||
| - run: uv sync | ||
| - uses: extractions/setup-just@v3 | ||
| - uses: pnpm/action-setup@v5 | ||
| with: | ||
| version: 10 | ||
| - uses: actions/setup-node@v5 | ||
| with: | ||
| node-version: 24 | ||
| cache: pnpm | ||
| cache-dependency-path: frontend/pnpm-lock.yaml | ||
| - name: Install musl C toolchain | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y --no-install-recommends musl-tools | ||
| - name: Install OBOM generator | ||
| run: | | ||
| npm install -g @cyclonedx/cdxgen@latest | ||
| cdxgen --version | ||
| - uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| targets: ${{ matrix.rust-target }} | ||
| - name: Build VM assets (kernel + rootfs) | ||
| env: | ||
| CAPSEM_CDXGEN_CMD: cdxgen | ||
| CC_aarch64_unknown_linux_musl: musl-gcc | ||
| CC_x86_64_unknown_linux_musl: musl-gcc | ||
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc | ||
| CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc | ||
| run: | | ||
| just build-kernel ${{ matrix.arch }} "${{ inputs.profile }}" | ||
| just build-rootfs ${{ matrix.arch }} "${{ inputs.profile }}" | ||
| - uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: vm-assets-${{ matrix.arch }} | ||
| path: assets/${{ matrix.arch }}/ | ||
| assemble-channel: | ||
| needs: build-assets | ||
| runs-on: ubuntu-latest | ||
| name: Assemble asset channel | ||
| outputs: | ||
| asset_changed: ${{ steps.asset-delta.outputs.changed }} | ||
| asset_blobs_changed: ${{ steps.asset-delta.outputs.asset_blobs_changed }} | ||
| env: | ||
| CHANNEL: ${{ inputs.channel }} | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| - uses: astral-sh/setup-uv@v5 | ||
| - run: uv sync | ||
| - uses: dtolnay/rust-toolchain@stable | ||
| - uses: Swatinem/rust-cache@v2 | ||
| - uses: actions/download-artifact@v8 | ||
| with: | ||
| name: vm-assets-arm64 | ||
| path: assets/arm64/ | ||
| - uses: actions/download-artifact@v8 | ||
| with: | ||
| name: vm-assets-x86_64 | ||
| path: assets/x86_64/ | ||
| - name: Generate asset manifest | ||
| run: | | ||
| cargo run -p capsem-admin -- manifest generate assets | ||
| - name: Preserve binary channel metadata | ||
| run: | | ||
| scripts/preserve-binary-channel-metadata.py \ | ||
| --manifest-path assets/manifest.json \ | ||
| --previous-manifest-url "https://release.capsem.org/assets/$CHANNEL/manifest.json" \ | ||
| --allow-missing-previous | ||
| - name: Check asset release delta | ||
| id: asset-delta | ||
| run: | | ||
| scripts/check-asset-release-delta.py \ | ||
| --new-manifest assets/manifest.json \ | ||
| --previous-manifest-url "https://release.capsem.org/assets/$CHANNEL/manifest.json" \ | ||
| --allow-missing-previous \ | ||
| --json-output target/asset-release-delta/delta.json | ||
| - name: Build asset channel preview | ||
| if: ${{ steps.asset-delta.outputs.changed == 'true' }} | ||
| run: | | ||
| cargo run -p capsem-admin -- assets channel build \ | ||
| --manifest "file://$PWD/assets/manifest.json" \ | ||
| --channel "$CHANNEL" \ | ||
| --out-dir target/release-channel | ||
| - name: Check asset channel preview | ||
| if: ${{ steps.asset-delta.outputs.changed == 'true' }} | ||
| run: | | ||
| cargo run -p capsem-admin -- assets channel check \ | ||
| --channel "$CHANNEL" \ | ||
| --dist target/release-channel | ||
| - name: Publish immutable GitHub asset release | ||
| if: ${{ steps.asset-delta.outputs.asset_blobs_changed == 'true' }} | ||
| env: | ||
| DRY_RUN: ${{ inputs.dry_run }} | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: | | ||
| set -euo pipefail | ||
| ASSET_VERSION=$(python - <<'PY' | ||
| import json | ||
| with open("assets/manifest.json", encoding="utf-8") as handle: | ||
| print(json.load(handle)["assets"]["current"]) | ||
| PY | ||
| ) | ||
| TAG="assets-v$ASSET_VERSION" | ||
| RELEASE_DIR="target/asset-release/$TAG" | ||
| UPLOAD_SCRIPT="target/asset-release/upload-assets.sh" | ||
| mkdir -p "$RELEASE_DIR" | ||
| for arch_dir in assets/*; do | ||
| [ -d "$arch_dir" ] || continue | ||
| arch="$(basename "$arch_dir")" | ||
| for logical_name in vmlinuz initrd.img rootfs.erofs obom.cdx.json; do | ||
| src="$arch_dir/$logical_name" | ||
| test -f "$src" | ||
| cp "$src" "$RELEASE_DIR/$arch-$logical_name" | ||
| done | ||
| done | ||
| files=("$RELEASE_DIR"/*) | ||
| test "${#files[@]}" -gt 0 | ||
| mkdir -p "$(dirname "$UPLOAD_SCRIPT")" | ||
| { | ||
| echo '#!/usr/bin/env bash' | ||
| echo 'set -euo pipefail' | ||
| printf 'if gh release view %q >/dev/null 2>&1; then\n' "$TAG" | ||
| printf ' gh release upload %q' "$TAG" | ||
| printf ' %q' "${files[@]}" | ||
| printf ' --clobber\n' | ||
| printf 'else\n' | ||
| printf ' gh release create %q' "$TAG" | ||
| printf ' %q' "${files[@]}" | ||
| printf ' --title %q --notes %q --target %q\n' \ | ||
| "Capsem VM assets $ASSET_VERSION" \ | ||
| "Immutable Capsem VM asset release for $CHANNEL/$ASSET_VERSION." \ | ||
| "$GITHUB_SHA" | ||
| printf 'fi\n' | ||
| } > "$UPLOAD_SCRIPT" | ||
| chmod +x "$UPLOAD_SCRIPT" | ||
| { | ||
| echo "asset_version=$ASSET_VERSION" | ||
| echo "asset_release_tag=$TAG" | ||
| } >> "$GITHUB_OUTPUT" | ||
| { | ||
| echo "## Immutable VM asset release" | ||
| echo | ||
| echo "- Tag: \`$TAG\`" | ||
| echo "- Dry run: \`$DRY_RUN\`" | ||
| echo "- Files:" | ||
| printf ' - `%s`\n' "${files[@]}" | ||
| } >> "$GITHUB_STEP_SUMMARY" | ||
| if [[ "$DRY_RUN" == "true" ]]; then | ||
| echo "Dry run: would publish immutable VM asset release $TAG" | ||
| sed 's/^/DRY-RUN: /' "$UPLOAD_SCRIPT" | ||
| else | ||
| "$UPLOAD_SCRIPT" | ||
| fi | ||
| - name: Attest VM asset provenance | ||
| if: ${{ inputs.dry_run == false && steps.asset-delta.outputs.asset_blobs_changed == 'true' }} | ||
| uses: actions/attest-build-provenance@v4 | ||
| with: | ||
| subject-path: | | ||
| target/asset-release/assets-v*/*-vmlinuz | ||
| target/asset-release/assets-v*/*-initrd.img | ||
| target/asset-release/assets-v*/*-rootfs.erofs | ||
| target/asset-release/assets-v*/*-obom.cdx.json | ||
| - uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: asset-channel-source | ||
| path: assets/manifest.json | ||
| - uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: asset-release-delta | ||
| path: target/asset-release-delta/ | ||
| - uses: actions/upload-artifact@v7 | ||
| if: ${{ inputs.dry_run == true && steps.asset-delta.outputs.asset_blobs_changed == 'true' }} | ||
| with: | ||
| name: asset-release-plan | ||
| path: target/asset-release/ | ||
| - uses: actions/upload-artifact@v7 | ||
| if: ${{ steps.asset-delta.outputs.changed == 'true' }} | ||
| with: | ||
| name: asset-channel-preview | ||
| path: target/release-channel/ | ||
| deploy-channel: | ||
|
Check failure on line 250 in .github/workflows/release-assets.yaml
|
||
| needs: assemble-channel | ||
| if: ${{ inputs.dry_run == false && needs.assemble-channel.outputs.asset_changed == 'true' }} | ||
| uses: ./.github/workflows/release-channel.yaml | ||
| with: | ||
| channel: ${{ inputs.channel }} | ||
| dist_artifact: asset-channel-preview | ||
| secrets: inherit | ||