From d69af115c6c4fd414c19ba01b74c8e2a1c40f185 Mon Sep 17 00:00:00 2001 From: Oliver Calder Date: Fri, 9 Oct 2026 13:51:57 -0500 Subject: [PATCH 1/2] feat(install): install the snap package by default when supported - `install.sh` now selects snap when the `snap` command exists and `OPENSHELL_VERSION` is unset or `dev`. - Explicit `OPENSHELL_INSTALL_METHOD=snap|deb|rpm` still takes precedence. - Exact releases and prereleases continue to use native packages during automatic selection. - Docker-related snap errors now mention DEB/RPM overrides. - Installer selection tests cover default snap selection, native fallbacks, overrides, pinned releases, and prereleases. - Snap canary jobs no longer force `OPENSHELL_INSTALL_METHOD=snap`, so they test automatic selection. - Updated installation, VM driver, release canary, CI, and test guest documentation. - Fixed some leftover "Snap" language which should be "snap" Signed-off-by: Oliver Calder --- .agents/skills/test-release-canary/SKILL.md | 16 ++++++------ .github/workflows/release-canary.yml | 4 --- CI.md | 2 +- crates/openshell-driver-vm/README.md | 13 ++++++---- docs/about/installation.mdx | 10 +++++--- install.sh | 27 ++++++++++----------- nix/test-guest/README.md | 8 +++--- tasks/scripts/test-install-sh.sh | 14 +++++++---- tasks/scripts/test-packaging-assets.sh | 1 + 9 files changed, 51 insertions(+), 44 deletions(-) diff --git a/.agents/skills/test-release-canary/SKILL.md b/.agents/skills/test-release-canary/SKILL.md index fc6414eeed..31799f6cb0 100644 --- a/.agents/skills/test-release-canary/SKILL.md +++ b/.agents/skills/test-release-canary/SKILL.md @@ -16,8 +16,8 @@ The Release Canary (`.github/workflows/release-canary.yml`) smoke-tests the arti | `macos` | `macos-latest-xlarge` | Installs the dev Homebrew artifacts, reaches the VM gateway, and creates, executes in, and deletes a sandbox. | | `ubuntu-deb` | `ubuntu-latest` | Installs the dev Debian package, reaches the Docker gateway, and creates, executes in, and deletes a sandbox. | | `fedora` | `fedora:latest` container | Installs the dev RPM packages, reaches the Podman gateway, and creates, executes in, and deletes a sandbox. | -| `ubuntu-snap-system-docker` | `ubuntu-latest` | Uses `install.sh` to install the snap from `latest/edge`, reuses system Docker, verifies the packaged prover version and a local policy boundary check, reaches the Docker gateway, creates, executes in, and deletes a sandbox, and verifies that the Docker snap is not installed. | -| `ubuntu-snap-docker-preflight` | `ubuntu-latest` | Verifies that `install.sh` rejects the OpenShell snap path when Docker is absent or supplied by the Docker snap, without installing OpenShell. | +| `ubuntu-snap-system-docker` | `ubuntu-latest` | Verifies that `install.sh` selects the snap automatically when the `snap` command is available, installs it from `latest/edge`, reuses system Docker, verifies the packaged prover version and a local policy boundary check, reaches the Docker gateway, creates, executes in, and deletes a sandbox, and verifies that the Docker snap is not installed. | +| `ubuntu-snap-docker-preflight` | `ubuntu-latest` | Verifies that automatic snap selection rejects installation when Docker is absent or supplied by the Docker snap, without installing OpenShell. | | `kubernetes` | `ubuntu-latest` + kind | Installs the dev Helm chart, reaches the in-cluster gateway, and creates, executes in, and deletes a sandbox using the published runtime images. | All canary jobs disable anonymous OpenShell telemetry. Host package jobs inject @@ -26,11 +26,13 @@ Kubernetes job installs with `server.telemetryEnabled=false`, so smoke traffic does not contribute to product usage metrics. The workflow sets `OPENSHELL_VERSION=dev` for every `install.sh` job. Positive -jobs consume the rolling dev release produced by the triggering workflow. The -system-Docker snap lane tracks `latest/edge`; the missing-Docker lane exits -before installing a snap. The Debian and Kubernetes CLI lanes remove snapd so -they continue to exercise the dev Debian package. Kubernetes pins the matching -`0.0.0-dev` chart and `:dev` images. +jobs consume the rolling dev release produced by the triggering workflow. Both +snap lanes rely on the installed `snap` command to exercise automatic snap +selection without setting `OPENSHELL_INSTALL_METHOD`. The system-Docker lane +tracks `latest/edge`; the missing-Docker lane exits before installing a snap. +The Debian and Kubernetes CLI lanes remove snapd so they continue to exercise +the dev Debian package. Kubernetes pins the matching `0.0.0-dev` chart and +`:dev` images. RPM package installation also has tmachine conformance coverage in `Branch E2E Checks` (with `test:e2e`), `Release Dev`, and `Release Tag`. Those diff --git a/.github/workflows/release-canary.yml b/.github/workflows/release-canary.yml index d60697a12a..c5494cd2c8 100644 --- a/.github/workflows/release-canary.yml +++ b/.github/workflows/release-canary.yml @@ -195,8 +195,6 @@ jobs: name: Ubuntu snap with system Docker if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest - env: - OPENSHELL_INSTALL_METHOD: snap timeout-minutes: 20 steps: - name: Install snapd @@ -297,8 +295,6 @@ jobs: name: Ubuntu snap Docker preflight if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest - env: - OPENSHELL_INSTALL_METHOD: snap timeout-minutes: 20 steps: - name: Install snapd diff --git a/CI.md b/CI.md index fc9547720f..dc98688937 100644 --- a/CI.md +++ b/CI.md @@ -571,7 +571,7 @@ These workflows run after merge to publish dev/tagged artifacts and verify them. | `.github/workflows/release-tag.yml` | Publishes stable releases and pre-releases on tag pushes or manual dispatch. Release Auto-Tag dispatches it explicitly because its `GITHUB_TOKEN` pushes do not trigger workflows. Both require the currently implemented qualification profile to pass before publication; the summary identifies the remaining RFC 0014 coverage. Failed candidates retain build artifacts and evidence in Actions storage. Source-SHA OCI images remain available as qualification inputs. | | `.github/workflows/snap-package.yml` | Builds snap and component artifacts for Release Dev and Release Tag without Store credentials or publication. | | `.github/workflows/snap-publish.yml` | Uploads existing snap and component artifacts to the Store without rebuilding. Release Dev calls it directly for `latest/edge` after snap builds and requires it to succeed before creating the dev release. Release Tag calls it for `latest/stable` only for stable releases, after qualification and release assembly succeed. | -| `.github/workflows/release-canary.yml` | Smoke-tests published dev artifacts in the `macos`, `ubuntu-deb`, `ubuntu-snap-system-docker`, `fedora`, and `kubernetes` (kind + Helm) jobs. Each job reaches its gateway and creates, exercises, and deletes a sandbox. The `ubuntu-snap-system-docker` job verifies a compatible system Docker lifecycle, while `ubuntu-snap-docker-preflight` tests fail-fast behavior when Docker is absent or supplied by the Docker snap. The positive snap lane also runs a local policy containment check with the packaged prover. It runs automatically after `Release Dev` succeeds and supports manual dispatch (`gh workflow run release-canary.yml --ref `). See the `test-release-canary` skill for the playbook and local kind reproduction. | +| `.github/workflows/release-canary.yml` | Smoke-tests published dev artifacts in the `macos`, `ubuntu-deb`, `ubuntu-snap-system-docker`, `fedora`, and `kubernetes` (kind + Helm) jobs. Each job reaches its gateway and creates, exercises, and deletes a sandbox. The snap jobs verify that `install.sh` selects the snap automatically when the `snap` command is available. The `ubuntu-snap-system-docker` job verifies a compatible system Docker lifecycle, while `ubuntu-snap-docker-preflight` tests fail-fast behavior when Docker is absent or supplied by the Docker snap. The positive snap lane also runs a local policy containment check with the packaged prover. It runs automatically after `Release Dev` succeeds and supports manual dispatch (`gh workflow run release-canary.yml --ref `). See the `test-release-canary` skill for the playbook and local kind reproduction. | ## Required status contexts diff --git a/crates/openshell-driver-vm/README.md b/crates/openshell-driver-vm/README.md index 4d6454e810..efaccade73 100644 --- a/crates/openshell-driver-vm/README.md +++ b/crates/openshell-driver-vm/README.md @@ -311,14 +311,17 @@ create TAP devices or install nftables/iptables rules. `release-vm-kernel.yml` On Debian-family Linux amd64 and arm64 systems, `install.sh` installs the -Debian package from the selected `OPENSHELL_VERSION` release tag. That package -includes `openshell-gateway` and `openshell-driver-vm`, but leaves +Debian package when the `snap` command is unavailable, automatic selection +receives an exact `OPENSHELL_VERSION` release tag, or +`OPENSHELL_INSTALL_METHOD=deb` is set. That package includes +`openshell-gateway` and `openshell-driver-vm`, but leaves `OPENSHELL_COMPUTE_DRIVER` unset so the gateway uses its normal runtime auto-detection. Set `OPENSHELL_COMPUTE_DRIVER=vm` to force the VM driver. -On RPM-family Linux x86_64 and aarch64 systems, `install.sh` installs the -`openshell` and `openshell-gateway` RPM packages from the selected release tag. -The RPM gateway package is configured for the Podman driver. +On RPM-family Linux x86_64 and aarch64 systems, the equivalent native path +installs the `openshell` and `openshell-gateway` RPM packages from the selected +release tag. Select it explicitly with `OPENSHELL_INSTALL_METHOD=rpm`. The RPM +gateway package is configured for the Podman driver. On Apple Silicon macOS, `install.sh` stages the generated `openshell.rb` formula from the selected release in the `nvidia/openshell` Homebrew tap. diff --git a/docs/about/installation.mdx b/docs/about/installation.mdx index 2a2057ddb6..a1b5176f47 100644 --- a/docs/about/installation.mdx +++ b/docs/about/installation.mdx @@ -86,9 +86,11 @@ The gateway reads `~/.config/openshell/gateway.toml` if it exists, otherwise the ## Linux -The script installs a Debian package on Debian and Ubuntu or an RPM package on Fedora and RHEL. Set `OPENSHELL_INSTALL_METHOD=snap` to install the [snap](#snap) package instead; hosts that already have the OpenShell snap keep refreshing it. Linux packages require glibc 2.28 or newer. +When the `snap` command is available, the script installs the [snap](#snap) package for the latest stable release or the rolling `dev` release. Otherwise, it installs a Debian package on Debian and Ubuntu or RPM packages on Fedora and RHEL. During automatic selection, prereleases and explicit release tags use native packages so the installer can select the exact release artifacts. Explicit `OPENSHELL_INSTALL_METHOD=snap` supports only an unset version or `OPENSHELL_VERSION=dev`. -The gateway runs as a systemd user service at `https://127.0.0.1:17670` and reads `~/.config/openshell/gateway.toml`. +Set `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm` to select a native package explicitly. Native Linux packages require glibc 2.28 or newer. + +For Debian and RPM installations, the gateway runs as a systemd user service at `https://127.0.0.1:17670` and reads `~/.config/openshell/gateway.toml`. Both Debian and RPM load `~/.config/openshell/gateway.env` for configuration preflight and gateway startup. Use it to select exact trusted runtime artifacts @@ -119,9 +121,9 @@ sudo loginctl enable-linger $USER ## Snap -The snap requires Docker Engine installed from your distribution or Docker's package repository. The Docker snap is not compatible. +The snap requires Docker Engine installed from your distribution or Docker's package repository. The Docker snap is not compatible. To use Podman or the VM driver instead, select a native package with `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm`. -The snap does not migrate existing Debian, RPM, or Homebrew installs. Remove any existing installation first, then either rerun the `install.sh` script with `OPENSHELL_INSTALL_METHOD=snap OPENSHELL_ACK_BREAKING_UPGRADE=1`, or install the snap directly: +The snap does not migrate existing Debian, RPM, or Homebrew installs. If the script detects an existing native installation while selecting the snap, it stops before making changes. To update the existing native installation instead, rerun it with `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm`. To migrate, remove the existing installation after backing up any state you need, then rerun the script with `OPENSHELL_ACK_BREAKING_UPGRADE=1`, or install the snap directly: ```shell sudo snap install openshell diff --git a/install.sh b/install.sh index 620a0beda0..a356af2d25 100755 --- a/install.sh +++ b/install.sh @@ -4,7 +4,8 @@ # # Install OpenShell from a GitHub release. # -# Linux installs either the Debian or RPM packages from the selected release. +# Linux automatically installs the snap when the snap command is available and +# the version is unset or dev; exact releases and prereleases use native packages. # Apple Silicon macOS installs the generated Homebrew formula, so Homebrew owns # the binary layout and launchd service lifecycle. # @@ -63,19 +64,19 @@ ENVIRONMENT VARIABLES: pre-v0.0.37 or non-snap installation. OPENSHELL_INSTALL_METHOD Linux package to install: snap, deb, or rpm. Unset - selects deb or rpm from the host package manager. + selects snap when available, otherwise deb or rpm. NOTES: When OPENSHELL_VERSION is unset, this resolves the latest tagged release from ${GITHUB_URL}/releases/latest. - Linux installs the Debian package on amd64/arm64 or the RPM packages on - x86_64/aarch64, depending on the host package manager. Set - OPENSHELL_INSTALL_METHOD=snap to install the OpenShell snap instead; hosts - that already have the OpenShell snap keep refreshing it. snap installs use - latest/stable by default and latest/edge for dev, and do not support - explicit release tags or prereleases. The OpenShell snap requires a running - Docker Engine installed from a system package or Docker's package + Linux installs the OpenShell snap when the snap command is available and + OPENSHELL_VERSION is unset or dev. Snap installs use latest/stable by + default and latest/edge for dev. Explicit release tags and prereleases use + the Debian package on amd64/arm64 or the RPM packages on x86_64/aarch64, + depending on the host package manager. Set OPENSHELL_INSTALL_METHOD=deb or + rpm to select a native package explicitly. The OpenShell snap requires a + running Docker Engine installed from a system package or Docker's package repository. The Docker snap is not currently compatible with OpenShell. macOS installs the release Homebrew formula on Apple Silicon and starts a brew services-backed local gateway. @@ -668,11 +669,9 @@ linux_package_method() { *) error "unsupported OPENSHELL_INSTALL_METHOD=${OPENSHELL_INSTALL_METHOD}; use snap, deb, or rpm" ;; esac - # Keep refreshing an existing snap install instead of adding a second - # gateway on the same port. case "${OPENSHELL_VERSION:-}" in '' | dev) - if has_cmd snap && snap list openshell >/dev/null 2>&1; then + if has_cmd snap; then echo "snap" return 0 fi @@ -1467,11 +1466,11 @@ install_linux_snap() { if snap list docker >/dev/null 2>&1; then error "the Docker snap is not currently compatible with OpenShell because its AppArmor confinement prevents OpenShell's hardened containers from starting. -Remove the Docker snap and install Docker Engine from a system package or Docker's package repository, then rerun this installer." +Remove the Docker snap and install Docker Engine from a system package or Docker's package repository, then rerun this installer. To use a native OpenShell package instead, set OPENSHELL_INSTALL_METHOD=deb or OPENSHELL_INSTALL_METHOD=rpm." fi if ! has_cmd docker; then error "Docker is required before installing the OpenShell snap. -Install Docker Engine from a system package or Docker's package repository, then rerun this installer. The Docker snap is not currently compatible with OpenShell." +Install Docker Engine from a system package or Docker's package repository, then rerun this installer. The Docker snap is not currently compatible with OpenShell. To use a native OpenShell package instead, set OPENSHELL_INSTALL_METHOD=deb or OPENSHELL_INSTALL_METHOD=rpm." fi info "using existing Docker installation" if [ "$_existing_mode" = user ]; then diff --git a/nix/test-guest/README.md b/nix/test-guest/README.md index 155b95305c..234a3c40f4 100644 --- a/nix/test-guest/README.md +++ b/nix/test-guest/README.md @@ -78,10 +78,10 @@ The root [`flake.nix`](../../flake.nix) exposes this directory as the `test-gues | Fedora 44 | No | Yes | Yes | Yes | `.rpm` | | Rocky Linux 9 | Yes | Yes | No | Yes | `.rpm` | -The `snapd` configuration is available for Ubuntu and prepares snapd for snap -Store installation experiments. Combine it with `docker` to reproduce the -system-Docker canary, or use it alone to verify that `install.sh` fails safely -when Docker is absent. +The `snapd` configuration is available for Ubuntu and prepares snapd to +reproduce `install.sh` automatic snap selection. Combine it with `docker` to +reproduce the system-Docker canary, or use it alone to verify that `install.sh` +fails safely when Docker is absent. `podman-rootless` configures the explicit rootless Podman guest setup used by OpenShell tests. It supports Fedora and Ubuntu 26.04 or later. Ubuntu adds the diff --git a/tasks/scripts/test-install-sh.sh b/tasks/scripts/test-install-sh.sh index e9ec590850..9d61035b9b 100755 --- a/tasks/scripts/test-install-sh.sh +++ b/tasks/scripts/test-install-sh.sh @@ -133,19 +133,23 @@ assert_linux_package_method() { fi } -assert_linux_package_method "deb is the default despite snap" "" "" 1 1 1 deb -assert_linux_package_method "rpm is the default despite snap" "" "" 1 0 1 rpm -assert_linux_package_method "dev uses deb despite snap" "" dev 1 1 1 deb -assert_linux_package_method "snap is opt-in" snap "" 1 1 1 snap -assert_linux_package_method "snap opt-in with dev" snap dev 1 1 1 snap +assert_linux_package_method "snap takes precedence over deb and rpm" "" "" 1 1 1 snap +assert_linux_package_method "snap takes precedence over rpm" "" "" 1 0 1 snap +assert_linux_package_method "dev uses snap" "" dev 1 1 1 snap +assert_linux_package_method "explicit snap" snap "" 1 1 1 snap +assert_linux_package_method "explicit snap with dev" snap dev 1 1 1 snap +assert_linux_package_method "explicit snap wins with pinned stable" snap v1.2.3 1 1 1 snap assert_linux_package_method "explicit deb" deb "" installed 0 1 deb assert_linux_package_method "explicit rpm" rpm "" 1 1 1 rpm assert_linux_package_method "existing snap install keeps refreshing" "" "" installed 1 1 snap assert_linux_package_method "existing snap install keeps refreshing dev" "" dev installed 1 1 snap assert_linux_package_method "pre uses deb despite existing snap" "" pre installed 1 1 deb +assert_linux_package_method "pre uses rpm despite snap" "" pre 1 0 1 rpm assert_linux_package_method "numbered prerelease uses deb despite existing snap" "" v0.1.0-pre.3 installed 1 1 deb +assert_linux_package_method "pinned stable uses deb despite snap" "" v1.2.3 1 1 1 deb assert_linux_package_method "pinned stable uses rpm despite existing snap" "" v1.2.3 installed 0 1 rpm assert_linux_package_method "deb is selected without snap" "" "" 0 1 1 deb +assert_linux_package_method "dev uses deb without snap" "" dev 0 1 1 deb assert_linux_package_method "rpm is selected without snap or deb" "" "" 0 0 1 rpm if (OPENSHELL_INSTALL_METHOD=flatpak linux_package_method) >"$out" 2>"$err"; then diff --git a/tasks/scripts/test-packaging-assets.sh b/tasks/scripts/test-packaging-assets.sh index 71baf77af4..853af30467 100755 --- a/tasks/scripts/test-packaging-assets.sh +++ b/tasks/scripts/test-packaging-assets.sh @@ -239,6 +239,7 @@ assert_contains "$snap_canary" "install.sh | sh" assert_contains "$snap_canary" "ubuntu-snap-system-docker:" assert_contains "$snap_canary" "ubuntu-snap-docker-preflight:" assert_contains "$snap_canary" "openshell.prover check" +assert_not_contains "$snap_canary" "OPENSHELL_INSTALL_METHOD" assert_not_contains "$snap_canary" "--dangerous" assert_not_contains "$snap_canary" "snap connect openshell:docker" if ! awk '/config preflight/ { seen = 1 } /generate-certs/ { exit !seen }' "$service"; then From e15b8bfcf39e9a066aed1da776f225621fe4dcf0 Mon Sep 17 00:00:00 2001 From: Oliver Calder Date: Tue, 13 Oct 2026 16:38:38 -0500 Subject: [PATCH 2/2] feat(install): improve snapd detection and clarify docs around snap selection Signed-off-by: Oliver Calder --- README.md | 2 + crates/openshell-driver-vm/README.md | 8 +- docs/about/installation.mdx | 4 +- install.sh | 16 +++- tasks/scripts/test-install-sh.sh | 108 ++++++++++++++++++++------- 5 files changed, 100 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 43f887bb95..5b81ba5077 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ See [Architecture](https://docs.nvidia.com/openshell/latest/about/architecture) You need Linux, macOS on Apple Silicon, or Windows with WSL 2 (experimental), plus Docker, Podman, or host virtualization. See the [Support Matrix](https://docs.nvidia.com/openshell/latest/about/support-matrix) for details. +On Linux with snapd, the default installation requires Docker Engine from a system package or Docker's repository; the Docker snap is unsupported. If you have snapd installed but want to use Podman or VMs instead of Docker, or you prefer a [native package](https://docs.nvidia.com/openshell/latest/about/installation#linux), you may do so with `OPENSHELL_INSTALL_METHOD=deb` or `rpm`. + ```shell curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh openshell sandbox create --name demo diff --git a/crates/openshell-driver-vm/README.md b/crates/openshell-driver-vm/README.md index efaccade73..51090aef9d 100644 --- a/crates/openshell-driver-vm/README.md +++ b/crates/openshell-driver-vm/README.md @@ -311,8 +311,8 @@ create TAP devices or install nftables/iptables rules. `release-vm-kernel.yml` On Debian-family Linux amd64 and arm64 systems, `install.sh` installs the -Debian package when the `snap` command is unavailable, automatic selection -receives an exact `OPENSHELL_VERSION` release tag, or +Debian package when snapd is unavailable, `OPENSHELL_VERSION=pre` or an exact +release tag is requested, or `OPENSHELL_INSTALL_METHOD=deb` is set. That package includes `openshell-gateway` and `openshell-driver-vm`, but leaves `OPENSHELL_COMPUTE_DRIVER` unset so the gateway uses its normal runtime @@ -320,8 +320,8 @@ auto-detection. Set `OPENSHELL_COMPUTE_DRIVER=vm` to force the VM driver. On RPM-family Linux x86_64 and aarch64 systems, the equivalent native path installs the `openshell` and `openshell-gateway` RPM packages from the selected -release tag. Select it explicitly with `OPENSHELL_INSTALL_METHOD=rpm`. The RPM -gateway package is configured for the Podman driver. +release tag. It is selected automatically under the same conditions or with +`OPENSHELL_INSTALL_METHOD=rpm`. The RPM gateway package uses the Podman driver. On Apple Silicon macOS, `install.sh` stages the generated `openshell.rb` formula from the selected release in the `nvidia/openshell` Homebrew tap. diff --git a/docs/about/installation.mdx b/docs/about/installation.mdx index a1b5176f47..120e072021 100644 --- a/docs/about/installation.mdx +++ b/docs/about/installation.mdx @@ -86,7 +86,7 @@ The gateway reads `~/.config/openshell/gateway.toml` if it exists, otherwise the ## Linux -When the `snap` command is available, the script installs the [snap](#snap) package for the latest stable release or the rolling `dev` release. Otherwise, it installs a Debian package on Debian and Ubuntu or RPM packages on Fedora and RHEL. During automatic selection, prereleases and explicit release tags use native packages so the installer can select the exact release artifacts. Explicit `OPENSHELL_INSTALL_METHOD=snap` supports only an unset version or `OPENSHELL_VERSION=dev`. +When snapd is available, the script installs the [snap](#snap) package for the latest stable release or the rolling `dev` release. Otherwise, it installs a Debian package on Debian and Ubuntu or RPM packages on Fedora and RHEL. Prereleases and explicit release tags use native packages. Explicit `OPENSHELL_INSTALL_METHOD=snap` supports only an unset version or `OPENSHELL_VERSION=dev`. Set `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm` to select a native package explicitly. Native Linux packages require glibc 2.28 or newer. @@ -123,7 +123,7 @@ sudo loginctl enable-linger $USER The snap requires Docker Engine installed from your distribution or Docker's package repository. The Docker snap is not compatible. To use Podman or the VM driver instead, select a native package with `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm`. -The snap does not migrate existing Debian, RPM, or Homebrew installs. If the script detects an existing native installation while selecting the snap, it stops before making changes. To update the existing native installation instead, rerun it with `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm`. To migrate, remove the existing installation after backing up any state you need, then rerun the script with `OPENSHELL_ACK_BREAKING_UPGRADE=1`, or install the snap directly: +The snap does not migrate existing Debian, RPM, or Homebrew installs. If the script detects an existing native installation while selecting the snap, it stops before making changes. To keep the native installation, rerun it with `OPENSHELL_INSTALL_METHOD=deb` or `OPENSHELL_INSTALL_METHOD=rpm`. To migrate, back up any state you need, remove the native installation, and rerun the script. Set `OPENSHELL_ACK_BREAKING_UPGRADE=1` only if a detected native `openshell` binary remains after cleanup. You can also install the snap directly: ```shell sudo snap install openshell diff --git a/install.sh b/install.sh index a356af2d25..f71b7e23e8 100755 --- a/install.sh +++ b/install.sh @@ -4,7 +4,7 @@ # # Install OpenShell from a GitHub release. # -# Linux automatically installs the snap when the snap command is available and +# Linux automatically installs the snap when snapd is available and # the version is unset or dev; exact releases and prereleases use native packages. # Apple Silicon macOS installs the generated Homebrew formula, so Homebrew owns # the binary layout and launchd service lifecycle. @@ -64,13 +64,13 @@ ENVIRONMENT VARIABLES: pre-v0.0.37 or non-snap installation. OPENSHELL_INSTALL_METHOD Linux package to install: snap, deb, or rpm. Unset - selects snap when available, otherwise deb or rpm. + selects snap when snapd is available, otherwise deb or rpm. NOTES: When OPENSHELL_VERSION is unset, this resolves the latest tagged release from ${GITHUB_URL}/releases/latest. - Linux installs the OpenShell snap when the snap command is available and + Linux installs the OpenShell snap when snapd is available and OPENSHELL_VERSION is unset or dev. Snap installs use latest/stable by default and latest/edge for dev. Explicit release tags and prereleases use the Debian package on amd64/arm64 or the RPM packages on x86_64/aarch64, @@ -87,6 +87,11 @@ has_cmd() { command -v "$1" >/dev/null 2>&1 } +snapd_available() { + has_cmd snap || return 1 + snap version 2>/dev/null | grep -Eq '^snapd[[:space:]]+[0-9]' +} + require_cmd() { if ! has_cmd "$1"; then error "'$1' is required" @@ -671,7 +676,7 @@ linux_package_method() { case "${OPENSHELL_VERSION:-}" in '' | dev) - if has_cmd snap; then + if snapd_available; then echo "snap" return 0 fi @@ -1450,6 +1455,9 @@ wait_for_user_snap_gateway_listener() { install_linux_snap() { require_cmd snap + snapd_available || error "snapd is not available; ensure snapd is running, then rerun this installer" + info "waiting for snapd initialization to complete..." + as_root snap wait system seed.loaded || error "snapd initialization did not complete" set_linux_target_runtime_dir if snap list openshell >/dev/null 2>&1; then diff --git a/tasks/scripts/test-install-sh.sh b/tasks/scripts/test-install-sh.sh index 9d61035b9b..bfb1563a06 100755 --- a/tasks/scripts/test-install-sh.sh +++ b/tasks/scripts/test-install-sh.sh @@ -100,8 +100,8 @@ assert_glibc_preflight_fails \ "OpenShell Linux packages require glibc >= 2.28; detected musl or unsupported libc." \ setup_ldd_musl -# snap_state: 0 = no snap command, 1 = snap command only, -# installed = the OpenShell snap is already installed. +# snap_state: 0 = no snap command, cli = snap command without a reachable snapd, +# ready = functional snapd, installed = functional snapd with OpenShell installed. assert_linux_package_method() { local name=$1 local install_method=$2 @@ -123,7 +123,18 @@ assert_linux_package_method() { *) return 1 ;; esac } - snap() { [ "$*" = "list openshell" ] && [ "$snap_state" = "installed" ]; } + snap() { + case "$1" in + version) + case "$snap_state" in + ready | installed) printf '%s\n' "snap 2.78" "snapd 2.78" ;; + *) return 1 ;; + esac + ;; + list) [ "$*" = "list openshell" ] && [ "$snap_state" = "installed" ] ;; + *) return 1 ;; + esac + } linux_package_method ) >"$out" actual="$(cat "$out")" @@ -133,25 +144,59 @@ assert_linux_package_method() { fi } -assert_linux_package_method "snap takes precedence over deb and rpm" "" "" 1 1 1 snap -assert_linux_package_method "snap takes precedence over rpm" "" "" 1 0 1 snap -assert_linux_package_method "dev uses snap" "" dev 1 1 1 snap -assert_linux_package_method "explicit snap" snap "" 1 1 1 snap -assert_linux_package_method "explicit snap with dev" snap dev 1 1 1 snap -assert_linux_package_method "explicit snap wins with pinned stable" snap v1.2.3 1 1 1 snap +assert_linux_package_method "snap takes precedence over deb and rpm" "" "" ready 1 1 snap +assert_linux_package_method "snap takes precedence over rpm" "" "" ready 0 1 snap +assert_linux_package_method "dev uses snap" "" dev ready 1 1 snap +assert_linux_package_method "explicit snap" snap "" cli 1 1 snap +assert_linux_package_method "explicit snap with dev" snap dev cli 1 1 snap +assert_linux_package_method "explicit snap wins with pinned stable" snap v1.2.3 cli 1 1 snap assert_linux_package_method "explicit deb" deb "" installed 0 1 deb -assert_linux_package_method "explicit rpm" rpm "" 1 1 1 rpm +assert_linux_package_method "explicit rpm" rpm "" ready 1 1 rpm assert_linux_package_method "existing snap install keeps refreshing" "" "" installed 1 1 snap assert_linux_package_method "existing snap install keeps refreshing dev" "" dev installed 1 1 snap assert_linux_package_method "pre uses deb despite existing snap" "" pre installed 1 1 deb -assert_linux_package_method "pre uses rpm despite snap" "" pre 1 0 1 rpm +assert_linux_package_method "pre uses rpm despite snap" "" pre ready 0 1 rpm assert_linux_package_method "numbered prerelease uses deb despite existing snap" "" v0.1.0-pre.3 installed 1 1 deb -assert_linux_package_method "pinned stable uses deb despite snap" "" v1.2.3 1 1 1 deb +assert_linux_package_method "pinned stable uses deb despite snap" "" v1.2.3 ready 1 1 deb assert_linux_package_method "pinned stable uses rpm despite existing snap" "" v1.2.3 installed 0 1 rpm assert_linux_package_method "deb is selected without snap" "" "" 0 1 1 deb assert_linux_package_method "dev uses deb without snap" "" dev 0 1 1 deb +assert_linux_package_method "deb is selected when snapd is unreachable" "" "" cli 1 1 deb +assert_linux_package_method "dev uses rpm when snapd is unreachable" "" dev cli 0 1 rpm assert_linux_package_method "rpm is selected without snap or deb" "" "" 0 0 1 rpm +if ( + has_cmd() { [ "$1" = snap ]; } + snap() { return 1; } + install_linux_snap +) >"$out" 2>"$err"; then + echo "FAIL: explicit snap install should reject unreachable snapd" >&2 + exit 1 +fi +if ! grep -Fq "snapd is not available" "$err"; then + echo "FAIL: unreachable snapd rejection was not explained" >&2 + cat "$err" >&2 + exit 1 +fi + +if ( + has_cmd() { [ "$1" = snap ]; } + snap() { + [ "${1:-}" = version ] && printf '%s\n' "snap 2.78" "snapd 2.78" + } + as_root() { return 1; } + info() { :; } + install_linux_snap +) >"$out" 2>"$err"; then + echo "FAIL: explicit snap install should reject failed snapd initialization" >&2 + exit 1 +fi +if ! grep -Fq "snapd initialization did not complete" "$err"; then + echo "FAIL: failed snapd initialization was not explained" >&2 + cat "$err" >&2 + exit 1 +fi + if (OPENSHELL_INSTALL_METHOD=flatpak linux_package_method) >"$out" 2>"$err"; then echo "FAIL: unsupported OPENSHELL_INSTALL_METHOD should be rejected" >&2 exit 1 @@ -285,6 +330,7 @@ assert_snap_install_flow() { } snap() { case "${1:-}:${2:-}" in + version:) printf '%s\n' "snap 2.78" "snapd 2.78" ;; list:docker) return 1 ;; list:openshell) [ "$openshell_present" = "1" ] ;; get:openshell) printf '%s\n' system ;; @@ -342,6 +388,7 @@ assert_snap_user_refresh_flow() { } snap() { case "${1:-}:${2:-}" in + version:) printf '%s\n' "snap 2.78" "snapd 2.78" ;; list:docker) return 1 ;; list:openshell) return 0 ;; get:openshell) printf '%s\n' user ;; @@ -368,7 +415,8 @@ assert_snap_user_refresh_flow() { install_linux_snap ) >"$out" calls="$(cat "$out")" - expected="wait:user-docker + expected="root:snap wait system seed.loaded +wait:user-docker root:snap refresh openshell --channel=latest/stable root:snap restart openshell.user-gateway wait:user-gateway-listener @@ -384,7 +432,8 @@ wait:gateway-status" assert_snap_install_flow \ "existing Docker is reused" \ 1 0 "" \ - "wait:user-docker + "root:snap wait system seed.loaded +wait:user-docker root:snap install openshell --channel=latest/stable wait:user-gateway-listener register:user-gateway @@ -395,7 +444,8 @@ assert_snap_user_refresh_flow assert_snap_install_flow \ "existing OpenShell snap is refreshed" \ 1 1 "" \ - "wait:docker + "root:snap wait system seed.loaded +wait:docker root:snap refresh openshell --channel=latest/stable root:snap restart openshell.system-gateway wait:system-gateway-listener @@ -412,6 +462,7 @@ if ( } snap() { case "${1:-}:${2:-}" in + version:) printf '%s\n' "snap 2.78" "snapd 2.78" ;; list:docker) return 1 ;; list:openshell) return 0 ;; get:openshell) printf '%s\n' disable ;; @@ -419,13 +470,11 @@ if ( esac } as_root() { - if [ "${1:-}:${2:-}" = snap:get ]; then - shift - snap "$@" - else - echo "FAIL: disabled mode reached root command: $*" >&2 - return 99 - fi + case "${1:-}:${2:-}" in + snap:wait) return 0 ;; + snap:get) shift; snap "$@" ;; + *) echo "FAIL: disabled mode reached root command: $*" >&2; return 99 ;; + esac } set_linux_target_runtime_dir() { :; } install_linux_snap @@ -458,14 +507,17 @@ assert_snap_install_rejected() { esac } snap() { - if [ "${1:-}:${2:-}" = list:docker ]; then - [ "$docker_snap_present" = "1" ] - else - echo "FAIL: ${name}: unexpected snap command: $*" >&2 - return 99 - fi + case "${1:-}:${2:-}" in + version:) printf '%s\n' "snap 2.78" "snapd 2.78" ;; + list:openshell) return 1 ;; + list:docker) [ "$docker_snap_present" = "1" ] ;; + *) echo "FAIL: ${name}: unexpected snap command: $*" >&2; return 99 ;; + esac } as_root() { + if [ "${1:-}:${2:-}" = snap:wait ]; then + return 0 + fi echo "FAIL: ${name}: installation reached root command: $*" >&2 return 99 }