Skip to content

Release VM Dev

Release VM Dev #6

Workflow file for this run

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