Skip to content
Merged
Show file tree
Hide file tree
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
292 changes: 23 additions & 269 deletions .github/workflows/release-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,293 +2,47 @@ name: Release Canary

on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to test (e.g. dev, v1.2.3)"
required: true
type: string
workflow_run:
workflows: ["Release Dev", "Release Tag"]
workflows: ["Release Dev"]
types: [completed]

permissions:
contents: read
packages: read

defaults:
run:
shell: bash

jobs:
# ---------------------------------------------------------------------------
# Verify the default install path (no OPENSHELL_VERSION) resolves to latest
# ---------------------------------------------------------------------------
install-default:
name: Install default (${{ matrix.arch }})
if: >-
github.event.workflow_run.conclusion == 'success'
&& github.event.workflow_run.name == 'Release Tag'
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: linux-amd64-cpu8
- arch: arm64
runner: linux-arm64-cpu8
runs-on: ${{ matrix.runner }}
timeout-minutes: 10
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Install CLI (default / latest)
run: |
set -euo pipefail
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh

- name: Verify CLI installation
run: |
set -euo pipefail
command -v openshell
ACTUAL="$(openshell --version)"
echo "Installed: $ACTUAL"
# This job only runs after Release Tag, so the triggering tag
# should match the latest release the default installer resolves to.
TAG="${{ github.event.workflow_run.head_branch }}"
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
EXPECTED="${TAG#v}"
if [[ "$ACTUAL" != *"$EXPECTED"* ]]; then
echo "::error::Version mismatch: expected '$EXPECTED' in '$ACTUAL'"
exit 1
fi
echo "Version check passed: found $EXPECTED in output"
fi

install-dev:
name: Install Debian package (${{ matrix.arch }})
macos:
name: macOS Homebrew
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: linux-amd64-cpu8
- arch: arm64
runner: linux-arm64-cpu8
runs-on: ${{ matrix.runner }}
timeout-minutes: 10
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
runs-on: macos-latest-xlarge
timeout-minutes: 20
steps:
- name: Determine release tag
id: release
- name: Install dev and check status
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
else
WORKFLOW_NAME="${{ github.event.workflow_run.name }}"
if [ "$WORKFLOW_NAME" = "Release Dev" ]; then
echo "tag=dev" >> "$GITHUB_OUTPUT"
elif [ "$WORKFLOW_NAME" = "Release Tag" ]; then
TAG="${{ github.event.workflow_run.head_branch }}"
if [ -z "$TAG" ]; then
echo "::error::Could not determine release tag from workflow_run"
exit 1
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
else
echo "::error::Unexpected triggering workflow: ${WORKFLOW_NAME}"
exit 1
fi
fi
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install-dev.sh | sh
openshell status

- name: Install Debian package
run: |
set -euo pipefail
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install-dev.sh \
| OPENSHELL_VERSION=${{ steps.release.outputs.tag }} sh

- name: Verify gateway and VM driver versions
run: |
set -euo pipefail
command -v openshell-gateway
test -x /usr/libexec/openshell/openshell-driver-vm

GATEWAY_ACTUAL="$(openshell-gateway --version)"
DRIVER_ACTUAL="$(/usr/libexec/openshell/openshell-driver-vm --version)"
echo "Gateway: ${GATEWAY_ACTUAL}"
echo "Driver: ${DRIVER_ACTUAL}"

TAG="${{ steps.release.outputs.tag }}"
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
EXPECTED="${TAG#v}"
for actual in "$GATEWAY_ACTUAL" "$DRIVER_ACTUAL"; do
if [[ "$actual" != *"$EXPECTED"* ]]; then
echo "::error::Version mismatch: expected '$EXPECTED' in '$actual'"
exit 1
fi
done
echo "Version check passed: found $EXPECTED in both binaries"
else
echo "Non-release tag ($TAG), skipping version check"
fi

canary:
name: Canary package gateway (${{ matrix.arch }})
ubuntu:
name: Ubuntu Docker
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: linux-amd64-cpu8
- arch: arm64
runner: linux-arm64-cpu8
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
env:
OPENSHELL_REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENSHELL_CANARY_PORT: "17670"
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6

- name: Determine release tag
id: release
- name: Ensure Docker
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
else
WORKFLOW_NAME="${{ github.event.workflow_run.name }}"
if [ "$WORKFLOW_NAME" = "Release Dev" ]; then
echo "tag=dev" >> "$GITHUB_OUTPUT"
elif [ "$WORKFLOW_NAME" = "Release Tag" ]; then
TAG="${{ github.event.workflow_run.head_branch }}"
if [ -z "$TAG" ]; then
echo "::error::Could not determine release tag from workflow_run"
exit 1
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
else
echo "::error::Unexpected triggering workflow: ${WORKFLOW_NAME}"
exit 1
fi
if ! command -v docker >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y docker.io
fi
sudo systemctl start docker || sudo service docker start
mkdir -p "${HOME}/.config/openshell"
printf 'OPENSHELL_DRIVERS=docker\n' > "${HOME}/.config/openshell/gateway.env"
docker info

