Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions .github/workflows/shadow-rust-native-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

name: Shadow — Rust Native Build (openshell-gateway / openshell-sandbox)

# OS-49 Phase 4 / PR 4a — non-blocking shadow that builds openshell-gateway
# and openshell-sandbox natively per-arch on the nv-gha-runners shared CPU
# pool (`linux-{amd64,arm64}-cpu8`) with a GHA-backed sccache, and uploads
# the resulting binaries as artifacts. Reuses the pattern from PR #853's
# release-dev.yml "Build standalone {gateway,supervisor} binaries" jobs.
#
# The artifacts match the layout PR 4c expects when consuming `BINARY_SOURCE=
# prebuilt` (wired up in #945): one binary per (component, arch), staged to
# `deploy/docker/.build/prebuilt-binaries/<arch>/openshell-{gateway,sandbox}`.
#
# Dispatch 4-5 times after merge to collect cold + warm numbers and compare
# against the Rust portion of docker-build.yml's 17.5 m ARC baseline. Success
# criteria, gotchas, and dependency graph live on the OS-128 Linear issue.

on:
push:
branches: [main]
workflow_dispatch:

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"

jobs:
rust-native-build:
name: ${{ matrix.component }} (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
component: [gateway, sandbox]
arch: [amd64, arm64]
include:
- component: gateway
crate: openshell-server
binary: openshell-gateway
- component: sandbox
crate: openshell-sandbox
binary: openshell-sandbox
- arch: amd64
runner: linux-amd64-cpu8
target: x86_64-unknown-linux-gnu
- arch: arm64
runner: linux-arm64-cpu8
target: aarch64-unknown-linux-gnu
runs-on: ${{ matrix.runner }}
env:
# Partition the GHA sccache cache per (component, arch). Without this,
# concurrent matrix 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: ${{ matrix.component }}-${{ matrix.arch }}
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
timeout-minutes: 60
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: 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: shadow-rust-native-${{ matrix.component }}-${{ matrix.arch }}
cache-directories: .cache/sccache
cache-targets: "true"

- name: Compute cargo version
id: version
run: |
set -euo pipefail
echo "cargo_version=$(uv run python tasks/scripts/release.py get-version --cargo)" >> "$GITHUB_OUTPUT"

- 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 ${{ matrix.binary }} (${{ matrix.target }})
# Matches docker-build.yml's default EXTRA_CARGO_FEATURES so the
# binary content is byte-comparable to what Dockerfile.images produces
# today (precondition for PR 4c's drop-in swap).
run: |
set -euo pipefail
mise x -- cargo build \
--release \
--target ${{ matrix.target }} \
-p ${{ matrix.crate }} \
--bin ${{ matrix.binary }} \
--features openshell-core/dev-settings

- name: Verify packaged binary
run: |
set -euo pipefail
BIN="target/${{ matrix.target }}/release/${{ matrix.binary }}"
OUTPUT="$("$BIN" --version)"
echo "$OUTPUT"
grep -q "^${{ matrix.binary }} " <<<"$OUTPUT"
# Record glibc linkage so drift from the Ubuntu noble runtime base
# image is visible in logs (not asserted — the runtime check lands
# when PR 4c builds images on top of these artifacts).
ldd --version | head -1
ldd "$BIN" | head -20 || true

- name: sccache stats
if: always()
run: mise x -- sccache --show-stats

- name: Stage binary for prebuilt layout
# Shape mirrors `deploy/docker/.build/prebuilt-binaries/<arch>/<bin>`
# so PR 4c can download the artifact directly into the build context.
run: |
set -euo pipefail
STAGE="prebuilt-binaries/${{ matrix.arch }}"
mkdir -p "$STAGE"
install -m 0755 "target/${{ matrix.target }}/release/${{ matrix.binary }}" "$STAGE/${{ matrix.binary }}"
ls -lh "$STAGE/"

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: rust-binary-${{ matrix.component }}-linux-${{ matrix.arch }}
path: prebuilt-binaries/${{ matrix.arch }}/${{ matrix.binary }}
retention-days: 5
if-no-files-found: error
Loading