Release Canary #37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| 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 | |
| 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: Install CLI | |
| run: | | |
| # For workflow_dispatch (manual/branch testing), build from source | |
| # so we test the code on this branch. For workflow_run (release | |
| # testing), install the published binary. | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "Building CLI from source..." | |
| cargo build --release -p openshell-cli | |
| cp target/release/openshell /usr/local/bin/openshell | |
| else | |
| GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" \ | |
| OPENSHELL_VERSION="${{ steps.release.outputs.tag }}" \ | |
| ./install.sh | |
| fi | |
| - name: Verify CLI installation | |
| run: openshell --version | |
| - name: Resolve gateway host | |
| run: | | |
| # On Linux CI runners host.docker.internal is not set automatically | |
| # (it's a Docker Desktop feature). Add it via the Docker bridge IP. | |
| if ! getent hosts host.docker.internal >/dev/null 2>&1; then | |
| BRIDGE_IP=$(docker network inspect bridge --format '{{(index .IPAM.Config 0).Gateway}}') | |
| echo "Adding /etc/hosts entry: ${BRIDGE_IP} host.docker.internal" | |
| echo "${BRIDGE_IP} host.docker.internal" >> /etc/hosts | |
| fi | |
| - name: Run canary test | |
| env: | |
| # The CI container uses Docker-outside-of-Docker (host socket mount), | |
| # so the gateway container is a sibling on the host. 127.0.0.1 inside | |
| # the CI container doesn't reach it — OPENSHELL_GATEWAY_HOST tells | |
| # the auto-bootstrap to advertise host.docker.internal instead. | |
| OPENSHELL_GATEWAY_HOST: host.docker.internal | |
| 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" | |
| 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 |