fix(release): build host Linux binaries with glibc floor (#1490)

This commit is contained in:
Piotr Mlocek
2026-05-22 12:12:03 -07:00
committed by GitHub
parent 521eccd47e
commit 0dc08a185e
16 changed files with 607 additions and 46 deletions
+4 -4
View File
@@ -10,7 +10,6 @@ env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SCCACHE_GHA_ENABLED: "true"
permissions:
contents: read
@@ -88,6 +87,7 @@ jobs:
runner: [linux-amd64-cpu8, linux-arm64-cpu8]
runs-on: ${{ matrix.runner }}
env:
SCCACHE_GHA_ENABLED: "true"
SCCACHE_GHA_VERSION: branch-checks-rust-${{ matrix.runner }}
container:
image: ghcr.io/nvidia/openshell/ci:latest
@@ -97,12 +97,12 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Install tools
run: mise install --locked
- name: Configure GHA sccache backend
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
- name: Install tools
run: mise install --locked
- name: Cache Rust target and registry
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
with:
+12 -4
View File
@@ -81,11 +81,13 @@ jobs:
- arch: arm64
runner: linux-arm64-cpu8
target: aarch64-unknown-linux-gnu
zig_target: aarch64-unknown-linux-gnu.2.31
platform: linux-aarch64
guest_arch: aarch64
- arch: amd64
runner: linux-amd64-cpu8
target: x86_64-unknown-linux-gnu
zig_target: x86_64-unknown-linux-gnu.2.31
platform: linux-x86_64
guest_arch: x86_64
runs-on: ${{ matrix.runner }}
@@ -163,19 +165,25 @@ jobs:
set -euo pipefail
sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ inputs['cargo-version'] }}"'"/}' Cargo.toml
- name: Build openshell-driver-vm
- name: Build openshell-driver-vm with glibc 2.31 floor
run: |
set -euo pipefail
mise x -- rustup target add ${{ matrix.target }}
OPENSHELL_VM_RUNTIME_COMPRESSED_DIR="${PWD}/target/vm-runtime-compressed" \
mise x -- cargo build --release -p openshell-driver-vm
mise x -- cargo zigbuild --release --target ${{ matrix.zig_target }} -p openshell-driver-vm --bin openshell-driver-vm
mkdir -p artifacts/bin
install -m 0755 target/${{ matrix.target }}/release/openshell-driver-vm artifacts/bin/openshell-driver-vm
- name: Verify packaged binary
run: |
set -euo pipefail
OUTPUT="$(target/release/openshell-driver-vm --version)"
OUTPUT="$(artifacts/bin/openshell-driver-vm --version)"
echo "$OUTPUT"
grep -q '^openshell-driver-vm ' <<<"$OUTPUT"
- name: Verify glibc symbol floor
run: tasks/scripts/verify-glibc-symbols.sh 2.31 artifacts/bin/openshell-driver-vm
- name: sccache stats
if: always()
run: mise x -- sccache --show-stats
@@ -185,7 +193,7 @@ jobs:
set -euo pipefail
mkdir -p artifacts
tar -czf "artifacts/openshell-driver-vm-${{ matrix.target }}.tar.gz" \
-C target/release openshell-driver-vm
-C artifacts/bin openshell-driver-vm
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
+49 -7
View File
@@ -376,7 +376,7 @@ jobs:
retention-days: 5
# ---------------------------------------------------------------------------
# Build standalone gateway binaries (Linux GNU — native on each arch)
# Build standalone gateway binaries (Linux GNU — glibc 2.31 floor)
# ---------------------------------------------------------------------------
build-gateway-binary-linux:
name: Build Gateway Binary (Linux ${{ matrix.arch }})
@@ -387,9 +387,11 @@ jobs:
- arch: amd64
runner: linux-amd64-cpu8
target: x86_64-unknown-linux-gnu
zig_target: x86_64-unknown-linux-gnu.2.31
- arch: arm64
runner: linux-arm64-cpu8
target: aarch64-unknown-linux-gnu
zig_target: aarch64-unknown-linux-gnu.2.31
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
container:
@@ -427,20 +429,26 @@ jobs:
set -euo pipefail
sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml
- name: Build ${{ matrix.target }}
- name: Build ${{ matrix.zig_target }}
env:
OPENSHELL_IMAGE_TAG: ${{ github.sha }}
run: |
set -euo pipefail
mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-server
mise x -- rustup target add ${{ matrix.target }}
mise x -- cargo zigbuild --release --target ${{ matrix.zig_target }} -p openshell-server --bin openshell-gateway
mkdir -p artifacts/bin
install -m 0755 target/${{ matrix.target }}/release/openshell-gateway artifacts/bin/openshell-gateway
- name: Verify packaged binary
run: |
set -euo pipefail
OUTPUT="$(target/${{ matrix.target }}/release/openshell-gateway --version)"
OUTPUT="$(artifacts/bin/openshell-gateway --version)"
echo "$OUTPUT"
grep -q '^openshell-gateway ' <<<"$OUTPUT"
- name: Verify glibc symbol floor
run: tasks/scripts/verify-glibc-symbols.sh 2.31 artifacts/bin/openshell-gateway
- name: sccache stats
if: always()
run: mise x -- sccache --show-stats
@@ -450,7 +458,7 @@ jobs:
set -euo pipefail
mkdir -p artifacts
tar -czf artifacts/openshell-gateway-${{ matrix.target }}.tar.gz \
-C target/${{ matrix.target }}/release openshell-gateway
-C artifacts/bin openshell-gateway
ls -lh artifacts/
- name: Upload artifact
@@ -641,7 +649,7 @@ jobs:
build-rpm:
name: Build RPM Packages
needs: [compute-versions]
needs: [compute-versions, build-cli-linux, build-gateway-binary-linux]
uses: ./.github/workflows/rpm-package.yml
with:
checkout-ref: ${{ github.sha }}
@@ -650,12 +658,46 @@ jobs:
cargo-version: ${{ needs.compute-versions.outputs.cargo_version }}
secrets: inherit
smoke-linux-dev-artifacts:
name: Smoke Linux Dev Artifacts (${{ matrix.name }})
needs: [build-gateway-binary-linux, build-driver-vm-linux, build-deb]
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- name: ubuntu-22.04-deb-amd64
runner: linux-amd64-cpu8
image: ubuntu:22.04
artifact_arch: amd64
- name: ubuntu-22.04-deb-arm64
runner: linux-arm64-cpu8
image: ubuntu:22.04
artifact_arch: arm64
runs-on: ${{ matrix.runner }}
container:
image: ${{ matrix.image }}
steps:
- name: Download Debian package artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: deb-linux-${{ matrix.artifact_arch }}
path: package-input/
- name: Smoke Debian package on Ubuntu 22.04
run: |
set -euo pipefail
apt-get update
apt-get install -y --no-install-recommends ./package-input/*.deb
openshell-gateway --version
/usr/libexec/openshell/openshell-driver-vm --version
# ---------------------------------------------------------------------------
# Create / update the dev GitHub Release with CLI, gateway, driver, and wheels
# ---------------------------------------------------------------------------
release-dev:
name: Release Dev
needs: [compute-versions, build-cli-linux, build-cli-macos, build-gateway-binary-linux, build-gateway-binary-macos, build-supervisor-binary-linux, build-python-wheels-linux, build-python-wheel-macos, build-driver-vm-linux, build-driver-vm-macos, build-deb, build-rpm]
needs: [compute-versions, build-cli-linux, build-cli-macos, build-gateway-binary-linux, build-gateway-binary-macos, build-supervisor-binary-linux, build-python-wheels-linux, build-python-wheel-macos, build-driver-vm-linux, build-driver-vm-macos, build-deb, build-rpm, smoke-linux-dev-artifacts]
runs-on: linux-amd64-cpu8
timeout-minutes: 10
permissions:
+123 -7
View File
@@ -409,7 +409,7 @@ jobs:
retention-days: 5
# ---------------------------------------------------------------------------
# Build standalone gateway binaries (Linux GNU — native on each arch)
# Build standalone gateway binaries (Linux GNU — glibc 2.31 floor)
# ---------------------------------------------------------------------------
build-gateway-binary-linux:
name: Build Gateway Binary (Linux ${{ matrix.arch }})
@@ -420,9 +420,11 @@ jobs:
- arch: amd64
runner: linux-amd64-cpu8
target: x86_64-unknown-linux-gnu
zig_target: x86_64-unknown-linux-gnu.2.31
- arch: arm64
runner: linux-arm64-cpu8
target: aarch64-unknown-linux-gnu
zig_target: aarch64-unknown-linux-gnu.2.31
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
container:
@@ -461,20 +463,26 @@ jobs:
set -euo pipefail
sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ needs.compute-versions.outputs.cargo_version }}"'"/}' Cargo.toml
- name: Build ${{ matrix.target }}
- name: Build ${{ matrix.zig_target }}
env:
OPENSHELL_IMAGE_TAG: ${{ needs.compute-versions.outputs.source_sha }}
run: |
set -euo pipefail
mise x -- cargo build --release --target ${{ matrix.target }} -p openshell-server
mise x -- rustup target add ${{ matrix.target }}
mise x -- cargo zigbuild --release --target ${{ matrix.zig_target }} -p openshell-server --bin openshell-gateway
mkdir -p artifacts/bin
install -m 0755 target/${{ matrix.target }}/release/openshell-gateway artifacts/bin/openshell-gateway
- name: Verify packaged binary
run: |
set -euo pipefail
OUTPUT="$(target/${{ matrix.target }}/release/openshell-gateway --version)"
OUTPUT="$(artifacts/bin/openshell-gateway --version)"
echo "$OUTPUT"
grep -q '^openshell-gateway ' <<<"$OUTPUT"
- name: Verify glibc symbol floor
run: tasks/scripts/verify-glibc-symbols.sh 2.31 artifacts/bin/openshell-gateway
- name: sccache stats
if: always()
run: mise x -- sccache --show-stats
@@ -484,7 +492,7 @@ jobs:
set -euo pipefail
mkdir -p artifacts
tar -czf artifacts/openshell-gateway-${{ matrix.target }}.tar.gz \
-C target/${{ matrix.target }}/release openshell-gateway
-C artifacts/bin openshell-gateway
ls -lh artifacts/
- name: Upload artifact
@@ -677,7 +685,7 @@ jobs:
build-rpm:
name: Build RPM Packages
needs: [compute-versions]
needs: [compute-versions, build-cli-linux, build-gateway-binary-linux]
uses: ./.github/workflows/rpm-package.yml
with:
checkout-ref: ${{ inputs.tag || github.ref }}
@@ -686,12 +694,120 @@ jobs:
cargo-version: ${{ needs.compute-versions.outputs.cargo_version }}
secrets: inherit
smoke-linux-release-artifacts:
name: Smoke Linux Release Artifacts (${{ matrix.name }})
needs: [build-gateway-binary-linux, build-driver-vm-linux, build-deb, build-rpm]
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- name: ubuntu-20.04-binaries
runner: linux-amd64-cpu8
image: ubuntu:20.04
kind: binary
artifact_arch: amd64
rpm_arch: x86_64
target: x86_64-unknown-linux-gnu
- name: ubuntu-20.04-binaries-arm64
runner: linux-arm64-cpu8
image: ubuntu:20.04
kind: binary
artifact_arch: arm64
rpm_arch: aarch64
target: aarch64-unknown-linux-gnu
- name: ubuntu-22.04-deb
runner: linux-amd64-cpu8
image: ubuntu:22.04
kind: deb
artifact_arch: amd64
rpm_arch: x86_64
target: x86_64-unknown-linux-gnu
- name: ubuntu-22.04-deb-arm64
runner: linux-arm64-cpu8
image: ubuntu:22.04
kind: deb
artifact_arch: arm64
rpm_arch: aarch64
target: aarch64-unknown-linux-gnu
- name: rhel9-rpm
runner: linux-amd64-cpu8
image: rockylinux:9
kind: rpm
artifact_arch: amd64
rpm_arch: x86_64
target: x86_64-unknown-linux-gnu
- name: rhel9-rpm-aarch64
runner: linux-arm64-cpu8
image: rockylinux:9
kind: rpm
artifact_arch: arm64
rpm_arch: aarch64
target: aarch64-unknown-linux-gnu
runs-on: ${{ matrix.runner }}
container:
image: ${{ matrix.image }}
steps:
- name: Download gateway binary artifact
if: matrix.kind == 'binary'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: gateway-binary-linux-${{ matrix.artifact_arch }}
path: smoke-input/
- name: Download VM driver binary artifact
if: matrix.kind == 'binary'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: driver-vm-linux-${{ matrix.artifact_arch }}
path: smoke-input/
- name: Smoke binary artifacts
if: matrix.kind == 'binary'
run: |
set -euo pipefail
mkdir -p smoke-bin
tar -xzf smoke-input/openshell-gateway-${{ matrix.target }}.tar.gz -C smoke-bin
tar -xzf smoke-input/openshell-driver-vm-${{ matrix.target }}.tar.gz -C smoke-bin
smoke-bin/openshell-gateway --version
smoke-bin/openshell-driver-vm --version
- name: Download Debian package artifact
if: matrix.kind == 'deb'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: deb-linux-${{ matrix.artifact_arch }}
path: package-input/
- name: Smoke Debian package
if: matrix.kind == 'deb'
run: |
set -euo pipefail
apt-get update
apt-get install -y --no-install-recommends ./package-input/*.deb
openshell-gateway --version
/usr/libexec/openshell/openshell-driver-vm --version
- name: Download RPM package artifacts
if: matrix.kind == 'rpm'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: rpm-linux-${{ matrix.rpm_arch }}
path: package-input/
- name: Smoke RPM packages
if: matrix.kind == 'rpm'
run: |
set -euo pipefail
dnf install -y ./package-input/*.rpm
openshell-gateway --version
# ---------------------------------------------------------------------------
# Create a tagged GitHub Release with CLI, gateway, driver, and wheels
# ---------------------------------------------------------------------------
release:
name: Release
needs: [compute-versions, build-cli-linux, build-cli-macos, build-gateway-binary-linux, build-gateway-binary-macos, build-supervisor-binary-linux, build-python-wheels-linux, build-python-wheel-macos, tag-ghcr-release, build-driver-vm-linux, build-driver-vm-macos, build-deb, build-rpm]
needs: [compute-versions, build-cli-linux, build-cli-macos, build-gateway-binary-linux, build-gateway-binary-macos, build-supervisor-binary-linux, build-python-wheels-linux, build-python-wheel-macos, tag-ghcr-release, build-driver-vm-linux, build-driver-vm-macos, build-deb, build-rpm, smoke-linux-release-artifacts]
runs-on: linux-amd64-cpu8
timeout-minutes: 10
permissions:
+27
View File
@@ -37,9 +37,15 @@ jobs:
matrix:
include:
- arch: x86_64
artifact_arch: amd64
runner: linux-amd64-cpu8
cli_target: x86_64-unknown-linux-musl
gnu_target: x86_64-unknown-linux-gnu
- arch: aarch64
artifact_arch: arm64
runner: linux-arm64-cpu8
cli_target: aarch64-unknown-linux-musl
gnu_target: aarch64-unknown-linux-gnu
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
container:
@@ -59,6 +65,26 @@ jobs:
ref: ${{ inputs.checkout-ref }}
fetch-depth: 0
- name: Download CLI artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: cli-linux-${{ matrix.artifact_arch }}
path: package-input/
- name: Download gateway artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: gateway-binary-linux-${{ matrix.artifact_arch }}
path: package-input/
- name: Extract package inputs
run: |
set -euo pipefail
mkdir -p package-binaries
tar -xzf "package-input/openshell-${{ matrix.cli_target }}.tar.gz" -C package-binaries
tar -xzf "package-input/openshell-gateway-${{ matrix.gnu_target }}.tar.gz" -C package-binaries
ls -lah package-binaries
- name: Mark workspace safe for git
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
@@ -70,6 +96,7 @@ jobs:
OPENSHELL_RPM_VERSION: ${{ inputs['rpm-version'] }}
OPENSHELL_RPM_RELEASE: ${{ inputs['rpm-release'] }}
OPENSHELL_CARGO_VERSION: ${{ inputs['cargo-version'] }}
OPENSHELL_PREBUILT_BINARIES_DIR: ${{ github.workspace }}/package-binaries
run: packit build locally
- name: Collect RPM artifacts
+26 -9
View File
@@ -6,7 +6,9 @@ name: Rust Image Binary Build (openshell-gateway / openshell-sandbox)
# Build Rust binaries per Linux architecture before the Docker image build
# consumes them as prebuilt artifacts. Gateway images use GNU-linked binaries
# for the NVIDIA distroless C/C++ runtime; supervisor images use musl/static
# binaries so the final image can remain scratch.
# binaries so the final image can remain scratch. Gateway GNU binaries are
# built with an explicit glibc 2.31 floor so image, package, and tarball
# artifacts share the same host portability contract.
on:
workflow_call:
@@ -95,6 +97,11 @@ jobs:
- name: Fetch tags
run: git fetch --tags --force
- name: Configure GHA sccache backend
# Exposes ACTIONS_CACHE_URL / ACTIONS_RUNTIME_TOKEN before `mise install`
# compiles cargo-installed tools through RUSTC_WRAPPER=sccache.
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
- name: Install tools
run: mise install --locked
@@ -127,6 +134,7 @@ jobs:
zig_target=x86_64-linux-musl
else
target=x86_64-unknown-linux-gnu
zig_target=x86_64-unknown-linux-gnu.2.31
fi
;;
arm64)
@@ -135,6 +143,7 @@ jobs:
zig_target=aarch64-linux-musl
else
target=aarch64-unknown-linux-gnu
zig_target=aarch64-unknown-linux-gnu.2.31
fi
;;
*)
@@ -150,11 +159,6 @@ jobs:
echo "zig_target=$zig_target"
} >> "$GITHUB_OUTPUT"
- name: Configure GHA sccache backend
# Exposes ACTIONS_CACHE_URL / ACTIONS_RUNTIME_TOKEN so sccache (wrapped
# around rustc via mise's RUSTC_WRAPPER) can initialize the GHA cache.
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
- name: Cache Rust target and registry
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2
with:
@@ -202,7 +206,7 @@ jobs:
echo "CARGO_TARGET_${TARGET_ENV_UPPER}_LINKER=/tmp/zig-musl/cc" >> "$GITHUB_ENV"
echo "CARGO_TARGET_${TARGET_ENV_UPPER}_RUSTFLAGS=-Clink-self-contained=no" >> "$GITHUB_ENV"
- name: Build ${{ steps.target.outputs.binary }} (${{ steps.target.outputs.target }})
- name: Build ${{ steps.target.outputs.binary }} (${{ steps.target.outputs.zig_target || steps.target.outputs.target }})
env:
# Preserve the release-codegen setting used by the old Dockerfile
# Rust build path so image artifacts keep the same release profile.
@@ -211,9 +215,15 @@ jobs:
run: |
set -euo pipefail
mise x -- rustup target add "${{ steps.target.outputs.target }}"
cargo_cmd=(cargo build)
build_target="${{ steps.target.outputs.target }}"
if [[ "${{ inputs.component }}" == "gateway" ]]; then
cargo_cmd=(cargo zigbuild)
build_target="${{ steps.target.outputs.zig_target }}"
fi
args=(
--release
--target "${{ steps.target.outputs.target }}"
--target "$build_target"
-p "${{ steps.target.outputs.crate }}"
--bin "${{ steps.target.outputs.binary }}"
)
@@ -223,7 +233,7 @@ jobs:
if [[ -n "${{ steps.version.outputs.cargo_version }}" ]]; then
export GIT_DIR=/nonexistent
fi
mise x -- cargo build "${args[@]}"
mise x -- "${cargo_cmd[@]}" "${args[@]}"
- name: Verify packaged binary
run: |
@@ -236,6 +246,13 @@ jobs:
ldd --version
ldd "$BIN" || true
- name: Verify glibc symbol floor
if: inputs.component == 'gateway'
run: |
set -euo pipefail
BIN="target/${{ steps.target.outputs.target }}/release/${{ steps.target.outputs.binary }}"
tasks/scripts/verify-glibc-symbols.sh 2.31 "$BIN"
- name: Stage binary for prebuilt layout
run: |
set -euo pipefail
+17 -4
View File
@@ -20,6 +20,15 @@ OpenShell builds these main artifacts:
Sandbox community images are built outside this repository.
## Linux Runtime Environments
OpenShell uses different Linux libc environments for different host artifacts.
The standalone `openshell` CLI is built as a static musl binary so it can run on
a wide range of Linux distributions without depending on the host's glibc. Host
runtime binaries that use the GNU/Linux runtime environment, including
`openshell-gateway` and `openshell-driver-vm`, are GNU-linked and built with a
glibc 2.31 floor.
## Container Builds
The Docker image pipeline is a two-step flow: build the Rust binary natively
@@ -29,9 +38,11 @@ and the supervisor image from `deploy/docker/Dockerfile.supervisor`. Neither
Dockerfile compiles Rust — both copy a staged binary out of
`deploy/docker/.build/prebuilt-binaries/<arch>/` into the final image.
Binary staging is driven by `tasks/scripts/stage-prebuilt-binaries.sh`, which
runs `cargo build` natively on a matching host or `cargo zigbuild` when
cross-compiling. Local Docker image tasks infer the target architecture from
Binary staging is driven by `tasks/scripts/stage-prebuilt-binaries.sh`. Gateway
binaries use `cargo zigbuild` with GNU targets pinned to glibc 2.31, including
native-architecture builds, so the gateway image, standalone tarballs, and Linux
packages share the same host portability floor. Supervisor binaries remain
static musl. Local Docker image tasks infer the target architecture from
`DOCKER_PLATFORM` when set, otherwise from the container engine host metadata
with the kernel architecture as the fallback. CI invokes the same staging step
via the `rust-native-build.yml` workflow (per-architecture, per-component) and
@@ -41,7 +52,9 @@ the staging directory before running Buildx.
Runtime layout:
- **Gateway**: `gcr.io/distroless/cc-debian13:nonroot` base, GNU-linked binary at
`/usr/local/bin/openshell-gateway`, runs as UID/GID `1000:1000`.
`/usr/local/bin/openshell-gateway`, runs as UID/GID `1000:1000`. Linux GNU
gateway and VM driver binaries must not reference `GLIBC_*` symbols newer than
`GLIBC_2.31`; release workflows verify this before publishing artifacts.
- **Supervisor**: `scratch` base, static musl binary at `/openshell-sandbox`.
Static linkage is required because the image is mounted/extracted into
sandbox environments (Docker extraction, Podman image volumes, Kubernetes
+2
View File
@@ -55,6 +55,8 @@ On Fedora and RHEL, the install script uses RPM packages. The RPM installs the `
On Debian and Ubuntu, the install script uses a Debian package. The Debian package installs the `openshell` CLI, the `openshell-gateway` daemon, VM sandbox support, and a systemd user service.
Linux packages require glibc 2.31 or newer. The installer checks libc before downloading packages and exits with an error on older glibc versions, Alpine, musl-based distributions, or unknown libc environments.
The Linux user service listens on `https://127.0.0.1:17670`, starts from built-in defaults, and generates a local mTLS bundle before the gateway starts. Create `~/.config/openshell/gateway.toml` only when you need to override those defaults.
The CLI reads the client bundle from `~/.config/openshell/gateways/openshell/mtls/`.
+5 -1
View File
@@ -10,7 +10,7 @@ This page lists the host platform, compute driver, software, runtime, and kernel
## Supported Platforms
OpenShell publishes multi-architecture gateway images for `linux/amd64` and `linux/arm64`. The CLI and standalone gateway binary are supported on the following host platforms:
OpenShell publishes multi-architecture gateway images for `linux/amd64` and `linux/arm64`. The CLI, package-managed gateway, and standalone gateway binary are supported on the following host platforms:
| Platform | Architecture | Status |
| -------------------------------- | --------------------- | --------- |
@@ -19,6 +19,8 @@ OpenShell publishes multi-architecture gateway images for `linux/amd64` and `lin
| macOS (Docker Desktop) | Apple Silicon (arm64) | Supported |
| Windows (WSL 2 + Docker Desktop) | x86_64 | Experimental |
On Linux, the `openshell` CLI is a static musl binary and does not require glibc at runtime.
## Standalone Gateway Binary
OpenShell publishes standalone `openshell-gateway` release assets for manual download on these platforms:
@@ -31,6 +33,8 @@ OpenShell publishes standalone `openshell-gateway` release assets for manual dow
These artifacts are attached to GitHub releases. Kubernetes deployments should use the Helm chart and the published gateway image.
On Linux, `openshell-gateway` requires glibc 2.31 or newer. Compatible systems include, for example, Ubuntu 20.04+, RHEL 9+, Amazon Linux 2023+, and Fedora 32+.
## Compute Drivers
The gateway can manage sandboxes through several compute drivers.
+103 -1
View File
@@ -19,6 +19,7 @@ LOCAL_GATEWAY_PORT="17670"
HOMEBREW_TAP="nvidia/openshell"
HOMEBREW_FORMULA_NAME="openshell"
BREAKING_RELEASE_VERSION="0.0.37"
LINUX_PACKAGE_GLIBC_MIN_VERSION="2.31"
UPGRADE_NOTICE_ACK="${OPENSHELL_ACK_BREAKING_UPGRADE:-}"
info() {
@@ -118,6 +119,104 @@ semver_at_least() {
[ "$_patch" -ge "$_min_patch" ]
}
version_at_least_major_minor() {
_version="$1"
_minimum="$2"
_major="${_version%%.*}"
_minor="${_version#*.}"
_minor="${_minor%%.*}"
_min_major="${_minimum%%.*}"
_min_minor="${_minimum#*.}"
_min_minor="${_min_minor%%.*}"
case "$_major:$_minor:$_min_major:$_min_minor" in
*[!0-9:]* | *::*)
return 1
;;
esac
[ "$_major" -gt "$_min_major" ] && return 0
[ "$_major" -lt "$_min_major" ] && return 1
[ "$_minor" -ge "$_min_minor" ]
}
getconf_gnu_libc_version() {
if [ "${OPENSHELL_INSTALL_SH_TEST:-0}" = "1" ] && [ "${OPENSHELL_TEST_GETCONF_UNAVAILABLE:-0}" = "1" ]; then
return 127
fi
if [ "${OPENSHELL_INSTALL_SH_TEST:-0}" = "1" ] && [ "${OPENSHELL_TEST_GETCONF_OUTPUT+x}" = "x" ]; then
printf '%s\n' "$OPENSHELL_TEST_GETCONF_OUTPUT"
return 0
fi
getconf GNU_LIBC_VERSION 2>/dev/null
}
ldd_version_output() {
if [ "${OPENSHELL_INSTALL_SH_TEST:-0}" = "1" ] && [ "${OPENSHELL_TEST_LDD_UNAVAILABLE:-0}" = "1" ]; then
return 127
fi
if [ "${OPENSHELL_INSTALL_SH_TEST:-0}" = "1" ] && [ "${OPENSHELL_TEST_LDD_OUTPUT+x}" = "x" ]; then
printf '%s\n' "$OPENSHELL_TEST_LDD_OUTPUT"
return 0
fi
ldd --version 2>&1
}
detect_glibc_version() {
_ldd_output="$(ldd_version_output 2>&1 || true)"
case "$_ldd_output" in
*[Mm][Uu][Ss][Ll]* | *[Aa][Ll][Pp][Ii][Nn][Ee]*)
return 2
;;
esac
_ldd_version="$(printf '%s\n' "$_ldd_output" | awk 'FNR == 1 && match($NF, /^[0-9]+\.[0-9]+/) { print substr($NF, RSTART, RLENGTH); exit }')"
if [ -n "$_ldd_version" ]; then
printf '%s\n' "$_ldd_version"
return 0
fi
_getconf_output="$(getconf_gnu_libc_version 2>/dev/null || true)"
case "$_getconf_output" in
glibc\ [0-9]*.[0-9]*)
printf '%s\n' "${_getconf_output#glibc }"
return 0
;;
*[Mm][Uu][Ss][Ll]* | *[Aa][Ll][Pp][Ii][Nn][Ee]*)
return 2
;;
esac
return 1
}
require_linux_package_glibc() {
_glibc_status=0
_glibc_version="$(detect_glibc_version)" || _glibc_status=$?
case "$_glibc_status" in
0)
;;
2)
error "OpenShell Linux packages require glibc >= ${LINUX_PACKAGE_GLIBC_MIN_VERSION}; detected musl or unsupported libc."
;;
*)
error "OpenShell Linux packages require glibc >= ${LINUX_PACKAGE_GLIBC_MIN_VERSION}; could not detect glibc."
;;
esac
if ! version_at_least_major_minor "$_glibc_version" "$LINUX_PACKAGE_GLIBC_MIN_VERSION"; then
error "OpenShell Linux packages require glibc >= ${LINUX_PACKAGE_GLIBC_MIN_VERSION}; detected glibc ${_glibc_version}.
Please use a newer distribution or container environment."
fi
}
target_uses_breaking_gateway_model() {
case "$RELEASE_TAG" in
dev)
@@ -934,6 +1033,7 @@ main() {
case "$PLATFORM" in
linux)
require_linux_package_glibc
case "$(linux_package_method)" in
deb)
install_linux_deb
@@ -955,4 +1055,6 @@ main() {
esac
}
main "$@"
if [ "${OPENSHELL_INSTALL_SH_TEST:-0}" != "1" ]; then
main "$@"
fi
+1 -1
View File
@@ -35,7 +35,7 @@ k3d = { version = "5.8.3", os = ["macos"] }
"github:anchore/syft" = { version = "1.44.0" }
"github:EmbarkStudios/cargo-about" = { version = "0.8.4", version_prefix = "" }
zig = "0.14.1"
"cargo:cargo-zigbuild" = { version = "0.22.3", os = ["macos"] }
"cargo:cargo-zigbuild" = "0.22.3"
"npm:markdownlint-cli2" = "0.22.0"
[tools."github:mozilla/sccache"]
+18 -4
View File
@@ -103,12 +103,18 @@ sed -i 's/^version = "0.0.0"/version = "%{openshell_cargo_version}"/' Cargo.toml
grep -q 'version = "%{openshell_cargo_version}"' Cargo.toml || (echo "ERROR: Cargo.toml version patch failed" && exit 1)
%build
# Build the CLI and gateway binaries
# Build the CLI and gateway binaries unless the release workflow supplied the
# same prebuilt artifacts used for tarballs and Debian packages.
export CARGO_BUILD_JOBS=%{_smp_build_ncpus}
# Set the default container image tag so compiled-in image refs point at
# real tags in the ghcr.io/nvidia/openshell registry.
export OPENSHELL_IMAGE_TAG=%{image_tag}
cargo build --release --bin openshell --bin openshell-gateway
if [ -n "${OPENSHELL_PREBUILT_BINARIES_DIR:-}" ]; then
test -x "${OPENSHELL_PREBUILT_BINARIES_DIR}/openshell"
test -x "${OPENSHELL_PREBUILT_BINARIES_DIR}/openshell-gateway"
else
cargo build --release --bin openshell --bin openshell-gateway
fi
# Generate vendored crate manifest and license metadata.
# cargo-vendor.txt is consumed by an RPM generator (from cargo-rpm-macros)
@@ -123,10 +129,18 @@ pandoc -s -t man deploy/man/openshell-gateway.8.md -o openshell-gateway.8
%install
# --- CLI binary ---
install -Dpm 0755 target/release/%{name} %{buildroot}%{_bindir}/%{name}
if [ -n "${OPENSHELL_PREBUILT_BINARIES_DIR:-}" ]; then
install -Dpm 0755 "${OPENSHELL_PREBUILT_BINARIES_DIR}/%{name}" %{buildroot}%{_bindir}/%{name}
else
install -Dpm 0755 target/release/%{name} %{buildroot}%{_bindir}/%{name}
fi
# --- Gateway binary ---
install -Dpm 0755 target/release/%{name}-gateway %{buildroot}%{_bindir}/%{name}-gateway
if [ -n "${OPENSHELL_PREBUILT_BINARIES_DIR:-}" ]; then
install -Dpm 0755 "${OPENSHELL_PREBUILT_BINARIES_DIR}/%{name}-gateway" %{buildroot}%{_bindir}/%{name}-gateway
else
install -Dpm 0755 target/release/%{name}-gateway %{buildroot}%{_bindir}/%{name}-gateway
fi
# --- Default gateway TOML config template ---
# Shipped as a read-only reference in %{_datadir}. The systemd unit seeds a
+14 -3
View File
@@ -141,6 +141,7 @@ build_component_for_arch() {
local stage
local features
local cargo_subcommand
local build_target
local current_host_os
local current_host_arch
@@ -152,7 +153,17 @@ build_component_for_arch() {
current_host_arch="$(host_arch)"
cargo_subcommand=(cargo build)
if [[ "$current_host_os" != "Linux" || "$current_host_arch" != "$arch" ]]; then
build_target="$target"
if [[ "$component" == "gateway" ]]; then
if command -v cargo-zigbuild >/dev/null 2>&1 || mise which cargo-zigbuild >/dev/null 2>&1; then
cargo_subcommand=(cargo zigbuild)
build_target="${target}.2.31"
else
echo "Error: cargo-zigbuild + zig are required to build ${binary} with the glibc 2.31 floor." >&2
exit 1
fi
elif [[ "$current_host_os" != "Linux" || "$current_host_arch" != "$arch" ]]; then
if command -v cargo-zigbuild >/dev/null 2>&1 || mise which cargo-zigbuild >/dev/null 2>&1; then
cargo_subcommand=(cargo zigbuild)
else
@@ -163,12 +174,12 @@ build_component_for_arch() {
fi
fi
echo "Building ${binary} for linux/${arch} (${target})..."
echo "Building ${binary} for linux/${arch} (${build_target})..."
mise x -- rustup target add "$target" >/dev/null 2>&1 || true
args=(
--release
--target "$target"
--target "$build_target"
-p "$crate"
--bin "$binary"
)
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
out="${tmpdir}/out"
err="${tmpdir}/err"
export OPENSHELL_INSTALL_SH_TEST=1
# shellcheck source=../../install.sh
. "${ROOT}/install.sh"
assert_glibc_preflight_passes() {
local name=$1
local ldd_output=$2
if ! (export OPENSHELL_TEST_GETCONF_UNAVAILABLE=1 OPENSHELL_TEST_LDD_OUTPUT="$ldd_output"; require_linux_package_glibc) >"$out" 2>"$err"; then
echo "FAIL: ${name}" >&2
cat "$err" >&2 || true
exit 1
fi
}
assert_glibc_preflight_fails() {
local name=$1
local expected=$2
local setup=$3
if ("$setup"; require_linux_package_glibc) >"$out" 2>"$err"; then
echo "FAIL: ${name}: expected failure" >&2
exit 1
fi
if ! grep -Fq "$expected" "$err"; then
echo "FAIL: ${name}: missing expected message" >&2
echo "Expected: ${expected}" >&2
echo "Actual:" >&2
cat "$err" >&2 || true
exit 1
fi
}
setup_glibc_228() {
export OPENSHELL_TEST_GETCONF_UNAVAILABLE=1
export OPENSHELL_TEST_LDD_OUTPUT="ldd (GNU libc) 2.28"
}
setup_missing_glibc() {
export OPENSHELL_TEST_GETCONF_UNAVAILABLE=1
export OPENSHELL_TEST_LDD_UNAVAILABLE=1
}
setup_getconf_musl() {
export OPENSHELL_TEST_LDD_UNAVAILABLE=1
export OPENSHELL_TEST_GETCONF_OUTPUT="musl libc"
}
setup_ldd_musl() {
export OPENSHELL_TEST_GETCONF_UNAVAILABLE=1
export OPENSHELL_TEST_LDD_OUTPUT="musl libc (x86_64)"
}
assert_glibc_preflight_passes "glibc 2.31 passes" "glibc 2.31"
assert_glibc_preflight_passes "glibc 2.35 passes" "ldd (GNU libc) 2.35"
if ! (export OPENSHELL_TEST_LDD_UNAVAILABLE=1 OPENSHELL_TEST_GETCONF_OUTPUT="glibc 2.35"; require_linux_package_glibc) >"$out" 2>"$err"; then
echo "FAIL: getconf glibc fallback passes" >&2
cat "$err" >&2 || true
exit 1
fi
if ! (export OPENSHELL_TEST_LDD_OUTPUT="not ldd" OPENSHELL_TEST_GETCONF_OUTPUT="glibc 2.35"; require_linux_package_glibc) >"$out" 2>"$err"; then
echo "FAIL: unparseable ldd output falls back to getconf" >&2
cat "$err" >&2 || true
exit 1
fi
assert_glibc_preflight_fails \
"glibc 2.28 fails" \
"OpenShell Linux packages require glibc >= 2.31; detected glibc 2.28." \
setup_glibc_228
assert_glibc_preflight_fails \
"missing glibc detection fails" \
"OpenShell Linux packages require glibc >= 2.31; could not detect glibc." \
setup_missing_glibc
assert_glibc_preflight_fails \
"musl detection fails" \
"OpenShell Linux packages require glibc >= 2.31; detected musl or unsupported libc." \
setup_getconf_musl
assert_glibc_preflight_fails \
"ldd musl fallback fails" \
"OpenShell Linux packages require glibc >= 2.31; detected musl or unsupported libc." \
setup_ldd_musl
echo "install.sh libc preflight tests passed"
+98
View File
@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
usage() {
echo "Usage: verify-glibc-symbols.sh <max-glibc-version> <binary> [binary ...]" >&2
}
version_gt() {
local left=$1
local right=$2
local left_major=${left%%.*}
local left_minor=${left#*.}
local right_major=${right%%.*}
local right_minor=${right#*.}
left_minor=${left_minor%%.*}
right_minor=${right_minor%%.*}
[[ $left_major =~ ^[0-9]+$ && $left_minor =~ ^[0-9]+$ ]] || return 1
[[ $right_major =~ ^[0-9]+$ && $right_minor =~ ^[0-9]+$ ]] || return 1
(( left_major > right_major )) && return 0
(( left_major < right_major )) && return 1
(( left_minor > right_minor ))
}
extract_glibc_versions() {
local binary=$1
if command -v readelf >/dev/null 2>&1; then
readelf --version-info "$binary" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' || true
elif command -v objdump >/dev/null 2>&1; then
objdump -T "$binary" 2>/dev/null | grep -oE 'GLIBC_[0-9]+\.[0-9]+' || true
fi
}
if [[ $# -lt 2 ]]; then
usage
exit 2
fi
max_version=$1
shift
failed=0
if ! command -v readelf >/dev/null 2>&1 && ! command -v objdump >/dev/null 2>&1; then
echo "error: readelf or objdump is required to inspect GLIBC symbol versions" >&2
exit 2
fi
for binary in "$@"; do
if [[ ! -f $binary ]]; then
echo "error: binary not found: $binary" >&2
failed=1
continue
fi
echo "==> Inspecting $binary"
if command -v file >/dev/null 2>&1; then
file "$binary" || true
else
echo "file: not available"
fi
if command -v ldd >/dev/null 2>&1; then
ldd "$binary" || true
else
echo "ldd: not available"
fi
highest=
found=0
while IFS= read -r version; do
version=${version#GLIBC_}
found=1
if [[ -z $highest ]] || version_gt "$version" "$highest"; then
highest=$version
fi
if version_gt "$version" "$max_version"; then
echo "error: $binary references GLIBC_${version}, above allowed GLIBC_${max_version}" >&2
failed=1
fi
done < <(extract_glibc_versions "$binary")
if [[ $found -eq 0 ]]; then
echo "highest GLIBC symbol: none"
continue
fi
echo "highest GLIBC symbol: GLIBC_${highest}"
done
exit "$failed"
+6 -1
View File
@@ -5,7 +5,12 @@
[test]
description = "Run all tests (Rust + Python)"
depends = ["test:rust", "test:python"]
depends = ["test:rust", "test:python", "test:install-sh"]
["test:install-sh"]
description = "Run focused install.sh shell tests"
run = "tasks/scripts/test-install-sh.sh"
hide = true
[e2e]
description = "Run all end-to-end tests (Rust + Python)"