mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-16 05:20:22 +08:00
* test(e2e): run rootless podman on ubuntu host Signed-off-by: Evan Lezar <elezar@nvidia.com> * test(e2e): probe rootless capability behavior Signed-off-by: Evan Lezar <elezar@nvidia.com> * test(e2e): make capability probe observational Signed-off-by: Evan Lezar <elezar@nvidia.com> --------- Signed-off-by: Evan Lezar <elezar@nvidia.com>
208 lines
7.5 KiB
YAML
208 lines
7.5 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: ""
|
|
|
|
permissions:
|
|
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: 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ inputs['checkout-ref'] || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Check out MCP conformance tests
|
|
if: matrix.suite == 'mcp'
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
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'
|
|
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.
|
|
runs-on: ${{ matrix.runner }}
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Ubuntu 24.04 matches the environment reported in #2069 and ships
|
|
# Podman 4.x. The probe records whether AppArmor blocks the drop.
|
|
- runner: ubuntu-24.04
|
|
podman_major: "4"
|
|
# Ubuntu 26.04 provides the supported Podman 5.x coverage for
|
|
# comparison with the Ubuntu 24.04 environment.
|
|
- runner: ubuntu-26.04
|
|
podman_major: "5"
|
|
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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ inputs['checkout-ref'] || github.sha }}
|
|
persist-credentials: false
|
|
|
|
- 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 \
|
|
podman \
|
|
slirp4netns \
|
|
uidmap
|
|
|
|
- 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 "$(podman info --format '{{.Host.Security.Rootless}}')" = "true"
|
|
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
|