Skip to content
Open
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
11 changes: 10 additions & 1 deletion .agents/skills/test-release-canary/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The Release Canary (`.github/workflows/release-canary.yml`) smoke-tests the arti
| `macos` | `macos-latest-xlarge` | `install.sh` resolves the Homebrew formula, brew installs the cask, and `openshell status` reaches the brew-services–backed local gateway with the VM driver. |
| `ubuntu` | `ubuntu-latest` | `install.sh` installs the Debian package, the post-install systemd user service starts, and `openshell status` reaches the local gateway with the Docker driver. |
| `fedora` | `fedora:latest` container | `install.sh` installs the RPM packages, the local gateway starts under Podman, and `openshell status` succeeds. |
| `ubuntu-snap` | `ubuntu-latest` | Downloads the Snap artifact from Release Dev, installs it with `--dangerous`, connects the required interfaces, and waits up to 30 seconds for the recovered local gateway. |
| `kubernetes` | `ubuntu-latest` + kind | `helm install oci://ghcr.io/nvidia/openshell/helm-chart --version 0.0.0-dev` succeeds in a kind cluster, the gateway pod becomes Ready, port-forward exposes 8080, and the released CLI registers the in-cluster gateway and runs `openshell status` against it. |

All canary jobs disable anonymous OpenShell telemetry. Host package jobs inject
Expand Down Expand Up @@ -41,7 +42,7 @@ on:
```

- **Automatic.** Every successful `Release Dev` run (on `main` or a manual dispatch of Release Dev) fires the canary. Each job gates on `github.event.workflow_run.conclusion == 'success'` so a failed Release Dev does not run the canary.
- **Manual.** `workflow_dispatch` lets you run the canary on demand against any branch's workflow definition.
- **Manual.** `workflow_dispatch` lets you run the canary on demand against any branch's workflow definition. To include `ubuntu-snap`, supply `release-dev-run-id` for a successful Release Dev run whose Snap artifact should be tested; without it, that job is skipped because no artifact is available.

When dispatched manually, `github.event.workflow_run.head_sha` is empty and the workflow falls back to `github.sha` (the branch tip) for the `install.sh` URL.

Expand All @@ -53,6 +54,13 @@ Run the canary as-is on the current branch:
gh workflow run release-canary.yml --ref "$(git branch --show-current)"
```

To exercise the Ubuntu Snap job, pass the successful Release Dev run ID:

```shell
gh workflow run release-canary.yml --ref "$(git branch --show-current)" \
-f release-dev-run-id=<release-dev-run-id>
```

Watch the run that starts:

