diff --git a/.agents/skills/test-release-canary/SKILL.md b/.agents/skills/test-release-canary/SKILL.md index 15430d8610..1f6965873c 100644 --- a/.agents/skills/test-release-canary/SKILL.md +++ b/.agents/skills/test-release-canary/SKILL.md @@ -16,7 +16,7 @@ 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, reaches the Docker gateway, and creates, executes in, and deletes a sandbox, and verifies that the Docker snap is not installed. | +| `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. | | `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. | @@ -144,6 +144,7 @@ Loopback registration auto-derives the gateway name to `openshell` if `--name` i | Sandbox create or exec fails | Published sandbox and supervisor artifacts are missing, incompatible, or cannot establish the protected runtime channel. | Gateway logs plus Docker, Podman, VM, Snap, or Kubernetes runtime diagnostics for the job. | | `macos`/`ubuntu-deb`/`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_COMPUTE_DRIVER` env in the "Ensure …" step. | | `ubuntu-snap-system-docker` fails during `install.sh` | System Docker was unavailable, the edge revision or automatic interfaces were unavailable, or the gateway did not become reachable. | Failure diagnostics dump system Docker, snap service/connection/change state, gateway and snapd journals, snap logs, and port 17670 listeners. | +| `ubuntu-snap-system-docker` fails during the prover checks | The prover artifact is missing or packaged for the wrong architecture, `openshell.prover` is not exposed or confined to read the test policies, or its solver linkage is not runnable. | The `Verify Snap installation` and `Check a policy boundary with the Snap prover` steps, plus `snap info openshell` and `snap connections openshell`. | | `ubuntu-snap-docker-preflight` unexpectedly succeeds | The installer no longer fails before installing the OpenShell snap when Docker is absent or supplied by the Docker snap. | Inspect `install.log`, `docker-snap.log`, `snap list`, and snapd changes. | | `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`. | diff --git a/.github/workflows/release-canary.yml b/.github/workflows/release-canary.yml index 69fd3b3e55..286d685672 100644 --- a/.github/workflows/release-canary.yml +++ b/.github/workflows/release-canary.yml @@ -233,12 +233,35 @@ jobs: docker info sudo snap connections openshell | grep -E '^docker +openshell:docker +:docker +' openshell --version + openshell.prover --version sudo snap services openshell sudo journalctl -b -u snap.openshell.gateway.service --no-pager | grep -F "mTLS user authentication enabled" openshell gateway list | grep -F "https://127.0.0.1:17670" openshell status + - name: Check a policy boundary with the Snap prover + run: | + set -euo pipefail + prover_dir=$(mktemp -d "$HOME/openshell-prover-canary.XXXXXX") + trap 'rm -rf "$prover_dir"' EXIT + cat >"$prover_dir/boundary.yaml" <<'EOF' + version: 1 + filesystem_policy: + read_only: + - /usr + - /etc + EOF + cat >"$prover_dir/candidate.yaml" <<'EOF' + version: 1 + filesystem_policy: + read_only: + - /usr + EOF + result=$(openshell.prover check "$prover_dir/candidate.yaml" \ + --boundary "$prover_dir/boundary.yaml") + grep -q '^result: within_boundary$' <<<"$result" + - name: Create and exercise a sandbox run: | set -euo pipefail diff --git a/.github/workflows/snap-package.yml b/.github/workflows/snap-package.yml index 7eb78d3a27..f5eaa61e9d 100644 --- a/.github/workflows/snap-package.yml +++ b/.github/workflows/snap-package.yml @@ -89,6 +89,12 @@ jobs: name: openshell-${{ matrix.rust_arch }}-unknown-linux-musl path: prebuilt/cli + - name: Download prebuilt prover binary + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: openshell-prover-${{ matrix.rust_arch }}-unknown-linux-musl + path: prebuilt/prover + - name: Download prebuilt gateway binary uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -105,6 +111,7 @@ jobs: run: | set -euo pipefail chmod +x prebuilt/cli/openshell + chmod +x prebuilt/prover/openshell-prover chmod +x prebuilt/gateway/openshell-gateway chmod +x prebuilt/sandbox/openshell-sandbox ls -laR prebuilt/ @@ -115,6 +122,7 @@ jobs: mkdir -p snap/prebuilt cp prebuilt/cli/openshell snap/prebuilt/openshell + cp prebuilt/prover/openshell-prover snap/prebuilt/openshell-prover cp prebuilt/gateway/openshell-gateway snap/prebuilt/openshell-gateway cp prebuilt/sandbox/openshell-sandbox snap/prebuilt/openshell-sandbox diff --git a/CI.md b/CI.md index c5a19e1f08..baacc243ff 100644 --- a/CI.md +++ b/CI.md @@ -491,7 +491,7 @@ These workflows run after merge to publish dev/tagged artifacts and verify them. |---|---| | `.github/workflows/release-dev.yml` | Publishes the rolling `dev` build on every push to `main`. Builds gateway, sandbox, and supervisor images and binaries, packages, wheels, and pushes the Helm chart as `oci://ghcr.io/nvidia/openshell/helm-chart:0.0.0-dev` (plus an immutable `0.0.0-dev.` pin). Also dispatchable manually. | | `.github/workflows/release-tag.yml` | Publishes tagged stable releases and manually dispatched pre-releases. Its automatic tag trigger excludes `-pre.*`. Protobuf, security, and integration failures do not block pre-release artifact publication. Stable publication requires the currently implemented qualification profile to pass; the summary identifies the remaining RFC 0014 coverage. | -| `.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 lanes verify a compatible system Docker lifecycle and `ubuntu-snap-docker-preflight` tests fail-fast behavior when Docker is absent or supplied by the Docker snap. 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 lanes verify a compatible system Docker lifecycle and `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/docs/about/installation.mdx b/docs/about/installation.mdx index a279bb3510..957c4e2316 100644 --- a/docs/about/installation.mdx +++ b/docs/about/installation.mdx @@ -106,11 +106,16 @@ 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. +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: + ```shell sudo snap install openshell ``` -The snap does not migrate existing Debian, RPM, or Homebrew installs. Remove any existing installation first, then rerun the script with `OPENSHELL_INSTALL_METHOD=snap OPENSHELL_ACK_BREAKING_UPGRADE=1`. +The snap installs the standalone policy prover as `openshell.prover`. The +`openshell-prover` alias requires Snap Store approval and may not be available. +The prover reads local policy files through the `home` interface and does not +connect to the gateway. The gateway runs as a system service at `https://127.0.0.1:17670` and reads `/var/snap/openshell/common/gateway.toml`. It requires a client certificate. The install script copies that certificate to the installing user's Snap state and registers the gateway automatically. If you installed with `sudo snap install openshell`, give each trusted user the certificate and register the gateway from that user's account: diff --git a/docs/about/support-matrix.mdx b/docs/about/support-matrix.mdx index 9cace1a708..4115854e8e 100644 --- a/docs/about/support-matrix.mdx +++ b/docs/about/support-matrix.mdx @@ -106,6 +106,11 @@ OpenShell publishes standalone `openshell-prover` release assets for manual down These artifacts are attached to GitHub releases. The Linux binaries are static and do not require glibc. All prover archives include the required solver linkage. +The Debian, RPM, Homebrew, and Snap packages also include the prover. Debian, +RPM, and Homebrew installations expose it as `openshell-prover`; use +`openshell.prover` with the Snap. The `openshell-prover` Snap alias requires +Store approval and may not be available. + ## Runtimes The gateway can manage sandboxes through several runtimes. diff --git a/docs/how-it-works/policies/prover.mdx b/docs/how-it-works/policies/prover.mdx index 95b48dcf15..acde16f577 100644 --- a/docs/how-it-works/policies/prover.mdx +++ b/docs/how-it-works/policies/prover.mdx @@ -36,6 +36,16 @@ contain access that the proposal risk check would flag. This page covers the boundary check. To learn about the proposal risk check, refer to [Policy Advisor](/how-it-works/policies/advisor). +For Snap installations, replace `openshell-prover` in these examples with +`openshell.prover`. The `openshell-prover` Snap alias requires Store approval +and may not be available. + +The prover remains independent of the gateway at runtime. If you only need the +standalone binary, use the artifacts listed in the +[Support Matrix](/about/support-matrix#standalone-policy-prover). These +artifacts and `openshell-prover-checksums-sha256.txt` are attached to +[OpenShell releases](https://github.com/NVIDIA/OpenShell/releases). + ## Run a Boundary Check A boundary check compares the policy you are testing, called the candidate, with @@ -50,12 +60,10 @@ or MCP rules, the prover reports that it cannot check the policy instead of ignoring those rules. [What the Boundary Check Covers](#what-the-boundary-check-covers) describes each part and its limits. -The Homebrew, Debian, and RPM packages install the `openshell-prover` CLI. The -snap package does not include it, so on a snap installation, download the -`openshell-prover` archive for your platform from the [OpenShell -releases](https://github.com/NVIDIA/OpenShell/releases). The CLI reads policy -files on your machine, does not need a gateway, and does not apply or approve -policies. +The Homebrew, Debian, RPM, and Snap packages install the prover. Homebrew, +Debian, and RPM expose it as `openshell-prover`; use `openshell.prover` with the +Snap. The CLI reads policy files on your machine, does not need a gateway, and +does not apply or approve policies. Create `boundary.yaml`, a boundary that allows reading `/usr` and `/etc`: diff --git a/nix/test-guest/scripts/snap-gateway-repro.sh b/nix/test-guest/scripts/snap-gateway-repro.sh index 43b7f3949c..8dd09fc206 100755 --- a/nix/test-guest/scripts/snap-gateway-repro.sh +++ b/nix/test-guest/scripts/snap-gateway-repro.sh @@ -127,20 +127,39 @@ for attempt in $(seq 1 "${attempts}"); do fi sandbox="snap-${attempt}-$$" + prover_dir=$(mktemp -d "$HOME/openshell-prover-repro.XXXXXX") + cat >"${prover_dir}/boundary.yaml" <<'EOF' +version: 1 +filesystem_policy: + read_only: + - /usr + - /etc +EOF + cat >"${prover_dir}/candidate.yaml" <<'EOF' +version: 1 +filesystem_policy: + read_only: + - /usr +EOF if ! OPENSHELL_INSTALL_METHOD=snap OPENSHELL_VERSION=dev sh "${install_script}" || ! sudo snap list openshell >/dev/null || ! snap info openshell | grep -Eq '^tracking: +latest/edge$' || ! docker_is_ready || ! sudo snap connections openshell | grep -Eq '^docker +openshell:docker +:docker +' || ! /snap/bin/openshell status || + ! /snap/bin/openshell.prover --version || + ! /snap/bin/openshell.prover check "${prover_dir}/candidate.yaml" \ + --boundary "${prover_dir}/boundary.yaml" | grep -q '^result: within_boundary$' || ! /snap/bin/openshell sandbox create --name "${sandbox}" --detach || ! /snap/bin/openshell sandbox exec --name "${sandbox}" --no-tty -- true || ! /snap/bin/openshell sandbox delete "${sandbox}"; then echo "install.sh Snap reproduction failed" >&2 diagnostics "${attempt}" failures=$((failures + 1)) + rm -rf "${prover_dir}" continue fi + rm -rf "${prover_dir}" if sudo snap list docker >/dev/null 2>&1; then echo "install.sh unexpectedly installed the Docker snap" >&2 diff --git a/snapcraft.yaml b/snapcraft.yaml index c05011e1d9..7a7340d857 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -12,7 +12,8 @@ description: | profile-backed model-provider access. The OpenShell snap ships a CLI (`openshell`), a terminal UI - (`openshell.term`), and a managed gateway daemon (`openshell.gateway`). + (`openshell.term`), a standalone policy prover (`openshell.prover`), and a + managed gateway daemon (`openshell.gateway`). **Setup instructions** @@ -85,6 +86,12 @@ apps: - home - network - system-observe + prover: + command: bin/openshell-prover + aliases: + - openshell-prover + plugs: + - home gateway: command: bin/openshell-gateway-wrapper daemon: simple @@ -120,7 +127,7 @@ parts: set -euo pipefail MISSING=() - for bin in openshell openshell-gateway openshell-sandbox openshell-gateway-wrapper; do + for bin in openshell openshell-prover openshell-gateway openshell-sandbox openshell-gateway-wrapper; do if [ ! -f "$CRAFT_PART_SRC/$bin" ]; then MISSING+=("$bin") fi @@ -138,6 +145,8 @@ parts: install -D -m 0755 "$CRAFT_PART_SRC/openshell" \ "$CRAFT_PART_INSTALL/bin/openshell" + install -D -m 0755 "$CRAFT_PART_SRC/openshell-prover" \ + "$CRAFT_PART_INSTALL/bin/openshell-prover" install -D -m 0755 "$CRAFT_PART_SRC/openshell-gateway" \ "$CRAFT_PART_INSTALL/bin/openshell-gateway" install -D -m 0755 "$CRAFT_PART_SRC/openshell-sandbox" \ diff --git a/tasks/scripts/test-packaging-assets.sh b/tasks/scripts/test-packaging-assets.sh index b9ade5eb05..1d5a487a76 100755 --- a/tasks/scripts/test-packaging-assets.sh +++ b/tasks/scripts/test-packaging-assets.sh @@ -80,6 +80,7 @@ assert_not_contains "$spec" '%%S/openshell/tls' # Schema-v2 package startup wiring. snap_wrapper="${ROOT}/tasks/scripts/snap-gateway-wrapper.sh" snapcraft="${ROOT}/snapcraft.yaml" +snap_workflow="${ROOT}/.github/workflows/snap-package.yml" snap_install_docs="${ROOT}/docs/about/installation.mdx" snap_canary="${ROOT}/.github/workflows/release-canary.yml" snap_repro="${ROOT}/nix/test-guest/scripts/snap-gateway-repro.sh" @@ -87,6 +88,7 @@ snap_post_refresh_hook="${ROOT}/snap/hooks/post-refresh" package_deb="${ROOT}/tasks/scripts/package-deb.sh" assert_file_exists "$snap_wrapper" assert_file_exists "$snapcraft" +assert_file_exists "$snap_workflow" assert_file_exists "$snap_install_docs" assert_file_exists "$snap_canary" assert_file_exists "$snap_repro" @@ -131,18 +133,38 @@ if [[ ! -x "$snap_post_refresh_hook" ]]; then fi assert_not_contains "$ROOT/tasks/scripts/snap-gateway-wrapper.sh" 'OPENSHELL_DISABLE_TLS' bash "$ROOT/tasks/scripts/test-snap-post-refresh-hook.sh" "$snap_post_refresh_hook" +assert_contains "$snap_workflow" 'name: openshell-prover-${{ matrix.rust_arch }}-unknown-linux-musl' +assert_contains "$snap_workflow" 'chmod +x prebuilt/prover/openshell-prover' +assert_contains "$snap_workflow" 'cp prebuilt/prover/openshell-prover snap/prebuilt/openshell-prover' +assert_contains "$snapcraft" 'for bin in openshell openshell-prover openshell-gateway openshell-sandbox openshell-gateway-wrapper; do' +assert_contains "$snapcraft" '"$CRAFT_PART_INSTALL/bin/openshell-prover"' +if ! awk ' + /^ prover:$/ { in_prover = 1; next } + in_prover && /^ [[:alnum:]_-]+:$/ { finished = 1; exit } + in_prover && /command: bin\/openshell-prover/ { command = 1 } + in_prover && /- openshell-prover/ { alias = 1 } + in_prover && /^ plugs:$/ { in_plugs = 1; next } + in_prover && in_plugs && /^ - / { + plug_count++ + if ($0 == " - home") home = 1 + } + END { exit !(in_prover && finished && command && alias && home && plug_count == 1) } +' "$snapcraft"; then + echo "FAIL: Snap prover app must expose the openshell-prover alias with only home access" >&2 + exit 1 +fi assert_not_contains "$snap_install_docs" "snap connect openshell:home" assert_not_contains "$snap_install_docs" "snap connect openshell:network" assert_not_contains "$snap_install_docs" "snap connect openshell:network-bind" assert_contains "$snap_install_docs" "snap connect openshell:docker :docker" assert_contains "$snap_install_docs" "systemctl reset-failed snap.openshell.gateway.service" assert_contains "$snap_install_docs" "snap restart openshell.gateway" -assert_contains "$snap_install_docs" "Snap refreshes keep the running gateway process active" -assert_contains "$snap_install_docs" "install script refreshes and restarts the gateway automatically" 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_contains "$snap_repro" 'OPENSHELL_INSTALL_METHOD=snap OPENSHELL_VERSION=dev sh "${install_script}"' +assert_contains "$snap_repro" "/snap/bin/openshell.prover check" assert_contains "$snap_repro" "system-docker" assert_contains "$snap_repro" "missing-docker" assert_contains "$snap_repro" "docker-snap"