- name: Install Debian package
- name: Install dev and check status
run: |
set -euo pipefail
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install-dev.sh \
| OPENSHELL_VERSION=${{ steps.release.outputs.tag }} sh

- name: Verify package binaries
run: |
set -euo pipefail
command -v openshell
command -v openshell-gateway
test -x /usr/libexec/openshell/openshell-driver-vm

CLI_ACTUAL="$(openshell --version)"
GATEWAY_ACTUAL="$(openshell-gateway --version)"
DRIVER_ACTUAL="$(/usr/libexec/openshell/openshell-driver-vm --version)"
echo "CLI: ${CLI_ACTUAL}"
echo "Gateway: ${GATEWAY_ACTUAL}"
echo "Driver: ${DRIVER_ACTUAL}"

TAG="${{ steps.release.outputs.tag }}"
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
EXPECTED="${TAG#v}"
for actual in "$CLI_ACTUAL" "$GATEWAY_ACTUAL" "$DRIVER_ACTUAL"; do
if [[ "$actual" != *"$EXPECTED"* ]]; then
echo "::error::Version mismatch: expected '$EXPECTED' in '$actual'"
exit 1
fi
done
echo "Version check passed: found $EXPECTED in package binaries"
else
echo "Non-release tag ($TAG), skipping version check"
fi

- name: Start packaged gateway
run: |
set -euo pipefail

# The CLI no longer owns gateway lifecycle. In CI we start the
# gateway binary installed by the Debian package directly, using the
# Docker driver so this canary can launch a real sandbox.
systemctl --user stop openshell-gateway >/dev/null 2>&1 || true

STATE_DIR="$(mktemp -d)"
LOG="${STATE_DIR}/openshell-gateway.log"
echo "GATEWAY_LOG=${LOG}" >> "$GITHUB_ENV"
echo "GATEWAY_STATE_DIR=${STATE_DIR}" >> "$GITHUB_ENV"

OPENSHELL_BIND_ADDRESS=0.0.0.0 \
OPENSHELL_SERVER_PORT="${OPENSHELL_CANARY_PORT}" \
OPENSHELL_DISABLE_TLS=true \
OPENSHELL_DISABLE_GATEWAY_AUTH=true \
OPENSHELL_DRIVERS=docker \
OPENSHELL_DB_URL="sqlite:${STATE_DIR}/openshell.db?mode=rwc" \
OPENSHELL_GRPC_ENDPOINT="http://host.openshell.internal:${OPENSHELL_CANARY_PORT}" \
OPENSHELL_SSH_GATEWAY_HOST=127.0.0.1 \
OPENSHELL_SSH_GATEWAY_PORT="${OPENSHELL_CANARY_PORT}" \
OPENSHELL_SANDBOX_NAMESPACE="canary-${{ matrix.arch }}-${{ github.run_id }}" \
nohup openshell-gateway >"${LOG}" 2>&1 &
PID=$!
echo "GATEWAY_PID=${PID}" >> "$GITHUB_ENV"

for _ in $(seq 1 60); do
if curl -fsS "http://127.0.0.1:${OPENSHELL_CANARY_PORT}/healthz" >/dev/null; then
break
fi
if ! kill -0 "$PID" 2>/dev/null; then
echo "::error::openshell-gateway exited before becoming healthy"
cat "$LOG"
exit 1
fi
sleep 1
done

curl -fsS "http://127.0.0.1:${OPENSHELL_CANARY_PORT}/healthz"
openshell gateway remove local >/dev/null 2>&1 || true
openshell gateway add "http://127.0.0.1:${OPENSHELL_CANARY_PORT}" --local --name local

- name: Run canary test
run: |
set -euo pipefail

echo "Creating sandbox and running 'echo hello world'..."
OUTPUT=$(openshell sandbox create --no-keep --no-tty -- echo "hello world" 2>&1) || {
EXIT_CODE=$?
echo "::error::openshell sandbox create failed with exit code ${EXIT_CODE}"
echo "$OUTPUT"
exit $EXIT_CODE
}

echo "$OUTPUT"

if echo "$OUTPUT" | grep -q "hello world"; then
echo "Canary test passed: 'hello world' found in output"
else
echo "::error::Canary test failed: 'hello world' not found in output"
exit 1
fi

- name: Stop packaged gateway
if: always()
run: |
set -euo pipefail
if [ -n "${GATEWAY_PID:-}" ]; then
kill "$GATEWAY_PID" >/dev/null 2>&1 || true
fi
if [ "${{ job.status }}" != "success" ] && [ -n "${GATEWAY_LOG:-}" ] && [ -f "$GATEWAY_LOG" ]; then
echo "Gateway log:"
cat "$GATEWAY_LOG"
fi
curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/${{ github.event.workflow_run.head_sha || github.sha }}/install-dev.sh | sh
openshell status
Loading
Loading