```shell
Expand Down Expand Up @@ -122,6 +130,7 @@ Loopback registration auto-derives the gateway name to `openshell` if `--name` i
|---|---|---|
| `macos`/`ubuntu`/`fedora` job fails on `install.sh` | Latest tagged release missing an asset, checksum mismatch, or `install.sh` regression on this branch. | Job log around the `curl … install.sh \| sh` step. |
| `macos`/`ubuntu`/`fedora` job fails on `openshell status` | Local gateway service did not start (systemd/brew/podman). Often a driver issue. | Service logs in the job log; `OPENSHELL_DRIVERS` env in the "Ensure …" step. |
| `ubuntu-snap` fails after interface connection | The gateway did not recover after Docker became available, or did not become reachable within the 30-second bound. | Failure diagnostics dump Snap service/connection/change state, gateway and snapd journals, Snap logs, and port 17670 listeners. |
| `kubernetes` job fails on `helm install --wait` | Chart did not deploy in 5 min — usually image pull failure or readiness probe failing. | "Diagnostics on failure" step dumps `helm status`, manifest, pod describe, pod logs. |
| `kubernetes` job fails on `kubectl wait` | Gateway pod stuck `CrashLoopBackOff` or `ImagePullBackOff`. | Diagnostics dump; check `:dev` image existence at `ghcr.io/nvidia/openshell/gateway`. |
| `kubernetes` job fails on `openshell gateway add` or `status` | Port-forward not reachable, or CLI/gateway proto mismatch. | `port-forward.log` and `openshell gateway list` in the diagnostics dump. |
Expand Down
31 changes: 28 additions & 3 deletions .github/workflows/release-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ name: Release Canary

on:
workflow_dispatch:
inputs:
release-dev-run-id:
description: "Successful Release Dev run ID whose Snap artifact to test"
required: false
type: string
workflow_run:
workflows: ["Release Dev"]
types: [completed]
Expand Down Expand Up @@ -154,7 +159,7 @@ jobs:

ubuntu-snap:
name: Ubuntu Snap
if: ${{ github.event.workflow_run.conclusion == 'success' }}
if: ${{ github.event.workflow_run.conclusion == 'success' || inputs.release-dev-run-id != '' }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
Expand All @@ -176,7 +181,7 @@ jobs:
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
run-id: ${{ inputs.release-dev-run-id || github.event.workflow_run.id }}
pattern: snap-linux-amd64
path: release/
merge-multiple: true
Expand All @@ -202,7 +207,27 @@ jobs:
sudo snap services openshell
openshell gateway add http://127.0.0.1:17670 --local --name snap-docker
openshell gateway select snap-docker
openshell status
for _ in $(seq 1 30); do
if openshell status; then
exit 0
fi
sleep 1
done
echo "Gateway did not become ready within 30 seconds" >&2
exit 1

- name: Collect Snap diagnostics
if: failure()
run: |
set +e
sudo snap services openshell
sudo snap connections openshell
sudo snap changes
sudo systemctl status snap.openshell.gateway.service --no-pager
sudo journalctl -b -u snap.openshell.gateway.service --no-pager -n 300
sudo journalctl -b -u snapd.service --no-pager -n 300
sudo snap logs openshell.gateway -n=300
sudo ss -ltnp '( sport = :17670 )'

kubernetes:
name: Kubernetes Helm (kind)
Expand Down
3 changes: 3 additions & 0 deletions docs/about/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ requires manual connection:
sudo snap connect openshell:docker docker:docker-daemon
```

Connecting Docker automatically restarts the gateway so it discovers the newly
available Docker socket. This restart interrupts active sandbox sessions.
Comment on lines +107 to +108

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems superfluous


The snap declares `default-provider: docker` on the Docker plug so snapd will
offer to install the Docker snap, but the connection itself must be made
manually.
Expand Down
12 changes: 12 additions & 0 deletions python/openshell/release_formula_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import annotations

import re
import stat
import subprocess
import sys
from pathlib import Path
Expand Down Expand Up @@ -130,6 +131,17 @@ def test_snap_wrapper_uses_optional_gateway_config_without_generating_toml() ->
assert 'exec "${SNAP}/bin/openshell-gateway" "$@"' in wrapper


def test_snap_docker_connect_hook_restarts_gateway() -> None:
repo_root = Path(__file__).resolve().parents[2]
hook = repo_root / "snap/hooks/connect-plug-docker"

assert hook.is_file()
assert hook.stat().st_mode & stat.S_IXUSR
assert 'snapctl restart "${SNAP_INSTANCE_NAME}.gateway"' in hook.read_text(
encoding="utf-8"
)


def test_rpm_spec_uses_gateway_defaults_without_config_helper() -> None:
repo_root = Path(__file__).resolve().parents[2]
spec = (repo_root / "openshell.spec").read_text(encoding="utf-8")
Expand Down
12 changes: 12 additions & 0 deletions snap/hooks/connect-plug-docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# The gateway daemon can start when this plug is still disconnected. Restart it
# after Docker access becomes available so driver auto-detection runs with the
# socket exposed by docker:docker-daemon. This hook does not make normal gateway
# startup conditional on Docker; it runs only after an operator connects Docker.

set -eu

snapctl restart "${SNAP_INSTANCE_NAME}.gateway"
6 changes: 4 additions & 2 deletions snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ description: |

Support for system-installed Docker is coming in snapd 2.76.

2. Connect the required interfaces and start the gateway:
2. Connect the required interfaces:

sudo snap connect openshell:docker docker:docker-daemon
sudo snap connect openshell:log-observe
sudo snap connect openshell:system-observe
sudo snap start openshell.gateway

Connecting Docker automatically restarts the gateway so it discovers
the newly available Docker socket.

3. Verify the gateway and register it locally:

Expand Down
Loading