mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-16 05:20:22 +08:00
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from 2.9.1 to 2.9.2. - [Release notes](https://github.com/swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](https://github.com/swatinem/rust-cache/compare/c19371144df3bb44fab255c43d04cbc2ab54d1c4...6323deb102c322ba6fcbdcafc7e3dddab59af2b6) --- updated-dependencies: - dependency-name: Swatinem/rust-cache dependency-version: 2.9.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
366 lines
14 KiB
YAML
366 lines
14 KiB
YAML
name: E2E Test
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
image-tag:
|
|
description: "Image tag to test (typically the commit SHA)"
|
|
required: true
|
|
type: string
|
|
runner:
|
|
description: "GitHub Actions runner label"
|
|
required: false
|
|
type: string
|
|
default: "linux-amd64-cpu8"
|
|
checkout-ref:
|
|
description: "Git ref to check out for test inputs (defaults to the workflow SHA)"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
cli-artifact-prefix:
|
|
description: "Optional prebuilt CLI artifact prefix (artifact suffix is linux-<arch>)"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
gateway-artifact-prefix:
|
|
description: "Optional prebuilt gateway artifact prefix (artifact suffix is linux-<arch>)"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
vm-driver-artifact-name:
|
|
description: "Optional prebuilt VM driver artifact name"
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
packages: read
|
|
|
|
jobs:
|
|
e2e:
|
|
name: "E2E (${{ matrix.suite }})"
|
|
runs-on: ${{ inputs.runner }}
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- suite: python
|
|
cmd: "mise run --no-deps --skip-deps e2e:python"
|
|
apt_packages: ""
|
|
- suite: oidc-python
|
|
cmd: "mise run --no-deps --skip-deps e2e:oidc-python:docker"
|
|
apt_packages: ""
|
|
- suite: oidc-pkce-docker
|
|
cmd: "mise run --no-deps --skip-deps e2e:oidc-pkce:docker"
|
|
apt_packages: "openssh-client"
|
|
- suite: rust-docker
|
|
cmd: "mise run --no-deps --skip-deps e2e:rust"
|
|
apt_packages: "openssh-client"
|
|
- suite: mcp
|
|
cmd: "mise run --no-deps --skip-deps e2e:mcp"
|
|
apt_packages: ""
|
|
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
|
|
- /home/runner/_work:/home/runner/_work
|
|
env:
|
|
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
IMAGE_TAG: ${{ inputs.image-tag }}
|
|
OPENSHELL_REGISTRY: ghcr.io/nvidia/openshell
|
|
OPENSHELL_REGISTRY_HOST: ghcr.io
|
|
OPENSHELL_REGISTRY_NAMESPACE: nvidia/openshell
|
|
OPENSHELL_REGISTRY_USERNAME: ${{ github.actor }}
|
|
OPENSHELL_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs['checkout-ref'] || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Use prebuilt OpenShell CLI
|
|
if: inputs.cli-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-cli
|
|
with:
|
|
artifact-prefix: ${{ inputs.cli-artifact-prefix }}
|
|
|
|
- name: Use prebuilt OpenShell gateway
|
|
if: inputs.gateway-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-gateway
|
|
with:
|
|
artifact-prefix: ${{ inputs.gateway-artifact-prefix }}
|
|
|
|
- name: Check out MCP conformance tests
|
|
if: matrix.suite == 'mcp'
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
repository: modelcontextprotocol/conformance
|
|
# Pin after v0.1.16 to include the tools_call client scenario fix.
|
|
ref: b9041ea41b0188581803459dbae71bc7e02fd995
|
|
path: .cache/mcp-conformance
|
|
persist-credentials: false
|
|
|
|
- name: Install OS test dependencies
|
|
if: matrix.apt_packages != ''
|
|
env:
|
|
APT_PACKAGES: ${{ matrix.apt_packages }}
|
|
run: apt-get update && apt-get install -y ${APT_PACKAGES} && rm -rf /var/lib/apt/lists/*
|
|
|
|
- name: Log in to GHCR with Docker
|
|
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
|
|
|
|
- name: Install Python dependencies and generate protobuf stubs
|
|
if: matrix.suite == 'python' || matrix.suite == 'oidc-python'
|
|
run: uv sync --frozen && mise run --no-deps python:proto
|
|
|
|
- name: Run tests
|
|
env:
|
|
OPENSHELL_SUPERVISOR_IMAGE: ${{ format('ghcr.io/nvidia/openshell/supervisor:{0}', inputs.image-tag) }}
|
|
OPENSHELL_MCP_CONFORMANCE_CLIENT_IMAGE: ${{ format('openshell-mcp-conformance-client:{0}', inputs.image-tag) }}
|
|
run: ${{ matrix.cmd }}
|
|
|
|
e2e-podman-rootless:
|
|
name: E2E (rust-podman-rootless, ${{ matrix.runner }})
|
|
# Run directly on the Ubuntu host so the test observes the host's AppArmor
|
|
# and unprivileged-user-namespace policy. A privileged job container masks
|
|
# the restrictions that production rootless Podman installations enforce.
|
|
# Ubuntu 26.04 provides the supported Podman 5.x and pasta combination.
|
|
# Re-add older/slirp4netns environments when direct callbacks through a
|
|
# rootless-network namespace relay are supported.
|
|
runs-on: ${{ matrix.runner }}
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Keep package versions explicit so hosted-runner tool overrides
|
|
# cannot silently change the supported test environment.
|
|
- runner: ubuntu-26.04
|
|
podman_major: "5"
|
|
podman_package_version: "5.7.0+ds2-3build1"
|
|
conmon_package_version: "2.1.13+ds1-2"
|
|
env:
|
|
IMAGE_TAG: ${{ inputs.image-tag }}
|
|
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
OPENSHELL_REGISTRY: ghcr.io/nvidia/openshell
|
|
OPENSHELL_REGISTRY_HOST: ghcr.io
|
|
OPENSHELL_REGISTRY_NAMESPACE: nvidia/openshell
|
|
OPENSHELL_REGISTRY_USERNAME: ${{ github.actor }}
|
|
OPENSHELL_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
|
OPENSHELL_SUPERVISOR_IMAGE: ${{ format('ghcr.io/nvidia/openshell/supervisor:{0}', inputs.image-tag) }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs['checkout-ref'] || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Use prebuilt OpenShell CLI
|
|
if: inputs.cli-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-cli
|
|
with:
|
|
artifact-prefix: ${{ inputs.cli-artifact-prefix }}
|
|
|
|
- name: Use prebuilt OpenShell gateway
|
|
if: inputs.gateway-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-gateway
|
|
with:
|
|
artifact-prefix: ${{ inputs.gateway-artifact-prefix }}
|
|
|
|
- name: Install mise
|
|
run: |
|
|
curl https://mise.run | MISE_VERSION=v2026.4.25 sh
|
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
echo "$HOME/.local/share/mise/shims" >> "$GITHUB_PATH"
|
|
|
|
- name: Install tools
|
|
run: mise install --locked
|
|
|
|
- name: Install Podman and build dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
clang \
|
|
fuse-overlayfs \
|
|
libssl-dev \
|
|
libz3-dev \
|
|
openssh-client \
|
|
passt \
|
|
pkg-config \
|
|
"conmon=${{ matrix.conmon_package_version }}" \
|
|
"podman=${{ matrix.podman_package_version }}" \
|
|
uidmap
|
|
# Hosted runners can place newer Podman and conmon binaries under
|
|
# /usr/local ahead of Ubuntu's packages. Select the distro CLI and
|
|
# use Podman's supported final config override for its conmon path.
|
|
podman_config="${RUNNER_TEMP}/openshell-containers.conf"
|
|
printf '%s\n' \
|
|
'[engine]' \
|
|
'conmon_path = ["/usr/bin/conmon"]' \
|
|
> "${podman_config}"
|
|
echo "/usr/bin" >> "${GITHUB_PATH}"
|
|
echo "CONTAINERS_CONF_OVERRIDE=${podman_config}" >> "${GITHUB_ENV}"
|
|
|
|
- name: Configure rootless Podman
|
|
run: |
|
|
set -euo pipefail
|
|
if ! grep -q "^${USER}:" /etc/subuid; then
|
|
sudo usermod --add-subuids 100000-165535 "$USER"
|
|
fi
|
|
if ! grep -q "^${USER}:" /etc/subgid; then
|
|
sudo usermod --add-subgids 100000-165535 "$USER"
|
|
fi
|
|
runtime_dir="/run/user/$(id -u)"
|
|
sudo install -d -m 0700 -o "$(id -u)" -g "$(id -g)" "$runtime_dir"
|
|
echo "XDG_RUNTIME_DIR=$runtime_dir" >> "$GITHUB_ENV"
|
|
|
|
- name: Verify rootless Podman environment
|
|
run: |
|
|
set -euo pipefail
|
|
podman_version="$(podman version --format '{{.Client.Version}}')"
|
|
case "$podman_version" in
|
|
"${{ matrix.podman_major }}".*) ;;
|
|
*) echo "ERROR: expected Podman ${{ matrix.podman_major }}.x, found $podman_version" >&2; exit 1 ;;
|
|
esac
|
|
test "$(dpkg-query -W -f='${Version}' podman)" = "${{ matrix.podman_package_version }}"
|
|
test "$(dpkg-query -W -f='${Version}' conmon)" = "${{ matrix.conmon_package_version }}"
|
|
test "$(command -v podman)" = "/usr/bin/podman"
|
|
test "$(podman info --format '{{.Host.Conmon.Path}}')" = "/usr/bin/conmon"
|
|
test "$(podman info --format '{{.Host.Security.Rootless}}')" = "true"
|
|
test "$(podman info --format '{{.Host.RootlessNetworkCmd}}')" = "pasta"
|
|
test "$(sudo sysctl -n kernel.apparmor_restrict_unprivileged_userns)" = "1"
|
|
echo "=== host ==="
|
|
uname -a
|
|
echo "=== AppArmor ==="
|
|
cat /proc/self/attr/current
|
|
sudo aa-status || true
|
|
echo "=== Podman ==="
|
|
podman version
|
|
podman info --debug
|
|
|
|
- name: Probe rootless capability bounding set
|
|
run: |
|
|
set -euo pipefail
|
|
probe="$RUNNER_TEMP/openshell-capbset-probe"
|
|
cc -static -O2 -Wall -Wextra -Werror \
|
|
e2e/support/capbset-probe.c \
|
|
-o "$probe"
|
|
podman run --rm \
|
|
--cap-add=SETPCAP \
|
|
--volume "$probe:/openshell-capbset-probe:ro" \
|
|
docker.io/library/alpine:3.22 \
|
|
/openshell-capbset-probe
|
|
|
|
- name: Log in to GHCR with Podman
|
|
run: echo "${{ secrets.GITHUB_TOKEN }}" | podman login ghcr.io -u "${{ github.actor }}" --password-stdin
|
|
|
|
- name: Run rootless Podman E2E
|
|
run: mise run --no-deps --skip-deps e2e:podman:rootless
|
|
|
|
- name: Print AppArmor denials
|
|
if: always()
|
|
run: sudo dmesg | grep -E 'apparmor=.*DENIED|profile="unprivileged_userns"' | tail -100 || true
|
|
|
|
e2e-vm:
|
|
name: E2E (rust-vm)
|
|
# libkrun needs KVM, so this job must run directly on a GitHub-hosted
|
|
# Linux VM. GitHub-hosted macOS runners do not support nested
|
|
# virtualization, and a job container would hide the host KVM device.
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 90
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs['checkout-ref'] || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Use prebuilt OpenShell CLI
|
|
if: inputs.cli-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-cli
|
|
with:
|
|
artifact-prefix: ${{ inputs.cli-artifact-prefix }}
|
|
|
|
- name: Use prebuilt OpenShell gateway
|
|
if: inputs.gateway-artifact-prefix != ''
|
|
uses: ./.github/actions/setup-e2e-gateway
|
|
with:
|
|
artifact-prefix: ${{ inputs.gateway-artifact-prefix }}
|
|
|
|
- name: Use prebuilt OpenShell VM driver
|
|
if: inputs.vm-driver-artifact-name != ''
|
|
uses: ./.github/actions/setup-e2e-vm-driver
|
|
with:
|
|
artifact-name: ${{ inputs.vm-driver-artifact-name }}
|
|
|
|
- name: Install system dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
clang \
|
|
cmake \
|
|
libclang-dev \
|
|
libssl-dev \
|
|
libz3-dev \
|
|
openssh-client \
|
|
pkg-config \
|
|
socat \
|
|
zstd
|
|
|
|
- name: Enable KVM access
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ ! -c /dev/kvm ]]; then
|
|
echo "::error::The GitHub-hosted runner did not expose /dev/kvm"
|
|
lscpu
|
|
grep -m1 -E '^(flags|Features)' /proc/cpuinfo || true
|
|
ls -la /dev
|
|
exit 1
|
|
fi
|
|
|
|
# Package installation can restart systemd-udevd, which reapplies
|
|
# the default root:kvm 0660 mode. Install a persistent rule after
|
|
# dependencies so later udev events preserve runner access.
|
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
|
|
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger --settle --name-match=kvm
|
|
|
|
ls -l /dev/kvm
|
|
exec 3<>/dev/kvm
|
|
exec 3>&-
|
|
|
|
- name: Validate VM host tools
|
|
run: |
|
|
command -v mke2fs
|
|
command -v mkfs.ext4
|
|
command -v debugfs
|
|
|
|
- name: Install mise
|
|
run: |
|
|
curl https://mise.run | MISE_VERSION=v2026.4.25 sh
|
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
echo "$HOME/.local/share/mise/shims" >> "$GITHUB_PATH"
|
|
|
|
- name: Install tools
|
|
run: mise install --locked
|
|
|
|
- name: Cache Rust target and registry
|
|
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2
|
|
with:
|
|
shared-key: e2e-vm-linux-amd64
|
|
cache-on-failure: "true"
|
|
|
|
- name: Run VM E2E
|
|
run: mise run --no-deps --skip-deps e2e:vm
|