Skip to content

Release Canary

Release Canary #32

name: Release Canary
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to test (e.g. devel, v1.2.3)"
required: true
type: string
workflow_run:
workflows: ["Release Dev", "Release Tag"]
types: [completed]
permissions:
contents: read
packages: read
defaults:
run:
shell: bash
jobs:
acceptance:
name: Canary (${{ matrix.arch }})
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
runner: build-amd64
target: x86_64-unknown-linux-musl
- arch: arm64
runner: build-arm64
target: aarch64-unknown-linux-musl
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
# Run with Docker-in-Docker: the CI container starts its own dockerd so
# the gateway cluster container is a child process. This means 127.0.0.1
# port bindings are reachable directly, matching the real user experience
# without needing --gateway-host workarounds.
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
options: --privileged
env:
OPENSHELL_REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Determine release tag
id: release
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=devel" >> "$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
- name: Start Docker daemon
run: |
# Start our own dockerd for Docker-in-Docker. The CI container runs
# --privileged so the daemon can create networks and cgroups.
# Using DinD means the gateway container is a child of this
# container's daemon, so 127.0.0.1 port bindings are reachable
# directly — no --gateway-host workaround needed.
#
# We use a dedicated socket because the GHA runner injects its own
# /var/run/docker.sock for container management. DOCKER_HOST is set
# per-step (not via GITHUB_ENV) to avoid breaking the runner.
dockerd --host unix:///var/run/dind.sock &>/var/log/dockerd.log &
echo "Waiting for Docker daemon..."
export DOCKER_HOST=unix:///var/run/dind.sock
timeout 30 sh -c 'until docker info >/dev/null 2>&1; do sleep 1; done'
echo "Docker daemon ready"
- name: Install CLI from GitHub Release
run: ./install.sh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENSHELL_VERSION: ${{ steps.release.outputs.tag }}
- name: Verify CLI installation
run: openshell --version
- name: Run canary test
env:
DOCKER_HOST: unix:///var/run/dind.sock
run: |
set -euo pipefail
# Single-command canary: tests the full zero-to-sandbox path.
# With no gateway configured, `sandbox create` auto-bootstraps a
# gateway (pulls the cluster image from GHCR, starts k3s, deploys
# the control plane, generates mTLS PKI), then creates a sandbox
# and runs the command inside it.
echo "Creating sandbox (with auto-bootstrap) 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"
echo ""
echo "--- dockerd logs ---"
cat /var/log/dockerd.log || true
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