Files
OpenShell/.github/workflows/shadow-rust-native-build.yml
2026-04-30 13:22:47 -07:00

256 lines
8.1 KiB
YAML

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
name: Rust Native Build (openshell-gateway / openshell-sandbox)
# OS-128 Phase 4: build Rust binaries natively per Linux architecture before
# the Docker image build consumes them as prebuilt artifacts.
on:
workflow_call:
inputs:
component:
description: "Binary component to build (gateway or sandbox)"
required: true
type: string
arch:
description: "Linux architecture to build (amd64 or arm64)"
required: true
type: string
cargo-version:
description: "Pre-computed cargo version (skips internal git-based computation)"
required: false
type: string
default: ""
features:
description: "Cargo features to enable"
required: false
type: string
default: "openshell-core/dev-settings"
retention-days:
description: "Artifact retention period"
required: false
type: number
default: 5
artifact-name:
description: "Artifact name override"
required: false
type: string
default: ""
workflow_dispatch:
inputs:
component:
description: "Binary component to build"
required: true
type: choice
default: gateway
options:
- gateway
- sandbox
arch:
description: "Linux architecture to build"
required: true
type: choice
default: amd64
options:
- amd64
- arm64
cargo-version:
description: "Cargo version override"
required: false
type: string
default: ""
features:
description: "Cargo features to enable"
required: false
type: string
default: "openshell-core/dev-settings"
retention-days:
description: "Artifact retention period"
required: false
type: number
default: 5
artifact-name:
description: "Artifact name override"
required: false
type: string
default: ""
permissions:
contents: read
packages: read
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Route sccache (already RUSTC_WRAPPER in mise.toml) to the GHA cache
# backend instead of the EKS memcached used by ARC.
SCCACHE_GHA_ENABLED: "true"
defaults:
run:
shell: bash
jobs:
rust-native-build:
name: ${{ inputs.component }} (${{ inputs.arch }})
runs-on: ${{ inputs.arch == 'arm64' && 'linux-arm64-cpu8' || 'linux-amd64-cpu8' }}
timeout-minutes: 60
env:
COMPONENT: ${{ inputs.component }}
ARCH: ${{ inputs.arch }}
FEATURES: ${{ inputs.features }}
# Partition the GHA sccache cache per (component, arch). Without this,
# concurrent jobs collide on the same cache key and later-starting
# writers hit 409 Conflict (PR #961 fix for shadow-shared-cpu-spike).
SCCACHE_GHA_VERSION: ${{ inputs.component }}-${{ inputs.arch }}
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
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 --locked
- name: Resolve build target
id: target
run: |
set -euo pipefail
case "$COMPONENT" in
gateway)
crate=openshell-server
binary=openshell-gateway
;;
sandbox)
crate=openshell-sandbox
binary=openshell-sandbox
;;
*)
echo "unsupported component: $COMPONENT" >&2
exit 1
;;
esac
case "$ARCH" in
amd64)
target=x86_64-unknown-linux-gnu
;;
arm64)
target=aarch64-unknown-linux-gnu
;;
*)
echo "unsupported arch: $ARCH" >&2
exit 1
;;
esac
{
echo "crate=$crate"
echo "binary=$binary"
echo "target=$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@7d986dd989559c6ecdb630a3fd2557667be217ad # v0.0.9
- name: Cache Rust target and registry
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
with:
shared-key: rust-native-${{ inputs.component }}-${{ inputs.arch }}
cache-directories: .cache/sccache
cache-targets: "true"
- name: Compute cargo version
id: version
run: |
set -euo pipefail
if [[ -n "${{ inputs['cargo-version'] }}" ]]; then
echo "cargo_version=${{ inputs['cargo-version'] }}" >> "$GITHUB_OUTPUT"
else
echo "cargo_version=$(uv run python tasks/scripts/release.py get-version --cargo)" >> "$GITHUB_OUTPUT"
fi
- name: Patch workspace version
if: steps.version.outputs.cargo_version != ''
run: |
set -euo pipefail
sed -i -E '/^\[workspace\.package\]/,/^\[/{s/^version[[:space:]]*=[[:space:]]*".*"/version = "'"${{ steps.version.outputs.cargo_version }}"'"/}' Cargo.toml
- name: Build ${{ steps.target.outputs.binary }} (${{ 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.
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "1"
run: |
set -euo pipefail
args=(
--release
--target "${{ steps.target.outputs.target }}"
-p "${{ steps.target.outputs.crate }}"
--bin "${{ steps.target.outputs.binary }}"
)
if [[ -n "$FEATURES" ]]; then
args+=(--features "$FEATURES")
fi
if [[ -n "${{ steps.version.outputs.cargo_version }}" ]]; then
export GIT_DIR=/nonexistent
fi
mise x -- cargo build "${args[@]}"
- name: Verify packaged binary
run: |
set -euo pipefail
BIN="target/${{ steps.target.outputs.target }}/release/${{ steps.target.outputs.binary }}"
OUTPUT="$("$BIN" --version)"
echo "$OUTPUT"
grep -q "^${{ steps.target.outputs.binary }} " <<<"$OUTPUT"
# Record glibc linkage so drift from the Ubuntu noble runtime base
# image is visible in logs.
ldd --version
ldd "$BIN" || true
- name: Stage binary for prebuilt layout
run: |
set -euo pipefail
STAGE="prebuilt-binaries/$ARCH"
mkdir -p "$STAGE"
install -m 0755 \
"target/${{ steps.target.outputs.target }}/release/${{ steps.target.outputs.binary }}" \
"$STAGE/${{ steps.target.outputs.binary }}"
ls -lh "$STAGE/"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs['artifact-name'] != '' && inputs['artifact-name'] || format('rust-binary-{0}-linux-{1}', inputs.component, inputs.arch) }}
path: prebuilt-binaries/${{ inputs.arch }}/${{ steps.target.outputs.binary }}
retention-days: ${{ inputs['retention-days'] }}
if-no-files-found: error
- name: sccache stats
if: always()
run: |
set +e
stats_bin="${SCCACHE_PATH:-sccache}"
"$stats_bin" --show-stats
status=$?
if [[ $status -ne 0 ]]; then
echo "::warning::sccache stats unavailable (exit $status)"
fi
exit 0