Release VM Dev #6
Workflow file for this run
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 Dev | |
| # Build openshell-vm binaries for all supported platforms and upload them to | |
| # the rolling "vm-dev" GitHub Release. Each binary is self-extracting: it | |
| # embeds pre-built kernel runtime artifacts (from release-vm-kernel.yml) and a | |
| # base rootfs tarball. | |
| # | |
| # Prerequisites: the vm-dev release must already contain kernel runtime | |
| # tarballs. Run the "Release VM Kernel" workflow first if they are missing. | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| packages: read | |
| # Serialize with release-vm-kernel.yml — both update the vm-dev release. | |
| concurrency: | |
| group: vm-dev-release | |
| cancel-in-progress: false | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Compute versions (reuse the same logic as release-dev.yml) | |
| # --------------------------------------------------------------------------- | |
| compute-versions: | |
| name: Compute Versions | |
| runs-on: build-amd64 | |
| timeout-minutes: 5 | |
| container: | |
| image: ghcr.io/nvidia/openshell/ci:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| outputs: | |
| cargo_version: ${{ steps.v.outputs.cargo }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Mark workspace safe for git | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - name: Fetch tags | |
| run: git fetch --tags --force | |
| - name: Compute versions | |
| id: v | |
| run: | | |
| set -euo pipefail | |
| echo "cargo=$(uv run python tasks/scripts/release.py get-version --cargo)" >> "$GITHUB_OUTPUT" | |
| # --------------------------------------------------------------------------- | |
| # Download kernel runtime tarballs from the vm-dev release | |
| # --------------------------------------------------------------------------- | |
| download-kernel-runtime: | |
| name: Download Kernel Runtime | |
| runs-on: build-amd64 | |
| timeout-minutes: 10 | |
| container: | |
| image: ghcr.io/nvidia/openshell/ci:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all runtime tarballs | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p runtime-artifacts | |
| for platform in linux-aarch64 linux-x86_64 darwin-aarch64; do | |
| echo "Downloading vm-runtime-${platform}.tar.zst..." | |
| gh release download vm-dev \ | |
| --repo "${GITHUB_REPOSITORY}" \ | |
| --pattern "vm-runtime-${platform}.tar.zst" \ | |
| --dir runtime-artifacts \ | |
| --clobber | |
| done | |
| echo "Downloaded runtime artifacts:" | |
| ls -lah runtime-artifacts/ | |
| - name: Verify downloads | |
| run: | | |
| set -euo pipefail | |
| for platform in linux-aarch64 linux-x86_64 darwin-aarch64; do | |
| file="runtime-artifacts/vm-runtime-${platform}.tar.zst" | |
| if [ ! -f "$file" ]; then | |
| echo "ERROR: Missing ${file}" >&2 | |
| echo "" >&2 | |
| echo "The vm-dev release does not have kernel runtime artifacts." >&2 | |
| echo "Run the 'Release VM Kernel' workflow first:" >&2 | |
| echo " gh workflow run release-vm-kernel.yml" >&2 | |
| exit 1 | |
| fi | |
| echo "OK: ${file} ($(du -sh "$file" | cut -f1))" | |
| done | |
| - name: Upload as workflow artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: kernel-runtime-tarballs | |
| path: runtime-artifacts/vm-runtime-*.tar.zst | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Build base rootfs tarballs (architecture-specific) | |
| # --------------------------------------------------------------------------- | |
| build-rootfs: | |
| name: Build Rootfs (${{ matrix.arch }}) | |
| needs: [compute-versions] | |
| strategy: | |
| matrix: | |
| include: | |
| - arch: arm64 | |
| runner: build-arm64 | |
| guest_arch: aarch64 | |
| - arch: amd64 | |
| runner: build-amd64 | |
| guest_arch: x86_64 | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| container: | |
| image: ghcr.io/nvidia/openshell/ci:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| options: --privileged | |
| volumes: | |
| - /var/run/docker.sock:/var/run/docker.sock | |
| env: | |
| MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| OPENSHELL_IMAGE_TAG: dev | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Mark workspace safe for git | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - name: Log in to GHCR | |
| run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin | |
| - name: Install tools | |
| run: mise install | |
| - name: Install zstd | |
| run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/* | |
| - name: Build base rootfs tarball | |
| run: | | |
| set -euo pipefail | |
| crates/openshell-vm/scripts/build-rootfs.sh \ | |
| --base \ | |
| --arch ${{ matrix.guest_arch }} \ | |
| target/rootfs-build | |
| mkdir -p target/vm-runtime-compressed | |
| tar -C target/rootfs-build -cf - . \ | |
| | zstd -19 -T0 -o target/vm-runtime-compressed/rootfs.tar.zst | |
| echo "Rootfs tarball: $(du -sh target/vm-runtime-compressed/rootfs.tar.zst | cut -f1)" | |
| - name: Upload rootfs artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rootfs-${{ matrix.arch }} | |
| path: target/vm-runtime-compressed/rootfs.tar.zst | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Build openshell-vm binary (Linux — native on each arch) | |
| # --------------------------------------------------------------------------- | |
| build-vm-linux: | |
| name: Build VM (Linux ${{ matrix.arch }}) | |
| needs: [compute-versions, download-kernel-runtime, build-rootfs] | |
| strategy: | |
| matrix: | |
| include: | |
| - arch: arm64 | |
| runner: build-arm64 | |
| target: aarch64-unknown-linux-gnu | |
| platform: linux-aarch64 | |
| guest_arch: aarch64 | |
| - arch: amd64 | |
| runner: build-amd64 | |
| target: x86_64-unknown-linux-gnu | |
| platform: linux-x86_64 | |
| guest_arch: x86_64 | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| container: | |
| image: ghcr.io/nvidia/openshell/ci:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| options: --privileged | |
| env: | |
| MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} | |
| OPENSHELL_IMAGE_TAG: dev | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Mark workspace safe for git | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - name: Fetch tags | |
| run: git fetch --tags --force | |
| - name: Install tools | |
| run: mise install | |
| - name: Cache Rust target and registry | |
| uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2 | |
| with: | |
| shared-key: vm-linux-${{ matrix.arch }} | |
| cache-directories: .cache/sccache | |
| cache-targets: "true" | |
| - name: Install zstd | |
| run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/* | |
| - name: Download kernel runtime tarball | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: kernel-runtime-tarballs | |
| path: runtime-download/ | |
| - name: Download rootfs tarball | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rootfs-${{ matrix.arch }} | |
| path: rootfs-download/ | |
| - name: Stage compressed runtime for embedding | |
| run: | | |
| set -euo pipefail | |
| COMPRESSED_DIR="${PWD}/target/vm-runtime-compressed" | |
| mkdir -p "$COMPRESSED_DIR" | |
| # Extract kernel runtime tarball and re-compress individual files | |
| EXTRACT_DIR=$(mktemp -d) | |
| zstd -d "runtime-download/vm-runtime-${{ matrix.platform }}.tar.zst" --stdout \ | |
| | tar -xf - -C "$EXTRACT_DIR" | |
| echo "Extracted runtime files:" | |
| ls -lah "$EXTRACT_DIR" | |
| for file in "$EXTRACT_DIR"/*; do | |
| [ -f "$file" ] || continue | |
| name=$(basename "$file") | |
| [ "$name" = "provenance.json" ] && continue | |
| zstd -19 -f -q -T0 -o "${COMPRESSED_DIR}/${name}.zst" "$file" | |
| done | |
| # Copy rootfs tarball (already zstd-compressed) | |
| cp rootfs-download/rootfs.tar.zst "${COMPRESSED_DIR}/rootfs.tar.zst" | |
| echo "Staged compressed artifacts:" | |
| ls -lah "$COMPRESSED_DIR" | |
| - name: Scope workspace to VM crates | |
| run: | | |
| set -euo pipefail | |
| sed -i 's|members = \["crates/\*"\]|members = ["crates/openshell-vm", "crates/openshell-core", "crates/openshell-bootstrap", "crates/openshell-policy"]|' Cargo.toml | |
| - name: Patch workspace version | |
| if: needs.compute-versions.outputs.cargo_version != '' | |
| run: | | |
| set -euo pipefail | |
| sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml | |
| - name: Build openshell-vm | |
| run: | | |
| set -euo pipefail | |
| OPENSHELL_VM_RUNTIME_COMPRESSED_DIR="${PWD}/target/vm-runtime-compressed" \ | |
| mise x -- cargo build --release -p openshell-vm | |
| - name: sccache stats | |
| if: always() | |
| run: mise x -- sccache --show-stats | |
| - name: Package binary | |
| run: | | |
| set -euo pipefail | |
| mkdir -p artifacts | |
| tar -czf "artifacts/openshell-vm-${{ matrix.target }}.tar.gz" \ | |
| -C target/release openshell-vm | |
| ls -lh artifacts/ | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: vm-linux-${{ matrix.arch }} | |
| path: artifacts/*.tar.gz | |
| retention-days: 5 | |
| # --------------------------------------------------------------------------- | |
| # Build openshell-vm binary (macOS ARM64 via osxcross) | |
| # --------------------------------------------------------------------------- | |
| build-vm-macos: | |
| name: Build VM (macOS) | |
| needs: [compute-versions, download-kernel-runtime, build-rootfs] | |
| runs-on: build-amd64 | |
| timeout-minutes: 60 | |
| container: | |
| image: ghcr.io/nvidia/openshell/ci:latest | |
| credentials: | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| options: --privileged | |
| volumes: | |
| - /var/run/docker.sock:/var/run/docker.sock | |
| env: | |
| MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SCCACHE_MEMCACHED_ENDPOINT: ${{ vars.SCCACHE_MEMCACHED_ENDPOINT }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Mark workspace safe for git | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - name: Fetch tags | |
| run: git fetch --tags --force | |
| - name: Log in to GHCR | |
| run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin | |
| - name: Set up Docker Buildx | |
| uses: ./.github/actions/setup-buildx | |
| - name: Install zstd | |
| run: apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/* | |
| - name: Download kernel runtime tarball | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: kernel-runtime-tarballs | |
| path: runtime-download/ | |
| - name: Download rootfs tarball (arm64) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: rootfs-arm64 | |
| path: rootfs-download/ | |
| - name: Prepare compressed runtime directory | |
| run: | | |
| set -euo pipefail | |
| COMPRESSED_DIR="${PWD}/target/vm-runtime-compressed-macos" | |
| mkdir -p "$COMPRESSED_DIR" | |
| # Extract the darwin runtime tarball and re-compress for embedding. | |
| # The macOS embedded.rs expects: libkrun.dylib.zst, libkrunfw.5.dylib.zst, gvproxy.zst | |
| EXTRACT_DIR=$(mktemp -d) | |
| zstd -d "runtime-download/vm-runtime-darwin-aarch64.tar.zst" --stdout \ | |
| | tar -xf - -C "$EXTRACT_DIR" | |
| echo "Extracted darwin runtime files:" | |
| ls -lah "$EXTRACT_DIR" | |
| for file in "$EXTRACT_DIR"/*; do | |
| [ -f "$file" ] || continue | |
| name=$(basename "$file") | |
| [ "$name" = "provenance.json" ] && continue | |
| zstd -19 -f -q -T0 -o "${COMPRESSED_DIR}/${name}.zst" "$file" | |
| done | |
| # The macOS VM guest is always Linux ARM64, so use the arm64 rootfs | |
| cp rootfs-download/rootfs.tar.zst "${COMPRESSED_DIR}/rootfs.tar.zst" | |
| echo "Staged macOS compressed artifacts:" | |
| ls -lah "$COMPRESSED_DIR" | |
| - name: Build macOS binary via Docker (osxcross) | |
| run: | | |
| set -euo pipefail | |
| docker buildx build \ | |
| --file deploy/docker/Dockerfile.vm-macos \ | |
| --build-arg OPENSHELL_CARGO_VERSION="${{ needs.compute-versions.outputs.cargo_version }}" \ | |
| --build-arg OPENSHELL_IMAGE_TAG=dev \ | |
| --build-arg CARGO_TARGET_CACHE_SCOPE="${{ github.sha }}" \ | |
| --build-context vm-runtime-compressed="${PWD}/target/vm-runtime-compressed-macos" \ | |
| --target binary \ | |
| --output type=local,dest=out/ \ | |
| . | |
| - name: Package binary | |
| run: | | |
| set -euo pipefail | |
| mkdir -p artifacts | |
| tar -czf artifacts/openshell-vm-aarch64-apple-darwin.tar.gz \ | |
| -C out openshell-vm | |
| ls -lh artifacts/ | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: vm-macos | |
| path: artifacts/*.tar.gz | |
| retention-days: 5 | |
| # --------------------------------------------------------------------------- | |
| # Upload all VM binaries to the vm-dev rolling release | |
| # --------------------------------------------------------------------------- | |
| release-vm-dev: | |
| name: Release VM Dev | |
| needs: [build-vm-linux, build-vm-macos] | |
| runs-on: build-amd64 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all VM binary artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: vm-* | |
| path: release/ | |
| merge-multiple: true | |
| - name: Filter to only binary tarballs | |
| run: | | |
| set -euo pipefail | |
| mkdir -p release-final | |
| # Only include the openshell-vm binary tarballs, not kernel runtime | |
| cp release/openshell-vm-*.tar.gz release-final/ | |
| count=$(ls release-final/openshell-vm-*.tar.gz 2>/dev/null | wc -l) | |
| if [ "$count" -eq 0 ]; then | |
| echo "ERROR: No VM binary tarballs found in release/" >&2 | |
| exit 1 | |
| fi | |
| echo "Release artifacts (${count} binaries):" | |
| ls -lh release-final/ | |
| - name: Generate checksums | |
| run: | | |
| set -euo pipefail | |
| cd release-final | |
| sha256sum openshell-vm-*.tar.gz > vm-binary-checksums-sha256.txt | |
| cat vm-binary-checksums-sha256.txt | |
| - name: Ensure vm-dev tag exists | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -fa vm-dev -m "VM Development Build" "${GITHUB_SHA}" | |
| git push --force origin vm-dev | |
| - name: Prune stale VM binary assets from vm-dev release | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); | |
| let release; | |
| try { | |
| release = await github.rest.repos.getReleaseByTag({ owner, repo, tag: 'vm-dev' }); | |
| } catch (err) { | |
| if (err.status === 404) { | |
| core.info('No existing vm-dev release; will create fresh.'); | |
| return; | |
| } | |
| throw err; | |
| } | |
| // Delete old VM binary assets (keep kernel runtime assets) | |
| for (const asset of release.data.assets) { | |
| if (asset.name.startsWith('openshell-vm-') || asset.name === 'vm-binary-checksums-sha256.txt') { | |
| core.info(`Deleting stale asset: ${asset.name}`); | |
| await github.rest.repos.deleteReleaseAsset({ owner, repo, asset_id: asset.id }); | |
| } | |
| } | |
| - name: Upload to vm-dev GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: OpenShell VM Development Build | |
| prerelease: true | |
| tag_name: vm-dev | |
| target_commitish: ${{ github.sha }} | |
| body: | | |
| Rolling development build of **openshell-vm** — the MicroVM runtime for OpenShell. | |
| > **NOTE**: This is a development build, not a tagged release, and may be unstable. | |
| ### Kernel Runtime Artifacts | |
| Pre-built kernel runtime (libkrunfw + libkrun + gvproxy) for embedding into | |
| the openshell-vm binary. These are rebuilt when the kernel config or pinned | |
| dependency versions change. | |
| | Platform | Artifact | | |
| |----------|----------| | |
| | Linux ARM64 | `vm-runtime-linux-aarch64.tar.zst` | | |
| | Linux x86_64 | `vm-runtime-linux-x86_64.tar.zst` | | |
| | macOS ARM64 | `vm-runtime-darwin-aarch64.tar.zst` | | |
| ### VM Binaries | |
| Self-extracting openshell-vm binaries with embedded kernel runtime and base | |
| rootfs. These are rebuilt on every push to main. | |
| | Platform | Artifact | | |
| |----------|----------| | |
| | Linux ARM64 | `openshell-vm-aarch64-unknown-linux-gnu.tar.gz` | | |
| | Linux x86_64 | `openshell-vm-x86_64-unknown-linux-gnu.tar.gz` | | |
| | macOS ARM64 | `openshell-vm-aarch64-apple-darwin.tar.gz` | | |
| ### Quick install | |
| ``` | |
| curl -fsSL https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install-vm.sh | sh | |
| ``` | |
| Auto-detects your platform, verifies checksums, and codesigns on macOS. | |
| files: | | |
| release-final/openshell-vm-aarch64-unknown-linux-gnu.tar.gz | |
| release-final/openshell-vm-x86_64-unknown-linux-gnu.tar.gz | |
| release-final/openshell-vm-aarch64-apple-darwin.tar.gz | |
| release-final/vm-binary-checksums-sha256.txt |