diff --git a/.agents/skills/build-from-issue/SKILL.md b/.agents/skills/build-from-issue/SKILL.md index 89d9e04215..4ec54e61a4 100644 --- a/.agents/skills/build-from-issue/SKILL.md +++ b/.agents/skills/build-from-issue/SKILL.md @@ -177,7 +177,7 @@ In the prompt, instruct the reviewer to: - **Medium**: Multiple files/components, some design decisions, but well-scoped - **High**: Cross-cutting changes, architectural decisions needed, significant unknowns 8. Call out risks, unknowns, and decisions that need stakeholder input. -9. Assess **gateway config documentation impact** — if the change adds, removes, renames, or changes defaults for gateway TOML keys or driver-specific config options, the plan must include an update to `docs/reference/gateway-config.mdx`. If the change is surfaced through Helm or a compute-driver overview, also include `docs/reference/sandbox-compute-drivers.mdx` or the relevant deployment docs. +9. Assess **gateway config documentation impact** — if the change adds, removes, renames, or changes defaults for gateway TOML keys or driver-specific config options, the plan must include an update to `docs/how-it-works/gateways/configuration.mdx`. If the change is surfaced through Helm or a compute-driver overview, also include `docs/how-it-works/sandboxes/runtimes.mdx` or the relevant deployment docs. 10. Assess **LSM compatibility** — if the change touches process identity, `/proc` filesystem access, binary execution, or inter-process visibility, flag whether it will behave differently on hosts running SELinux (enforcing) or AppArmor. In particular, tests that fork+exec into system binaries will fail on SELinux-enforcing hosts due to cross-label `/proc//exe` access restrictions. Perform this investigation against the current branch and current product behavior. If the issue contains earlier diagnostics, verify them rather than relying on them. @@ -474,9 +474,9 @@ behavior or subsystem that changed. If the implementation changes gateway TOML parsing, `[openshell.gateway]` fields, `[openshell.drivers.]` fields, driver config defaults, or Helm -rendering of `gateway.toml`, update `docs/reference/gateway-config.mdx` in the +rendering of `gateway.toml`, update `docs/how-it-works/gateways/configuration.mdx` in the same branch. If the change affects user-facing compute-driver setup, also -update `docs/reference/sandbox-compute-drivers.mdx` or the relevant deployment +update `docs/how-it-works/sandboxes/runtimes.mdx` or the relevant deployment page. Use the `sync-agent-infra` skill's maintenance map to identify related skill updates when the implementation changes behavior, commands, or development workflows. Run its full consistency check when the implementation adds, removes, or renames skills or crates; changes workflow relationships or skill coverage; modifies issue or PR templates; or changes agent cross-references. Fix any drift before committing. diff --git a/.agents/skills/create-github-pr/SKILL.md b/.agents/skills/create-github-pr/SKILL.md index 5eafc91f9b..dd0463df8b 100644 --- a/.agents/skills/create-github-pr/SKILL.md +++ b/.agents/skills/create-github-pr/SKILL.md @@ -21,9 +21,9 @@ Create pull requests on GitHub using the `gh` CLI. If the branch changes gateway TOML parsing, `[openshell.gateway]` fields, `[openshell.drivers.]` fields, driver config defaults, or Helm rendering -of `gateway.toml`, verify that `docs/reference/gateway-config.mdx` is updated +of `gateway.toml`, verify that `docs/how-it-works/gateways/configuration.mdx` is updated in the same branch. If the change affects user-facing compute-driver setup, -also update `docs/reference/sandbox-compute-drivers.mdx` or the relevant +also update `docs/how-it-works/sandboxes/runtimes.mdx` or the relevant deployment docs. ### Check Agent Infrastructure diff --git a/.agents/skills/create-spike/SKILL.md b/.agents/skills/create-spike/SKILL.md index baafd173da..7e24cc8115 100644 --- a/.agents/skills/create-spike/SKILL.md +++ b/.agents/skills/create-spike/SKILL.md @@ -93,7 +93,7 @@ The prompt to the reviewer **must** instruct it to: 9. **Check architecture docs** in the `architecture/` directory for relevant documentation about the affected subsystems. -10. **Assess gateway config documentation impact.** If the change would add, remove, rename, or change defaults for gateway TOML keys or driver-specific config options, call out that `docs/reference/gateway-config.mdx` must be updated. If the change is surfaced through Helm or compute-driver setup docs, call out the relevant deployment or compute-driver docs too. +10. **Assess gateway config documentation impact.** If the change would add, remove, rename, or change defaults for gateway TOML keys or driver-specific config options, call out that `docs/how-it-works/gateways/configuration.mdx` must be updated. If the change is surfaced through Helm or compute-driver setup docs, call out the relevant deployment or compute-driver docs too. 11. **Assess Linux Security Module (LSM) impact.** If the change involves process identity, `/proc` filesystem access, file labeling, binary execution, or inter-process visibility, call out whether it will behave differently on hosts running SELinux (enforcing) or AppArmor. For example: reading `/proc//exe` across an SELinux domain boundary returns ENOENT, not EACCES. Tests that fork+exec into system binaries (different SELinux label) will fail on enforcing hosts. Flag any LSM-sensitive code paths and recommend mitigations. diff --git a/.agents/skills/update-docs/SKILL.md b/.agents/skills/update-docs/SKILL.md index 86edcd2738..99feaefc54 100644 --- a/.agents/skills/update-docs/SKILL.md +++ b/.agents/skills/update-docs/SKILL.md @@ -50,20 +50,20 @@ For each relevant commit, determine which doc page(s) it affects. Use this mappi | Code area | Likely doc page(s) | |---|---| -| `crates/openshell-cli/` (gateway commands) | `docs/sandboxes/manage-gateways.mdx` | -| `crates/openshell-cli/` (sandbox commands) | `docs/sandboxes/manage-sandboxes.mdx` | -| `crates/openshell-cli/` (provider commands) | `docs/sandboxes/manage-providers.mdx` | +| `crates/openshell-cli/` (gateway commands) | `docs/how-it-works/gateways/overview.mdx` | +| `crates/openshell-cli/` (sandbox commands) | `docs/how-it-works/sandboxes/overview.mdx` | +| `crates/openshell-cli/` (provider commands) | `docs/how-it-works/providers/overview.mdx` | | `crates/openshell-cli/` (new top-level command) | May need a new page or `docs/reference/` entry | -| `crates/openshell-server/src/config_file.rs` or gateway TOML parsing | `docs/reference/gateway-config.mdx` | -| `crates/openshell-server/src/cli.rs` gateway config merge/default behavior | `docs/reference/gateway-config.mdx` | -| `crates/openshell-driver-*/` config structs or driver defaults | `docs/reference/gateway-config.mdx`, `docs/reference/sandbox-compute-drivers.mdx` | -| `deploy/helm/openshell/templates/gateway-config.yaml` | `docs/reference/gateway-config.mdx`, `docs/reference/sandbox-compute-drivers.mdx`, Helm docs if values change | -| Proxy or policy code | `docs/sandboxes/policies.mdx`, `docs/reference/policy-schema.mdx` | +| `crates/openshell-server/src/config_file.rs` or gateway TOML parsing | `docs/how-it-works/gateways/configuration.mdx` | +| `crates/openshell-server/src/cli.rs` gateway config merge/default behavior | `docs/how-it-works/gateways/configuration.mdx` | +| `crates/openshell-driver-*/` config structs or driver defaults | `docs/how-it-works/gateways/configuration.mdx`, `docs/how-it-works/sandboxes/runtimes.mdx` | +| `deploy/helm/openshell/templates/gateway-config.yaml` | `docs/how-it-works/gateways/configuration.mdx`, `docs/how-it-works/sandboxes/runtimes.mdx`, Helm docs if values change | +| Proxy or policy code | `docs/how-it-works/policies/overview.mdx`, `docs/how-it-works/policies/schema.mdx` | | Inference code | `docs/inference/configure.mdx` | | `python/` (SDK changes) | `docs/reference/` or `docs/get-started/quickstart.mdx` | | `proto/` (API changes) | `docs/reference/` | -| `deploy/` (Dockerfile, Helm) | `docs/sandboxes/manage-gateways.mdx`, `docs/about/architecture.mdx` | -| Sandbox image behavior | `docs/sandboxes/manage-sandboxes.mdx` | +| `deploy/` (Dockerfile, Helm) | `docs/how-it-works/gateways/overview.mdx`, `docs/about/architecture.mdx` | +| Sandbox image behavior | `docs/how-it-works/sandboxes/overview.mdx` | If a commit does not map to any existing page but introduces a user-visible concept, flag it as needing a new page. @@ -135,8 +135,8 @@ After drafting all updates, present a summary to the user: ## Doc Updates from Commits ### Updated pages -- `docs/sandboxes/manage-gateways.mdx`: Added `--gpu` flag documentation (from commit abc1234). -- `docs/reference/policy-schema.mdx`: Updated network policy schema for new `tls_inspect` field (from commit def5678). +- `docs/how-it-works/gateways/overview.mdx`: Added `--gpu` flag documentation (from commit abc1234). +- `docs/how-it-works/policies/schema.mdx`: Updated network policy schema for new `tls_inspect` field (from commit def5678). ### New pages needed - None (or list any new pages created). diff --git a/AGENTS.md b/AGENTS.md index b1a0ffeb60..0ec8027da8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -266,7 +266,7 @@ When behavior, commands, or development workflows change, review the related age - When making changes, update the relevant documentation in the `architecture/` directory. - When changes affect user-facing behavior, update the relevant published docs pages under `docs/` and navigation in `docs/index.yml`. -- When changing gateway TOML fields, driver-specific config options, config defaults, or Helm rendering of `gateway.toml`, update `docs/reference/gateway-config.mdx` in the same branch. +- When changing gateway TOML fields, driver-specific config options, config defaults, or Helm rendering of `gateway.toml`, update `docs/how-it-works/gateways/configuration.mdx` in the same branch. - `fern/` contains the Fern site config, components, preview workflow inputs, publish settings, and publishing documentation in `fern/README.md`. - Follow the docs style guide in [docs/CONTRIBUTING.mdx](docs/CONTRIBUTING.mdx): active voice, minimal formatting, no filler introductions, `shell` fences for copyable commands, and no duplicate body H1. - Fern PR previews run through `.github/workflows/branch-docs.yml`. Release Dev publishes `dev`, and Release Tag publishes an immutable stable version plus `latest`. Both production paths call `.github/workflows/sync-docs.yml` once. diff --git a/README.md b/README.md index fd9b894ec7..3989aedbd3 100644 --- a/README.md +++ b/README.md @@ -280,11 +280,11 @@ Agent implementation is human-directed: a user may request a phase directly, or - [Full Documentation](https://docs.nvidia.com/openshell/latest/index.html) — overview, architecture, tutorials, and reference - [Run Your First Agent](https://docs.nvidia.com/openshell/latest/about/run-an-agent) — prepare an image, attach providers, and launch an agent -- [GitHub Sandbox Tutorial](https://docs.nvidia.com/openshell/latest/get-started/tutorials/github-sandbox) — end-to-end scoped GitHub repo access +- [GitHub Sandbox Tutorial](https://docs.nvidia.com/openshell/latest/tutorials/github-sandbox) — end-to-end scoped GitHub repo access - [Architecture](https://github.com/NVIDIA/OpenShell/tree/main/architecture) — detailed architecture docs and design decisions - [Roadmap](https://github.com/orgs/NVIDIA/projects/233) — planned work and project priorities - [RFC Board](https://github.com/orgs/NVIDIA/projects/233/views/6) — RFC proposals tracked on the OpenShell Roadmap with the `rfc` label -- [Support Matrix](https://docs.nvidia.com/openshell/latest/reference/support-matrix) — platforms, versions, and kernel requirements +- [Support Matrix](https://docs.nvidia.com/openshell/latest/about/support-matrix) — platforms, versions, and kernel requirements - [Brev Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3Ap3tL55zq4a8kew1AuW0FpSLsg) — try OpenShell on cloud compute without local setup - [Agent Instructions](AGENTS.md) — system prompt and workflow documentation for agent contributors diff --git a/architecture/gateway.md b/architecture/gateway.md index 19ba751e36..45cb5efd70 100644 --- a/architecture/gateway.md +++ b/architecture/gateway.md @@ -1217,7 +1217,7 @@ Gateway CLI flag > gateway OPENSHELL_* env var > TOML file > built-in defa The TOML file is opt-in via `--config ` / `OPENSHELL_GATEWAY_CONFIG`. Driver implementation settings live exclusively in TOML driver tables. The selector is the singular `[openshell.gateway] compute_driver`; legacy -`compute_drivers` lists are rejected. See `docs/reference/gateway-config.mdx` +`compute_drivers` lists are rejected. See `docs/how-it-works/gateways/configuration.mdx` for worked per-driver examples and RFC 0003 for the full schema. Each installation has an operator-assigned gateway name. Configure it with diff --git a/architecture/security-policy.md b/architecture/security-policy.md index 07dc57cdda..36a919573a 100644 --- a/architecture/security-policy.md +++ b/architecture/security-policy.md @@ -6,7 +6,7 @@ policy proxy. The gateway stores and delivers policy, but it does not make per-request egress decisions. For the field-by-field YAML reference, use -[Policy Schema Reference](../docs/reference/policy-schema.mdx). +[Policy Schema Reference](../docs/how-it-works/policies/schema.mdx). ## Policy Areas @@ -434,7 +434,7 @@ reported modeled domains. See the `openshell-prover` crate README for the supported construction and matching patterns. This containment operation is separate from the proposal-risk queries below. -See the [standalone policy prover documentation](../docs/reference/policy-prover.mdx) +See the [standalone policy prover documentation](../docs/how-it-works/policies/prover.mdx) for installation, command behavior, model limitations, evidence, and exit codes. ## What the proposal prover decides diff --git a/crates/openshell-cli/src/commands/common.rs b/crates/openshell-cli/src/commands/common.rs index 8eb7de2756..49fd66a9a8 100644 --- a/crates/openshell-cli/src/commands/common.rs +++ b/crates/openshell-cli/src/commands/common.rs @@ -22,7 +22,8 @@ use std::io::IsTerminal; use std::process::Command; use std::time::{Duration, Instant}; -const DOCS_PROVIDERS_URL: &str = "https://docs.nvidia.com/openshell/latest/sandboxes/providers-v2"; +const DOCS_PROVIDERS_URL: &str = + "https://docs.nvidia.com/openshell/latest/how-it-works/providers/overview"; // --------------------------------------------------------------------------- // View types diff --git a/crates/openshell-driver-docker/README.md b/crates/openshell-driver-docker/README.md index 096181a69f..a25c455eea 100644 --- a/crates/openshell-driver-docker/README.md +++ b/crates/openshell-driver-docker/README.md @@ -19,7 +19,7 @@ Caller driver config is disabled by default. Existing volumes require administrator-controlled approval labels; raw bind mounts have no supported label resolver and are denied under enforcement. GPU devices are temporarily exempt. Inspect labels again before launch, restart, and during reconciliation. -See [resource admission configuration](../../docs/reference/gateway-config.mdx#external-resource-admission). +See [resource admission configuration](../../docs/how-it-works/gateways/configuration.mdx#external-resource-admission). The driver creates two containers for each sandbox: diff --git a/crates/openshell-driver-kubernetes/README.md b/crates/openshell-driver-kubernetes/README.md index a71fa55d0a..215a7b21e1 100644 --- a/crates/openshell-driver-kubernetes/README.md +++ b/crates/openshell-driver-kubernetes/README.md @@ -8,7 +8,7 @@ before restart and scheduling-gate release. GPU devices are temporarily exempt. Image-pull Secrets are operator-selected gateway configuration rather than caller attachments. Managed mode stages an immutable copy for each sandbox runtime generation. -See [resource admission configuration](../../docs/reference/gateway-config.mdx#external-resource-admission). +See [resource admission configuration](../../docs/how-it-works/gateways/configuration.mdx#external-resource-admission). The driver uses the Kubernetes API to create, delete, fetch, and watch sandbox custom resources. It runs in-process with the gateway server and supports three diff --git a/crates/openshell-driver-kubernetes/src/config.rs b/crates/openshell-driver-kubernetes/src/config.rs index 40bcdc8422..d454014708 100644 --- a/crates/openshell-driver-kubernetes/src/config.rs +++ b/crates/openshell-driver-kubernetes/src/config.rs @@ -847,7 +847,7 @@ mod tests { #[test] fn published_kubernetes_example_is_valid_toml() { - let docs = include_str!("../../../docs/reference/gateway-config.mdx"); + let docs = include_str!("../../../docs/how-it-works/gateways/configuration.mdx"); let section = docs .split_once("### Kubernetes") .expect("Kubernetes documentation section") diff --git a/crates/openshell-driver-mxc/README.md b/crates/openshell-driver-mxc/README.md index b4ee82abb2..e5276ef4fe 100644 --- a/crates/openshell-driver-mxc/README.md +++ b/crates/openshell-driver-mxc/README.md @@ -7,7 +7,7 @@ OpenShell compute driver backed by **Microsoft MXC** (`wxc-exec`) on Windows. Caller driver config is disabled by default, so command-based MXC workflows need explicit administrator opt-in. Host filesystem grants have no trusted label resolver and are rejected while resource admission is enabled. -See [resource admission configuration](../../docs/reference/gateway-config.mdx#external-resource-admission) +See [resource admission configuration](../../docs/how-it-works/gateways/configuration.mdx#external-resource-admission) for the independent controls and the security consequences of opting out. This driver implements the gateway's ordinary in-process `ComputeDriver` diff --git a/crates/openshell-driver-podman/README.md b/crates/openshell-driver-podman/README.md index 5147d78a51..133326a0ec 100644 --- a/crates/openshell-driver-podman/README.md +++ b/crates/openshell-driver-podman/README.md @@ -18,7 +18,7 @@ administrator-controlled approval labels; bind and supplemental image mounts are denied under enforcement. Private-volume names alone do not prove ownership. GPU devices are temporarily exempt. Admission runs before launch, restart, and periodically for running workloads. -See [resource admission configuration](../../docs/reference/gateway-config.mdx#external-resource-admission). +See [resource admission configuration](../../docs/how-it-works/gateways/configuration.mdx#external-resource-admission). | Property | Workload | Supervisor | |---|---|---| @@ -119,7 +119,7 @@ image mounts also require disabled admission. Driver JSON requires `allow_driver_config = true`. Reserved control paths and the workspace root cannot be replaced. User-owned volumes are never created or deleted. -See [gateway configuration](../../docs/reference/gateway-config.mdx) for +See [gateway configuration](../../docs/how-it-works/gateways/configuration.mdx) for operator settings and [NETWORKING.md](NETWORKING.md) for supervisor networking. The supervisor uses Podman's host network and owns the upstream proxy settings. Omit `health_check_interval_secs` to disable Podman's periodic health command. diff --git a/crates/openshell-driver-vm/README.md b/crates/openshell-driver-vm/README.md index 0ec5758fac..b2103a6957 100644 --- a/crates/openshell-driver-vm/README.md +++ b/crates/openshell-driver-vm/README.md @@ -13,7 +13,7 @@ encoded in driver JSON. GPU devices and their trusted VFIO plumbing are temporarily exempt from approval labels; existing GPU selection validation still applies. Private rootfs staging does not authorize arbitrary host paths. The gateway passes its common policy to its managed VM subprocess. -See [resource admission configuration](../../docs/reference/gateway-config.mdx#external-resource-admission). +See [resource admission configuration](../../docs/how-it-works/gateways/configuration.mdx#external-resource-admission). ```mermaid flowchart LR diff --git a/crates/openshell-prover-cli/README.md b/crates/openshell-prover-cli/README.md index 92050bc2b5..e7340b1201 100644 --- a/crates/openshell-prover-cli/README.md +++ b/crates/openshell-prover-cli/README.md @@ -31,7 +31,7 @@ cargo build -p openshell-prover-cli --bin openshell-prover cargo test -p openshell-prover-cli ``` -See the [policy prover reference](../../docs/reference/policy-prover.mdx) for installed usage and interpretation guidance. +See the [policy prover reference](../../docs/how-it-works/policies/prover.mdx) for installed usage and interpretation guidance. JSON output uses a numeric `schema_version` for the result contract and a `prover_version` for the implementation that produced it. Consumers must inspect diff --git a/crates/openshell-server/src/config_file.rs b/crates/openshell-server/src/config_file.rs index 6bddddc4c2..6cde6aa461 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -396,8 +396,7 @@ pub enum ConfigFileError { }, } -const CONFIG_MIGRATION_URL: &str = - "https://docs.nvidia.com/openshell/latest/reference/gateway-config#migrate-to-schema-version-2"; +const CONFIG_MIGRATION_URL: &str = "https://docs.nvidia.com/openshell/latest/how-it-works/gateways/configuration#migrate-to-schema-version-2"; /// Stable package-preflight failure with no configuration contents attached. #[derive(Debug, thiserror::Error)] diff --git a/crates/openshell-server/src/otel_tracing.rs b/crates/openshell-server/src/otel_tracing.rs index da12500050..cdae552871 100644 --- a/crates/openshell-server/src/otel_tracing.rs +++ b/crates/openshell-server/src/otel_tracing.rs @@ -15,7 +15,7 @@ //! //! **How** to export — sampling, batching, span limits, transport headers — //! is the SDK's `OTEL_*` environment surface, read as the provider is built -//! and mirrored nowhere here. `docs/reference/gateway-config.mdx` documents +//! and mirrored nowhere here. `docs/how-it-works/gateways/configuration.mdx` documents //! the variables operators are likely to want. //! //! Only traces are exported. Logs and metrics have their own surfaces (OCSF @@ -401,7 +401,7 @@ mod tests { .map(|v| v.to_string()) } - /// Documented in `docs/reference/gateway-config.mdx`: the config file wins + /// Documented in `docs/how-it-works/gateways/configuration.mdx`: the config file wins /// over `OTEL_SERVICE_NAME`, because the gateway owns its own identity /// when an operator has stated it explicitly. #[test] diff --git a/deploy/rpm/TROUBLESHOOTING.md b/deploy/rpm/TROUBLESHOOTING.md index b9b2fdb56a..a975ab1e92 100644 --- a/deploy/rpm/TROUBLESHOOTING.md +++ b/deploy/rpm/TROUBLESHOOTING.md @@ -231,7 +231,7 @@ the schema-v2 upgrade, the user service replaces only an exact copy of the v1 file previously seeded by the RPM. If you edited that file, migrate it manually before restarting the service; direct `dnf` or `rpm` upgrades do not use the breaking-upgrade guard in `install.sh`. See the -[Gateway Configuration File](https://docs.nvidia.com/openshell/latest/reference/gateway-config#migrate-to-schema-version-2) +[Gateway Configuration File](https://docs.nvidia.com/openshell/latest/how-it-works/gateways/configuration#migrate-to-schema-version-2) for the field-by-field migration steps. New gateway process options are listed in CONFIGURATION.md and `openshell-gateway --help`. diff --git a/docs/CONTRIBUTING.mdx b/docs/CONTRIBUTING.mdx index b7a47ce986..383473918e 100644 --- a/docs/CONTRIBUTING.mdx +++ b/docs/CONTRIBUTING.mdx @@ -25,7 +25,7 @@ Update documentation when your change: - Adds, removes, or renames a CLI command or flag. - Changes default behavior or configuration. -- Adds, removes, renames, or changes defaults for gateway TOML fields or driver-specific config options. Update `docs/reference/gateway-config.mdx` for these changes. +- Adds, removes, renames, or changes defaults for gateway TOML fields or driver-specific config options. Update `docs/how-it-works/gateways/configuration.mdx` for these changes. - Adds a new feature that users interact with. - Fixes a bug that the docs describe incorrectly. - Changes an API, protocol, or policy schema. diff --git a/docs/about/architecture.mdx b/docs/about/architecture.mdx new file mode 100644 index 0000000000..8c8ab55679 --- /dev/null +++ b/docs/about/architecture.mdx @@ -0,0 +1,206 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Architecture" +sidebar-title: "Architecture" +description: "Understand the OpenShell control plane, sandbox boundary, runtime isolation, and policy-enforced network path." +keywords: "Generative AI, Cybersecurity, AI Agents, Architecture, Gateway, Sandbox, Supervisor, Isolation" +position: 2 +--- + +![OpenShell system architecture showing a trusted supervisor separated from a network-isolated sandbox workload. The workload can connect only to the supervisor.](../images/openshell-system-architecture.svg) + +OpenShell separates control-plane state from sandbox enforcement. The gateway +owns sandbox state, policy, providers, and access. A compute driver provisions +the workload and its isolation boundary. + +The trusted supervisor runs outside the workload. `openshell-sandbox` runs +inside it, owns the agent process, and mediates its network requests. All other +workload egress is denied. The supervisor initiates one connection to the +gateway for configuration, credentials, logs, and interactive sessions. + +## What Each Piece Does + +| Component | What it does | +|---|---| +| [Gateway](/how-it-works/gateways/overview) | Checks who you are and remembers everything about your sandboxes. It delivers policy and settings, attaches providers, decides who can do what, and coordinates connections into sandboxes. | +| [Compute runtime](/how-it-works/sandboxes/runtimes) | Creates the sandbox, starts the supervisor and the workload, sets up the private channel between them, and builds the network fence. It reports status back and cleans up when the sandbox goes away. | +| [Supervisor](#inside-the-sandbox-boundary) | Lives on the trusted side of the boundary. It checks requests against policy, supplies credentials, resolves DNS, opens approved connections, and keeps the link to the gateway alive. | +| [Isolation backend](/extensibility/isolation-backends) | Gives the supervisor one consistent way to work with any runtime: confirm the boundary, start the agent, run commands, forward connections, and see network requests. | +| [`openshell-sandbox`](#inside-the-sandbox-boundary) | Lives inside the boundary with the agent. It owns the agent's processes, knows which program made each request, applies process controls, and forwards TCP and DNS traffic to the supervisor. | +| [Outer network fence](/security/best-practices#deny-by-default-egress) | Denies all network egress from the workload except its protected connection to the supervisor. Each runtime builds this with its own native tools. | +| [Policies](/how-it-works/policies/overview) | Describe what the agent can touch: files, processes, network destinations, API calls, and where provider credentials can go. | +| [Providers](/how-it-works/providers/overview) | Connect a service name to a stored credential. The supervisor hands that credential out only where policy allows it. | + +## Inside the Sandbox Boundary + +The supervisor and `openshell-sandbox` sit on opposite sides of the boundary. +The supervisor is trusted and makes the decisions. `openshell-sandbox` shares +the boundary with the untrusted agent, so it never makes policy decisions. It +reports what the agent is trying to do and lets the supervisor decide. + +`openshell-sandbox` launches the agent as an owned child and provides exec, +terminal streams, signals, process status, and loopback forwarding. In the +current Linux backend, the workload uses one non-root identity and no Linux +capabilities. Landlock limits filesystem access; seccomp user notification +stages network operations. The sandbox identifies the calling executable from +trusted process observations. + +![OpenShell sandbox enforcement flow showing the network-isolated sandbox and trusted supervisor as separate boundaries. The supervisor channel is the workload's only allowed egress path.](../images/openshell-sandbox-enforcement.svg) + +### The protected channel + +The supervisor and `openshell-sandbox` talk over the OpenShell Sandbox Protocol: +one mutually authenticated HTTP/2 connection that carries many independent +streams. The compute driver picks the transport: a Unix socket for Docker and +Podman, TCP for Kubernetes, or vsock for MicroVM. Authentication and protocol +behavior are the same on all of them. The supervisor presents a +sandbox-specific credential, as described in +[How Components Authenticate](#how-components-authenticate). + +![OpenShell Sandbox Protocol showing the trusted supervisor and the network-isolated OpenShell Sandbox connected by one authenticated connection with separate control, DNS, and per-connection TCP streams. The agent reaches the supervisor only through the OpenShell Sandbox.](../images/openshell-sandbox-protocol.svg) + +Each TCP connection gets its own stream with its own backpressure, so a slow +download can't block DNS, exec, or process control. + +| Guarantee | How `openshell-sandbox` provides it | What the supervisor gets | +|---|---|---| +| Process ownership | Runs the agent as an owned child and keeps its process and terminal state. | Handles to wait on, attach to, signal, exec in, and stop the agent. | +| Program identity | Identifies the calling program from trusted `/proc` data. | The real program behind each request, not a path the agent claims. | +| Network mediation | Intercepts TCP opens and DNS queries with seccomp and hands them over. | Requests that wait for a policy decision before going anywhere. | +| Fail closed | Holds launch until the supervisor confirms, and freezes the agent if the connection drops. | A short window to reconnect, or a stopped workload. | + +Together these mean the agent can't run before its controls are confirmed, +signals and exec reach only this sandbox's processes, and the agent can't get +around TCP or DNS mediation. + +### Starting an agent safely + +The supervisor's `OpenShellRuntimeBackend` implements the shared +[Isolation Backend](/extensibility/isolation-backends) interface using the +Sandbox Protocol. Before the agent runs, it walks through a fixed series of +steps: + +```text +Attach → Bound → Confirmed → Ready → Running +``` + +The compute driver supplies the transport and a runtime descriptor. The backend +binds that descriptor to the admitted sandbox during attach, then confirms the +workload identity, launch controls, and outer network fence before starting the +agent. Each step must succeed before the next one begins. A stale or mismatched +boundary cannot launch the workload. + +### How a network request travels + +Say the agent tries to call an API. Here's what happens, and it works the same +way on every runtime: + +1. The agent opens a TCP connection or makes a DNS lookup. +2. `openshell-sandbox` notes which program made the request. +3. The request travels over the Sandbox Protocol to the supervisor. +4. The supervisor checks the request against policy and adds any credentials the + policy allows. +5. If the request is allowed, the supervisor opens the real connection and + relays the traffic. + +The protected channel to the supervisor is the only network path allowed out of +the workload boundary. The outer fence denies all other network egress. The +agent cannot reach an external service, the gateway, DNS, or another private +address directly. + +## How Each Runtime Builds the Boundary + +Every runtime follows the same contract, but each one uses the tools it already +has to place the supervisor, connect it to the sandbox, and fence off the +network. + +| Runtime | Where the supervisor runs | How it talks to the sandbox | How direct egress is blocked | +|---|---|---|---| +| Docker | Its own container | Authenticated Unix socket on a driver-owned volume | Workload container has networking turned off | +| Podman | Its own container | Authenticated Unix socket on a driver-owned volume | Workload container has networking turned off | +| Kubernetes | Its own pod | Private service with mutual TLS | NetworkPolicy allows only the supervisor service | +| VM | A process on the host | Authenticated vsock | Guest has no network device | + +The runtime's job is to build the boundary and prove it's in place. It never +decides whether a request is allowed. That decision always belongs to the shared +supervisor and policy engine, which is why the same policy behaves the same way +everywhere. + +Runtimes can differ in how they report readiness and which features they +support. Each one advertises its capabilities so the gateway knows what it can +do. + +## How Components Authenticate + +Three connections tie a sandbox together. The gateway is the only component +that signs credentials, and every credential names exactly one sandbox. + +![OpenShell sandbox authentication showing the compute driver giving the supervisor a bootstrap credential, the gateway issuing a gateway JWT and sandbox JWT, and the supervisor presenting the sandbox JWT over mutual TLS to the OpenShell Sandbox, which holds only the gateway's public key.](../images/openshell-sandbox-authentication.svg) + +| Connection | Who connects | How it's protected | +|---|---|---| +| Supervisor to gateway | The supervisor dials out to the gateway. | A gateway JWT, over TLS when the gateway has TLS enabled. | +| Supervisor to `openshell-sandbox` | The supervisor dials into the workload over the driver's private channel. | Mutual TLS, plus a sandbox JWT. | +| Agent to supervisor | The agent never connects directly. `openshell-sandbox` relays its traffic over the connection above. | Covered by the supervisor-to-sandbox channel. | + +### Getting the first credential + +The supervisor needs a starting credential to prove which sandbox it belongs +to. How it gets one depends on the runtime: + +- **Docker, Podman, and MicroVM.** The driver hands the supervisor its initial + tokens directly, in files only the supervisor can read. +- **Kubernetes.** The supervisor presents its pod's ServiceAccount token. The + gateway asks the Kubernetes driver to verify the token and confirm that the + pod belongs to the expected sandbox before it issues any JWTs. + +Either way, the gateway checks the claim against its own record of the sandbox +before returning credentials. + +### Two JWTs, two jobs + +The gateway issues a pair of JWTs for each run of a sandbox: + +- **Gateway JWT.** Sent with every supervisor call to the gateway. It allows + only the calls a supervisor needs, such as fetching policy, pushing logs, and + relaying sessions. It is not a user credential and can't manage other + sandboxes. +- **Sandbox JWT.** Sent with every supervisor call to `openshell-sandbox`. + `openshell-sandbox` holds only the gateway's public key, so it can verify the + token but can never create one. + +Each token works only on its own connection. Both are bound to one sandbox and +one run of that sandbox, called a generation. Restarting a sandbox starts a new +generation with fresh tokens and fresh TLS certificates, and the old ones stop +working. + +### Renewing and revoking + +The supervisor keeps its tokens in memory and renews both together before they +expire. Renewal works only while the sandbox still exists, so deleting a +sandbox cuts off its supervisor. + +Shared deployments, such as Kubernetes, should set `gateway_jwt.ttl_secs` so +tokens expire. Local single-user gateways can leave it unset, which issues +tokens that last for the life of the sandbox run. + +### What the agent can see + +The agent shares its side of the boundary with `openshell-sandbox`, so +`openshell-sandbox` holds nothing worth stealing: no gateway signing key, no +gateway JWT, and no provider credentials. It can verify that it's talking to +the right supervisor, but it can't impersonate one. + +If the supervisor disconnects, `openshell-sandbox` freezes the agent. Only the +same supervisor process can reconnect and resume it. A new supervisor can't +take over a running sandbox, even with valid credentials. + +## Working With Your Existing Infrastructure + +OpenShell plugs into the tools you already use, including container runtimes, +schedulers, secret stores, identity providers, image pipelines, storage, and +device plugins. The gateway and supervisor define how OpenShell behaves. +Drivers translate that behavior into whatever your platform understands and +report back what happened. This keeps platform-specific details out of the core +control plane and the policy model. diff --git a/docs/about/how-it-works.mdx b/docs/about/how-it-works.mdx deleted file mode 100644 index 014af559ec..0000000000 --- a/docs/about/how-it-works.mdx +++ /dev/null @@ -1,129 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "Architecture" -sidebar-title: "Architecture" -description: "Understand the OpenShell architecture, runtime boundaries, gateways, sandboxes, and ecosystem integration points." -keywords: "Generative AI, Cybersecurity, AI Agents, Architecture, Gateway, Sandbox, Providers" -position: 2 ---- - -OpenShell is built around three stable runtime components: the **CLI**, the **Gateway**, and the **Supervisor**. - -The CLI, SDK, and TUI provide user-facing access. The gateway is the -control plane: it owns API access, state, policy and settings delivery, provider configuration, and relay coordination. The supervisor runs inside every sandbox workload and is the local security boundary. It launches the agent as a restricted child process and enforces policy where process identity, filesystem access, network egress, and -runtime credentials are visible. - -Infrastructure-specific work sits behind integration boundaries. Compute, -credentials, control-plane identity, and sandbox identity each have a driver or -adapter boundary so OpenShell can integrate with native runtimes, secret stores, -identity providers, and workload identity systems without moving those concerns -into the core gateway or sandbox model. - -```mermaid -flowchart TB - subgraph UI["User interfaces"] - CLI["CLI"] - SDK["SDK"] - TUI["TUI"] - end - - subgraph CP["Control plane"] - GW["Gateway"] - DB[("Entity persistence")] - DRIVERS["Compute, credentials, and identity drivers"] - end - - subgraph INFRA["Integrated infrastructure"] - RUNTIME["Docker, Podman, Kubernetes, or VM"] - SECRETSTORE["Secret stores"] - IDP["Identity providers"] - WORKLOADID["Workload identity"] - end - - subgraph DP["Sandbox data plane"] - SUP["Supervisor"] - AGENT["Restricted agent process"] - PROXY["Policy proxy"] - POLICY["OPA policy engine"] - end - - CLI -->|"gRPC / HTTP"| GW - SDK -->|"gRPC / HTTP"| GW - TUI -->|"gRPC / HTTP"| GW - GW --> DB - GW --> DRIVERS - DRIVERS --> RUNTIME - DRIVERS --> SECRETSTORE - DRIVERS --> IDP - DRIVERS --> WORKLOADID - RUNTIME -->|"provisions workload"| SUP - SUP -->|"control, config, logs, relay"| GW - SUP -->|"spawn and restrict"| AGENT - AGENT -->|"ordinary egress"| PROXY - PROXY -->|"evaluate"| POLICY - PROXY -->|"allowed traffic"| EXT["External services"] - PROXY -->|"profile-authorized traffic"| MODEL["Model providers"] -``` - -## Deployment Models - -OpenShell can run on a single local machine or in a remote Kubernetes cluster. -The CLI workflow stays the same: users point the CLI, SDK, or TUI at a gateway, -and the gateway provisions sandboxes through its configured compute driver. - -| Deployment | How it works | Best for | -|---|---|---| -| Local machine | The gateway runs on the user's workstation or a nearby development host and creates sandboxes with Docker, Podman, or a VM runtime. The supervisor inside each sandbox connects back to that local gateway. | Individual development, local agent experiments, and private workstation workflows. | -| Remote Kubernetes cluster | The gateway runs as a cluster service and creates sandbox pods in the configured namespace. Supervisors connect outbound to the gateway endpoint, so clients do not need direct pod access. | Shared teams, centrally managed policy, remote compute, GPUs, and production-like environments. | - -This deployment split keeps the runtime model consistent. Local deployments use -the host's container or VM runtime as the integrated infrastructure. Kubernetes -deployments use the cluster scheduler, networking, secrets, identity, and GPU -device plugins without changing the gateway and sandbox contract. - -## Core Components - -| Component | Boundary | -|---|---| -| [Sandboxes](/sandboxes/manage-sandboxes) | Data-plane workloads that run the supervisor, launch restricted agent processes, apply local isolation, push logs, and maintain the gateway session. | -| [Gateways](/sandboxes/manage-gateways) | Authenticated control plane that owns API access, durable state, sandbox lifecycle, settings delivery, authorization, and relay coordination. | -| [Providers](/sandboxes/manage-providers) | Credential and provider records that map logical agent needs to platform or user-managed secrets without exposing raw credentials to the agent process. | -| [Policies](/sandboxes/policies) | Declarative controls for filesystem access, process identity, network egress, L7 rules, credential injection, and runtime policy updates. | -| [Inference](/sandboxes/inference-routing) | Per-sandbox provider attachment, native model endpoints, and endpoint-bound credential injection. | - -## Gateways and Sandboxes - -The gateway and sandbox split control-plane authority from runtime enforcement. The gateway owns durable platform state: sandboxes, policy revisions, runtime settings, provider records, session records, and authorization decisions. A sandbox owns the local execution boundary: process identity, filesystem access, network egress, credential injection, local logs, and the agent child process. - -The relationship is supervisor initiated. Each sandbox supervisor connects outbound to a known gateway endpoint, authenticates as a sandbox workload, and keeps a live session open for control traffic and relays. This avoids requiring every compute driver to solve gateway-to-sandbox reachability through pod IPs, bridge networks, port mappings, NAT traversal, or custom tunnels. - -The gateway delivers desired state. The supervisor applies it locally, keeps last-known-good config when refresh fails, and leaves static isolation controls in place until the sandbox is recreated. Live operations such as config refresh, policy updates, credential delivery, log push, connect, exec, file sync, and relay setup use the same authenticated gateway-supervisor relationship. - -## Supervisor Protection Layers - -The supervisor is the sandbox-local enforcement component. It starts before the -agent process, prepares the sandbox runtime, fetches gateway configuration, and -then launches the agent under the active policy. - -| Protection layer | Supervisor responsibility | -|---|---| -| Process | Drops privileges, applies process identity rules, disables privilege escalation paths, and starts the agent as a restricted child process. | -| Filesystem | Applies filesystem policy before the agent starts so undeclared paths are inaccessible and declared paths are read-only or read-write as configured. | -| Network | Routes ordinary egress through the policy proxy so destination, port, binary identity, and L7 request rules can be evaluated before traffic leaves the sandbox. | -| Credentials | Receives credential material from the gateway and injects it only through configured policy paths or request-time proxy rules. | -| Provider access | Enforces profile-derived policy and substitutes provider credential placeholders only at profile-authorized endpoints. | -| Observability | Emits local security and lifecycle logs, pushes sandbox logs to the gateway, and keeps relay endpoints available for connect, exec, and file transfer operations. | - -Static controls such as filesystem and process isolation are established at -sandbox start and require sandbox recreation to change. Dynamic controls such as -network policy and credential delivery can refresh over the -live gateway-supervisor session. - -## Ecosystem Integration - -OpenShell integrates with infrastructure ecosystems instead of replacing them. Runtimes, schedulers, secret stores, identity providers, workload identity systems, image pipelines, storage, and GPU or device exposure remain owned by the platforms that provide them. - -The gateway owns OpenShell control-plane semantics: sandbox state, lifecycle ordering, policy and settings resolution, credential mapping, authorization, and relay coordination. Drivers translate those semantics into platform-native operations. - -The supervisor owns OpenShell sandbox semantics. Filesystem policy, process privilege reduction, network proxying, provider credential injection, security logging, and gateway relay behavior stay consistent across Docker, Podman, Kubernetes, VM-backed sandboxes, and future integrations. diff --git a/docs/about/installation.mdx b/docs/about/installation.mdx index 8a8ac97689..f6912e79e0 100644 --- a/docs/about/installation.mdx +++ b/docs/about/installation.mdx @@ -3,95 +3,55 @@ # SPDX-License-Identifier: Apache-2.0 title: "Installation" sidebar-title: "Installation" -description: "Install OpenShell, choose a sandbox runtime, and connect to a gateway." +description: "Install OpenShell on a local workstation or Kubernetes." keywords: "Generative AI, Cybersecurity, AI Agents, Sandboxing, Installation, Setup, Gateway, Docker, Podman, MicroVM, Kubernetes" position: 3 --- -Install OpenShell on a local workstation, choose the runtime that runs -your sandboxes, and verify the package-managed gateway configuration. +Install OpenShell on a local workstation or Kubernetes. ## Install OpenShell -Install OpenShell with a single command: +Install the CLI, policy prover, and a local gateway with one command: ```shell curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh ``` -The script detects your operating system and installs the OpenShell CLI, standalone policy prover, and gateway. On Linux, it installs from the Snap Store when `snap` is available and `OPENSHELL_VERSION` is unset or `dev`. Explicit release tags and prereleases use the native Debian or RPM package. It then starts the local gateway server so you can begin creating sandboxes. +The script picks a package for your platform and starts the gateway. Confirm the CLI can reach it: -Snap installs use `latest/stable` by default and `latest/edge` when -`OPENSHELL_VERSION=dev`. Set `OPENSHELL_VERSION` to a release tag to install -that exact Debian or RPM version, even if `snap` is available. - -You can also download release artifacts directly from the [OpenShell GitHub Releases](https://github.com/NVIDIA/OpenShell/releases) page. - -Use `openshell status` to confirm the CLI can reach the gateway. - -## Release Cadence - -OpenShell publishes stable versions as coordinated release sets. The default -installer selects the newest stable release, and the `latest` documentation -channel follows that release. Use the same version of the gateway, compute and -credential drivers, supervisors, CLI, and SDK clients together. +```shell +openshell status +``` -Between stable releases, numbered prereleases such as `0.1.0-pre.3` provide -evaluation checkpoints. Rolling development builds track successful releases -from `main` and use versions such as `0.0.0-dev.`. Prerelease and -development builds may change before the next stable release; their matching -documentation is published in the `dev` channel. +To install a specific release, set `OPENSHELL_VERSION` to a release tag. Release artifacts are also on the [GitHub Releases](https://github.com/NVIDIA/OpenShell/releases) page. ## Supported Runtimes -OpenShell supports several sandbox runtimes. Package-managed gateways leave the -runtime unset by default so the gateway can auto-detect an available backend. -Set `compute_driver` in the gateway TOML when you need to pin a specific -runtime. - -| Runtime | How It Is Configured | System Requirements | -|---|---|---| -| Podman | The gateway is configured to create rootless Podman containers through the Podman API socket. | Linux with Podman 5.x, cgroups v2, rootless networking, and an active Podman user socket. | -| Docker | The gateway is configured to create containers through Docker Desktop or Docker Engine. | Docker Desktop or Docker Engine 28.0 or later on the gateway host. | -| MicroVM | The gateway is configured to create VM-backed sandboxes. | Host virtualization support. MicroVM uses Hypervisor.framework on macOS, KVM on Linux, and QEMU for GPU-backed sandboxes on Linux. | +The local gateway auto-detects an available runtime. To pin one, set `compute_driver` in the gateway TOML file. See [Sandbox Runtimes](/how-it-works/sandboxes/runtimes). -For detailed runtime behavior, refer to [Sandbox Runtimes](/reference/sandbox-compute-drivers). For gateway and sandbox operations, refer to [Gateways](/sandboxes/manage-gateways) and [Sandboxes](/sandboxes/manage-sandboxes). +| Runtime | Requirements | +|---|---| +| Docker | Docker Desktop or Docker Engine 28.0 or later. | +| Podman | Linux with Podman 5.x, cgroups v2, and an active Podman user socket. | +| MicroVM | Host virtualization: Hypervisor.framework on macOS or KVM on Linux. | ## macOS -On macOS, the install script uses Homebrew. The Homebrew package installs the `openshell` CLI, `openshell-prover`, the gateway binary, and a Homebrew-managed gateway service. - -The Homebrew service uses the gateway's built-in `127.0.0.1:17670` listener and generates a local mTLS bundle on install. The installer registers `https://localhost:17670` with the CLI so TLS uses a DNS name covered by the generated certificate. The formula creates a Homebrew prefix config, such as `/opt/homebrew/var/openshell/gateway.toml`, without overriding `bind_address`. Host-networked Docker Desktop and Podman Machine supervisors reuse the primary listener when they can reach host loopback. The gateway reads `~/.config/openshell/gateway.toml` instead when that file exists. Homebrew upgrades migrate exact package-generated schema-v1 prefix configs, including the affected IPv6 variant. They preserve edited prefix configs and all user configs. Follow the [schema version 2 migration steps](/reference/gateway-config#migrate-to-schema-version-2) for an edited v1 file. - -The CLI reads the client bundle from `~/.config/openshell/gateways/openshell/mtls/`. - -The installer starts the service for you. Use Homebrew service commands when you need to inspect, restart, or stop the gateway service: +The script installs OpenShell with Homebrew and runs the gateway as a Homebrew service at `https://localhost:17670`. ```shell brew services list brew services restart openshell ``` -## Linux - -On Linux systems with the `snap` command, the install script uses the OpenShell -snap when `OPENSHELL_VERSION` is unset or `dev`. Explicit release tags and the -`pre` prerelease alias use Debian or RPM packages even when `snap` is available. -For Snap installs, install and start Docker Engine from a system package or -Docker's package repository first. The Docker snap is not currently compatible -with OpenShell. - -On Fedora and RHEL without `snap`, or when a release tag or `pre` is specified, the install script uses RPM packages. The RPMs install the `openshell` CLI, `openshell-prover`, the `openshell-gateway` daemon, and a systemd user service. - -On Debian and Ubuntu without `snap`, or when a release tag or `pre` is specified, the install script uses a Debian package. The Debian package installs the `openshell` CLI, `openshell-prover`, the `openshell-gateway` daemon, VM sandbox support, and a systemd user service. - -Linux packages require glibc 2.28 or newer. The installer checks libc before downloading packages and exits with an error on older glibc versions, Alpine, musl-based distributions, or unknown libc environments. +The gateway reads `~/.config/openshell/gateway.toml` if it exists, otherwise the Homebrew config at `$(brew --prefix)/var/openshell/gateway.toml`. -The Linux user service listens on `https://127.0.0.1:17670` and generates a local mTLS bundle before the gateway starts. Debian uses built-in gateway defaults unless you create a config. RPM seeds `~/.config/openshell/gateway.toml` from its packaged Podman template on first start. RPM upgrades migrate only an unchanged package-generated schema-v1 file; they preserve edited files. Follow the [schema version 2 migration steps](/reference/gateway-config#migrate-to-schema-version-2) when upgrading an edited v1 configuration. +## Linux -The CLI reads the client bundle from `~/.config/openshell/gateways/openshell/mtls/`. +The script uses the [Snap](#snap) package when `snap` is available. Otherwise, or when you set `OPENSHELL_VERSION` to a release tag, it installs a Debian package on Debian and Ubuntu or an RPM package on Fedora and RHEL. Linux packages require glibc 2.28 or newer. -The installer starts the service for you. Use systemd user commands when you need to inspect, restart, or stop the gateway service: +The gateway runs as a systemd user service at `https://127.0.0.1:17670` and reads `~/.config/openshell/gateway.toml`. ```shell systemctl --user status openshell-gateway @@ -99,7 +59,7 @@ systemctl --user restart openshell-gateway journalctl --user -u openshell-gateway -f ``` -To keep the user service running after logout, enable linger: +To keep the gateway running after you log out, enable linger: ```shell sudo loginctl enable-linger $USER @@ -107,74 +67,27 @@ sudo loginctl enable-linger $USER ## Snap -The OpenShell snap requires a running Docker daemon. Docker can come from the -distribution's Docker package, Docker's package repository, or another -compatible non-Snap installation. The Docker snap is not currently compatible: -its AppArmor confinement prevents OpenShell's hardened containers from starting. -The installer exits without installing OpenShell when Docker is absent or the -Docker snap is installed. - -The snap keeps gateway and CLI state in snap-specific directories and does not -import state from a Debian, RPM, Homebrew, or manual installation. If the -installer detects an existing non-snap OpenShell binary, it stops before -installing the snap. Back up anything you need, clean up existing sandboxes and -runtime resources, stop the non-snap gateway, and remove the old installation. -After completing that cleanup, rerun the installer with -`OPENSHELL_ACK_BREAKING_UPGRADE=1`. - -Install the OpenShell snap from the Snap Store: +The snap requires Docker Engine installed from your distribution or Docker's package repository. The Docker snap is not compatible. ```shell sudo snap install openshell ``` -The install script installs `latest/stable` by default. Set -`OPENSHELL_VERSION=dev` to install from `latest/edge`: +The snap does not migrate existing Debian, RPM, or Homebrew installs. Remove any existing installation first, then rerun the script with `OPENSHELL_ACK_BREAKING_UPGRADE=1`. + +The gateway runs as a system service at `http://127.0.0.1:17670` and reads `/var/snap/openshell/common/gateway.toml`. + + +The snap gateway allows unauthenticated access from the local host. Any local user or process can operate it. Do not expose it beyond the local host. + + +Snap refreshes do not restart the gateway, so active sandboxes keep running. Restart it to pick up a new version: ```shell -curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | \ - OPENSHELL_VERSION=dev sh +sudo systemctl restart snap.openshell.gateway ``` -The snap defines two apps: the `openshell` CLI and the `openshell.gateway` -system service. Unlike the Debian and RPM user services, snapd runs this service -as root. The gateway therefore generates its certificates in root-owned snap -state, where ordinary users running the CLI cannot read the client certificate. -For this reason, the snap disables TLS and listens only on -`http://127.0.0.1:17670`. Its default configuration permits unauthenticated -local CLI access. Sandbox connections still use gateway-minted credentials. - -The gateway stores its database at `$SNAP_COMMON/gateway.db` and its -configuration at `$SNAP_COMMON/gateway.toml`, typically under -`/var/snap/openshell/common/`. Initial snap installation creates the default -configuration only when no configuration already exists. -The install script applies the same default when it installs or refreshes a snap -that has no existing gateway configuration, then restarts the gateway. - -Edit `$SNAP_COMMON/gateway.toml` when you need to override gateway settings, -then restart the service. Do not expose the default plaintext gateway beyond -the local host while unauthenticated user access is enabled. Any process or user -on the same host that can connect to the loopback port can operate the gateway. - -The snap CLI stores per-user config, data, and state under `$SNAP_USER_COMMON`, -typically `~/snap/openshell/common`. Gateway registrations live under -`$SNAP_USER_COMMON/.config/openshell/gateways/` instead of -`~/.config/openshell/gateways/`. - -### Snap store installs - -When installing OpenShell from the Snap Store, snapd automatically connects all -required interfaces. The `docker` plug connects to the system `:docker` slot, -which exposes the compatible Docker daemon installed on the host. The -`log-observe` and `system-observe` plugs are also automatically connected -through the OpenShell snap's store assertions. - -### Locally built snap packages - -To install a locally-built snap, one can install directly from a `.snap` file -with the `--dangerous` flag to acknowledge that it has not been signed by the -Snap Store. Thus, it lacks the store assertions which tell snapd to auto- -connect the privileged interfaces, so they must be connected manually. +To install a locally built snap, connect its interfaces manually: ```shell sudo snap install ./openshell_*.snap --dangerous @@ -183,61 +96,58 @@ sudo snap connect openshell:system-observe sudo snap connect openshell:docker :docker ``` -The `log-observe` and `system-observe` plugs are needed for the gateway service -to read logs and inspect system processes. The `docker` plug connects to the -same system `:docker` slot used by Store installations. +## Kubernetes + +Deploy the gateway to a cluster with the OpenShell Helm chart. See [Kubernetes Setup](/kubernetes/setup). -### Gateway service +## Validate Gateway Configuration -The gateway runs as a snap daemon with `refresh-mode: endure`, meaning snapd -will not restart it during snap refreshes. This prevents the gateway from -killing active sandbox sessions during automatic or direct snap refreshes. -Restart the service manually after a direct `snap refresh` when you need the -updated binary: +Check a gateway config file before restarting the service: ```shell -sudo systemctl restart snap.openshell.gateway +openshell-gateway config preflight --path ~/.config/openshell/gateway.toml ``` -Rerunning `install.sh` explicitly refreshes the snap and restarts the gateway so -the refreshed binary is active when installation completes. That restart -interrupts active sandbox sessions. +Preflight never changes the file. If the gateway reports a legacy schema, follow the [schema version 2 migration steps](/how-it-works/gateways/configuration#migrate-to-schema-version-2). -## Kubernetes +## Uninstall OpenShell + +Homebrew: -Kubernetes deployments use the OpenShell Helm chart. For step-by-step installation, refer to [Kubernetes Setup](/kubernetes/setup). For chart values and packaging details, refer to the [Helm chart README](https://github.com/NVIDIA/OpenShell/blob/main/deploy/helm/openshell/README.md). +```shell +brew services stop nvidia/openshell/openshell +brew uninstall nvidia/openshell/openshell +rm -rf "$(brew --prefix)/var/openshell" +``` -## Validate a package-managed gateway configuration +Debian and Ubuntu: -Debian and Ubuntu packages validate the selected gateway configuration before -generating local certificates or starting the service. Snap does the same before -its gateway daemon starts. The validation never changes the file. If startup reports a legacy schema, -malformed TOML, a symlink, or a nonregular configuration path, fix or manually -migrate the operator-owned file instead of deleting it. +```shell +systemctl --user disable --now openshell-gateway +sudo apt remove openshell +rm -rf "${XDG_STATE_HOME:-$HOME/.local/state}/openshell" +``` -Check the selected file before restarting a service: +Fedora and RHEL: ```shell -openshell-gateway config preflight --path ~/.config/openshell/gateway.toml +systemctl --user disable --now openshell-gateway +sudo dnf remove openshell-gateway openshell-prover openshell +rm -rf "${XDG_STATE_HOME:-$HOME/.local/state}/openshell" +``` + +Snap: + +```shell +sudo snap remove --purge openshell ``` -Without `--path`, preflight checks a nonempty `OPENSHELL_GATEWAY_CONFIG` or an -auto-discovered XDG config; no config is also a successful result. It applies -read-only startup validation to the effective selector, registered compute driver, -driver configuration, socket, rate limits, TLS, interceptors, and middleware. If -a selected file omits the selector, preflight validates configured tables for -auto-detectable drivers without running socket or process-based detection probes. -Wrappers can pass daemon arguments after `--` to validate the exact startup -invocation. Debian keeps its bare service invocation and `gateway.env` semantics. -Snap replays its effective daemon arguments through preflight and gives a nonempty -`OPENSHELL_GATEWAY_CONFIG` precedence over `SNAP_COMMON/gateway.toml`. -See [Gateway Configuration](/reference/gateway-config#gateway-config-preflight) -for preflight details and manual schema-v1 migration steps. +Remove any custom config or database set through `OPENSHELL_GATEWAY_CONFIG` or `OPENSHELL_DB_URL` separately. ## Next Steps -- To prepare an image and launch an agent, refer to [Run Your First Agent](/about/run-an-agent). -- To run the gateway as a container without the installer, refer to [Running the Gateway as a Container](/reference/container-gateway). -- To register, select, and inspect gateways, refer to [Gateways](/sandboxes/manage-gateways). -- To supply API keys or tokens, refer to [Manage Providers](/sandboxes/manage-providers). -- To control what the agent can access, refer to [Policies](/sandboxes/policies). +- [Run Your First Agent](/about/run-your-first-agent) to prepare an image and launch an agent. +- [Running the Gateway as a Container](/how-it-works/gateways/container-deployment) to skip the installer. +- [Gateways](/how-it-works/gateways/overview) to register, select, and inspect gateways. +- [Providers](/how-it-works/providers/overview) to supply API keys and tokens. +- [Policies](/how-it-works/policies/overview) to control what the agent can access. diff --git a/docs/about/overview.mdx b/docs/about/overview.mdx index 82be4bbe48..34b8b0cecb 100644 --- a/docs/about/overview.mdx +++ b/docs/about/overview.mdx @@ -11,7 +11,7 @@ position: 1 NVIDIA OpenShell is an open-source runtime for executing autonomous AI agents in sandboxed environments with kernel-level isolation. It combines sandbox runtime controls and a declarative YAML policy so teams can run agents without giving them unrestricted access to local files, credentials, and external networks. -New in OpenShell 0.1.0 is a [stable release cadence](/about/installation#release-cadence), a stronger [security model](/about/how-it-works), and an expanded [extension surface](/extensibility/overview), along with much more. +New in OpenShell 0.1.0: a [stable release cadence](/about/support-matrix#releases), new [isolation primitives](/about/architecture), and an expanded [extension surface](/extensibility/overview), along with much more. See our [upgrade guide](/upgrade/0-1-0) for everything that's changed. @@ -42,7 +42,7 @@ OpenShell applies defense in depth across the following policy domains. | Process | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | | Provider credentials | Resolves opaque credential placeholders only at profile-authorized endpoints. | Attachments, rotation, and revocation update at runtime; new environment variables require a new process. | -For details, refer to [Customize Sandbox Policies](/sandboxes/policies) and [Default Policy](/reference/default-policy). +For details, refer to [Customize Sandbox Policies](/how-it-works/policies/overview) and [Default Policy](/how-it-works/policies/default-policy). ## Common Use Cases @@ -59,6 +59,6 @@ OpenShell supports a range of agent deployment patterns. Explore these topics to go deeper: -- To understand the runtime architecture, refer to [How OpenShell Works](/about/how-it-works). -- To prepare an image and launch an agent, refer to [Run Your First Agent](/about/run-an-agent). -- To learn how OpenShell enforces policy controls across protection layers, refer to [Customize Sandbox Policies](/sandboxes/policies). +- To understand the runtime architecture, refer to [Architecture](/about/architecture). +- To prepare an image and launch an agent, refer to [Run Your First Agent](/about/run-your-first-agent). +- To learn how OpenShell enforces policy controls across protection layers, refer to [Customize Sandbox Policies](/how-it-works/policies/overview). diff --git a/docs/about/run-an-agent.mdx b/docs/about/run-an-agent.mdx index 46581d54c5..fb3169a6bd 100644 --- a/docs/about/run-an-agent.mdx +++ b/docs/about/run-an-agent.mdx @@ -3,130 +3,84 @@ # SPDX-License-Identifier: Apache-2.0 title: "Run Your First Agent" sidebar-title: "Run Your First Agent" -description: "Prepare a sandbox image, provider profile, and policy for an AI agent or another autonomous workload." +description: "Configure a provider, image, and policy to run an AI agent in an OpenShell sandbox." keywords: "Generative AI, Cybersecurity, AI Agents, Sandboxing, Provider Profiles, Policies, Custom Images" position: 4 --- -OpenShell can run an AI agent or another autonomous command when its executable -is available in the sandbox image. The image, provider profile, and policy -define what the workload can execute and access. OpenShell does not require the -agent to use a specific framework or model API. +OpenShell can run any agent that is available in a sandbox image. Configure the +agent's external services, choose its image and policy, then create the sandbox +with the agent as its main process. -## Prepare the Workload +**1. Configure what the agent has access to.** -An agent needs three pieces: - -| Requirement | Purpose | -|---|---| -| Sandbox image | Contains the agent executable and its runtime dependencies. | -| Provider profile | Declares credential fields, service endpoints, and the executable paths allowed to use them. | -| Sandbox policy | Controls filesystem access, process behavior, and network destinations beyond access contributed by attached providers. | - -Build and maintain an OCI image for each workload. Install the agent, shell, -development tools, CA certificates, and language runtimes that the workload -needs. Use pinned versions so you can review and reproduce image updates. +A [provider profile](/how-it-works/providers/profiles) defines the credentials, service +endpoints, and executable paths an agent may use. For Claude Code, review the +[example profile](https://github.com/NVIDIA/OpenShell/blob/main/providers/claude-code.yaml), +including its executable paths for your image, then import it and +[create a provider](/how-it-works/providers/overview#create-a-provider) that +stores its credentials. ```shell -docker build -t registry.example.com/team/agent:1.0 . -docker push registry.example.com/team/agent:1.0 -openshell sandbox create --from registry.example.com/team/agent:1.0 +openshell profile import \ + --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml + +openshell provider create \ + --name claude-code \ + --type claude-code \ + --from-existing ``` -The `--from` option also accepts a local rootfs archive. It does not build a -Dockerfile or directory. Refer to -[Custom Containers](/sandboxes/manage-sandboxes#custom-containers) for image and -runtime details. The fallback image contains no agent or development toolchain, -so pass your image explicitly for agent workloads. +Set `ANTHROPIC_API_KEY` before creating the provider. OpenShell stores its +value in the credential store. -## Prepare Provider Access +**2. Configure the sandbox image.** -A provider profile defines the credentials and endpoints an agent uses. The -gateway serves only profiles that an administrator or user has imported. -Review a profile before importing it, especially its executable paths and -network endpoints. +Build or select a [sandbox image](/how-it-works/sandboxes/overview#sandbox-images) +containing Claude Code and every tool it needs: ```shell -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml -openshell profile import -f claude-code.yaml --global -ANTHROPIC_API_KEY= \ - openshell provider create --name my-claude --type claude-code --from-existing +docker build -t agent:local . ``` -The repository includes example profiles in -[`providers/`](https://github.com/NVIDIA/OpenShell/tree/main/providers). Copy -and adapt an example when the agent binary is installed at another path or uses -a different service endpoint. Refer to [Profiles](/providers/profiles) for the -profile schema and import workflow. - -## Launch the Agent - -Pass the agent command after `--` and attach the provider instances it needs. -For example, this command starts Claude Code from an image your team built with -the `claude` executable installed: +For a remote gateway, push the image to a registry that the gateway can pull +from. Use an explicit version instead of a mutable tag for reproducible +deployments. -```shell -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --provider my-claude \ - -- claude -``` +The built-in fallback policy grants access to the working directory and common +runtime paths, and denies network egress unless an attached provider contributes +an endpoint. Create a custom [sandbox policy](/how-it-works/policies/overview) when the +agent needs more filesystem access, package registries, source hosts, tool +servers, or other destinations. -The command before `--` configures the sandbox. The command after `--` becomes -the sandbox's main process. OpenShell keeps the sandbox after that process exits -unless you pass `--no-keep`. +**3. Create the sandbox.** -Use `--detach` for an unattended or long-running agent: +[Create the sandbox](/how-it-works/sandboxes/overview#create-a-sandbox), attach the +provider, and pass the agent command after `--`: ```shell openshell sandbox create \ - --name worker \ - --detach \ - --from my-registry.example.com/team/agent:latest \ - --provider model-provider \ - -- ./worker + --name my-agent \ + --from agent:local \ + --provider claude-code \ + -- claude ``` -Use a profile-backed provider for credentials that the agent should not read -directly. Plain values passed with `--env` are visible to the agent process. - -## Build an Agent Image - -Prepare each agent as part of your normal container build and release process: - -1. Select a trusted base image and install the agent executable and tools. -2. Create or adapt provider profiles for every external service the agent uses. -3. Add policy rules for required files, child processes, package registries, - tool servers, and other network destinations. -4. Build, scan, sign, and publish the image to a registry the gateway can pull. -5. Launch the executable as the sandbox's main process. - -Provider profiles can contribute endpoint and executable rules to the effective -policy. They do not grant unrelated network or filesystem access. Use -[Customize Sandbox Policies](/sandboxes/policies) when the agent needs access -beyond its attached providers. +Add `--policy sandbox-policy.yaml` when the workload needs a custom policy. The +command after `--` becomes the sandbox's main process, and every child process +it starts remains inside the sandbox boundary. -## Verify and Troubleshoot - -Inspect the sandbox, effective policy, provider attachments, and logs: - -```shell -openshell sandbox list -openshell policy get my-sandbox --full -openshell sandbox provider list my-sandbox -openshell logs my-sandbox --tail -``` +## Examples -If the executable is missing, change the sandbox image. If a provider request -is denied, confirm that the profile names the actual endpoint and executable -path. For another denied network or filesystem operation, update the sandbox -policy after reviewing the requested access. +For a complete worked example, follow [Run Pi in OpenShell](/tutorials/run-pi). +The tutorial builds a Pi image, configures narrowly scoped Anthropic access, +uploads a project, and starts the agent inside the sandbox boundary. ## Next Steps - For sandbox lifecycle, resources, templates, files, and connectivity, refer - to [Sandboxes](/sandboxes/manage-sandboxes). + to [Sandboxes](/how-it-works/sandboxes/overview). - For the restrictive fallback policy, refer to - [Default Policy](/reference/default-policy). + [Default Policy](/how-it-works/policies/default-policy). - For operating-system and runtime requirements, refer to the - [Support Matrix](/reference/support-matrix). + [Support Matrix](/about/support-matrix). diff --git a/docs/reference/support-matrix.mdx b/docs/about/support-matrix.mdx similarity index 73% rename from docs/reference/support-matrix.mdx rename to docs/about/support-matrix.mdx index 87e80104dd..9cace1a708 100644 --- a/docs/reference/support-matrix.mdx +++ b/docs/about/support-matrix.mdx @@ -8,6 +8,36 @@ position: 5 This page lists the host platform, compute driver, software, runtime, and kernel requirements for running OpenShell. +## Releases + +OpenShell publishes dev, pre-release, and stable builds for different stages of +the release cycle. Use a stable release for production deployments. + +| Release | Publication | Intended use | +|---|---|---| +| Dev | Built from every commit to `main` that passes normal CI. The floating `dev` alias points to the newest build. | Testing upcoming functionality. Dev builds enable development features and have not passed release qualification. | +| Pre-release | Built nightly when `main` has changed and normal CI passes. Versions use the form `X.Y.Z-pre.N`. | Validating the immutable artifact set proposed for the next stable release. Pre-releases use the stable feature set but may not have passed qualification. | +| Stable | Promoted from a pre-release that passes conformance, upgrade, API compatibility, artifact, and security checks. Versions use the form `X.Y.Z`. | Production use within this support matrix. | + +Tagged stable releases generally go out every week. OpenShell targets Tuesday +publication when there are changes and every blocking qualification check +passes. A security release may ship sooner. + +Stable APIs and other Stable interfaces remain backward-compatible across +patch releases. Patch releases can contain fixes and additive functionality. A +breaking change to a Stable interface requires a minor release with notice and +migration guidance. Interfaces marked Experimental may change or be removed in +a patch release. + +OpenShell provides security and critical reliability updates for the latest +minor release and the previous minor release, also called N-1. Support applies +to the newest patch on each maintained minor line. Update to that patch to +receive fixes; OpenShell does not issue fixes for every older patch. Maintenance +updates do not backport features. + +Refer to [RFC 0014](https://github.com/NVIDIA/OpenShell/blob/main/rfc/0014-release-stability/README.md) +for the complete release and compatibility policy. + ## Supported Platforms OpenShell publishes multi-architecture gateway images for `linux/amd64` and `linux/arm64`. The CLI, policy prover, package-managed gateway, and standalone gateway binary are supported on the following host platforms: @@ -35,6 +65,35 @@ These artifacts are attached to GitHub releases. Kubernetes deployments should u On Linux, `openshell-gateway` requires glibc 2.28 or newer. Compatible systems include, for example, Ubuntu 20.04+, RHEL 8+, Rocky Linux 8+, Amazon Linux 2023+, and Fedora 32+. +## Sandbox Runtime Binary + +`openshell-sandbox` is the trusted workload-side runtime binary. It runs inside +the sandbox boundary, starts and owns the agent process tree, observes +executable identity, and sends mediated TCP and DNS operations to the +supervisor. It does not hold provider credentials or open upstream connections; +those responsibilities remain with the supervisor outside the workload +boundary. + +OpenShell publishes static musl builds for the Linux architectures supported by +the sandbox runtime: + +| Platform | Artifact pattern | +|---|---| +| Linux x86_64 (amd64) | `openshell-sandbox-x86_64-unknown-linux-musl.tar.gz` | +| Linux aarch64 (arm64) | `openshell-sandbox-aarch64-unknown-linux-musl.tar.gz` | + +The static binary does not depend on the agent image's libc. Each stable release +also publishes `openshell-sandbox-checksums-sha256.txt` for the standalone +archives. + +Supported runtimes deliver this binary automatically and separately from the +agent image. Docker and Podman stage it into the workload, Kubernetes uses the +trusted sandbox runtime image, and the VM runtime embeds it in the guest +rootfs. Most users do not invoke the binary directly. Use the standalone +archives when integrating a runtime or preparing artifacts for an air-gapped +environment, and keep the sandbox binary aligned with the rest of the OpenShell +release. + ## Standalone Policy Prover OpenShell publishes standalone `openshell-prover` release assets for manual download on these platforms: @@ -83,6 +142,7 @@ change the default, and users can select an explicit image with `--from`. | Image | Reference | Pulled When | |---|---|---| | Gateway | `ghcr.io/nvidia/openshell/gateway:latest` | Helm chart install or upgrade, or standalone container deployment | +| Sandbox runtime | `ghcr.io/nvidia/openshell/sandbox:latest` | A supported runtime stages `openshell-sandbox` into a workload boundary | | Default workload | `nvcr.io/nvidia/base/ubuntu:24.04` | First sandbox creation unless preloaded or overridden | The Helm chart in `deploy/helm/openshell` deploys the gateway workload, service account, service, optional persistent storage, and network policy for Kubernetes. It defaults to a StatefulSet for SQLite-backed installs and can render a Deployment for external database-backed installs. @@ -147,5 +207,5 @@ On macOS, these kernel modules run inside the Docker Desktop Linux VM, not on th OpenShell runs agents and tools that you install in a user-owned OCI image. The image must satisfy the selected compute driver's platform requirements. Refer to -[Run Your First Agent](/about/run-an-agent) for the image, provider, and policy +[Run Your First Agent](/about/run-your-first-agent) for the image, provider, and policy workflow. diff --git a/docs/extensibility/drivers.mdx b/docs/extensibility/drivers.mdx index 1f6fdc0800..f3f5a6d42d 100644 --- a/docs/extensibility/drivers.mdx +++ b/docs/extensibility/drivers.mdx @@ -20,7 +20,18 @@ socket and negotiates its protocol version and capabilities before serving requests. For built-in driver configuration and behavior, refer to -[Runtimes](/reference/sandbox-compute-drivers). +[Runtimes](/how-it-works/sandboxes/runtimes). For implementation details, refer +to each driver crate: + +| Driver | Crate | +|---|---| +| Docker | [`openshell-driver-docker`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-docker/README.md) | +| Podman | [`openshell-driver-podman`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-podman/README.md) | +| MicroVM | [`openshell-driver-vm`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-vm/README.md) | +| Kubernetes | [`openshell-driver-kubernetes`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-kubernetes/README.md) | +| Windows MXC | [`openshell-driver-mxc`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-mxc/README.md) | + +External compute drivers implement [`compute_driver.proto`](https://github.com/NVIDIA/OpenShell/blob/main/proto/compute_driver.proto). ## Credential Drivers @@ -30,11 +41,20 @@ the secret value in the provider record. OpenShell includes database, Kubernetes Secret, and Vault-compatible credential drivers. Configure the active credential driver in the -[Gateway Configuration](/reference/gateway-config#credential-drivers). +[Gateway Configuration](/how-it-works/gateways/configuration#credential-drivers). +For implementation details, refer to each driver crate: + +| Driver | Crate | +|---|---| +| Database | [`openshell-driver-db-credstore`](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-driver-db-credstore) | +| Kubernetes Secrets | [`openshell-driver-kubernetes-secrets`](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-driver-kubernetes-secrets) | +| Vault | [`openshell-driver-vault`](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-driver-vault) | + +External credential drivers implement [`credential_driver.proto`](https://github.com/NVIDIA/OpenShell/blob/main/proto/credential_driver.proto). ## Compatibility Drivers exchange peer metadata with the gateway and advertise their extension family capability. Upgrade both peers together when the protocol version -changes. Refer to [Extension Protocol Negotiation](/extensibility/extension-negotiation) +changes. Refer to [Extension Protocol Negotiation](/extensibility/overview#protocol-negotiation) for the negotiation contract. diff --git a/docs/extensibility/extension-authentication.mdx b/docs/extensibility/extension-authentication.mdx deleted file mode 100644 index 3861c99aad..0000000000 --- a/docs/extensibility/extension-authentication.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "Extension Authentication" -sidebar-title: "Authentication" -slug: "extensibility/extension-authentication" -description: "Verify that calls to your gateway interceptor or supervisor middleware service come from your OpenShell gateway." -keywords: "OpenShell Extensions, Extension Authentication, JWT, JWKS, Audience, Gateway Interceptors, Supervisor Middleware" ---- - -When the gateway has JWT signing configured, OpenShell attaches a short-lived bearer token to every call it makes to a [gateway interceptor](/extensibility/gateway-interceptors) or [supervisor middleware](/extensibility/supervisor-middleware) service. Your service validates this token to confirm that the call comes from your gateway or one of its sandboxes. - -## Tokens OpenShell Sends - -Each token is an EdDSA-signed JWT scoped to one service registration: - - - `openshell-gateway:`. - - - - The registration's `audience`. Defaults to `urn:openshell:extension:interceptor:` or `urn:openshell:extension:middleware:`. - - - - `gateway` for calls from the gateway, or `supervisor` for middleware calls from a sandbox supervisor. - - - - The calling sandbox. Present only when `caller_kind` is `supervisor`. - - -Authenticated network services use `https://` endpoints. OpenShell verifies the service certificate against platform trust roots, or against the private CA in the registration's `tls_ca_cert_path`, and always checks the hostname. - -## Establish Trust in the Gateway - -Before your service can validate tokens, configure it with three values from the gateway operator: - -- The gateway URL. -- The gateway ID. Tokens use `openshell-gateway:` as their issuer. -- The gateway's public signing key or JWKS. - -Configure these values directly instead of discovering them from the gateway. A key fetched from an unverified source does not prove which gateway it belongs to. - -To pick up new keys later, fetch `/.well-known/openid-configuration` from the configured gateway URL over TLS, then fetch the keys from its `jwks_uri`. This document looks like OIDC discovery, but its `issuer` is `openshell-gateway:` rather than the gateway URL. Compare the token's `iss` with that value, not with the URL. - -## Validate Each Token - -Cache keys by `kid` and check that: - -- `typ` is exactly `openshell-ext+jwt`. -- `alg` is `EdDSA`. Pin the algorithm instead of reading it from the token. -- The signature, issuer, exact audience, and expiry are valid. -- `caller_kind` is one your service accepts, and `sandbox_id` matches your expectations when your service scopes behavior per sandbox. - -OpenShell reuses a token until it rotates, so do not reject a repeated `jti` as a replay. - -## Confirm the Audience at Startup - -Return the audience your service expects in the `expected_audience` field of its `Describe` manifest. After authentication succeeds, the gateway compares this value with the operator-configured `audience` and refuses to start when they differ. A strict service may reject a token with the wrong audience before returning its manifest, in which case gateway startup reports an authentication failure. Leave the field empty to skip this check. - -## Run Without Authentication - -Set `allow_insecure_transport = true` on a registration to use a plaintext `http://` endpoint. OpenShell then sends no token, and your service cannot distinguish OpenShell from any other client that can reach it. The gateway logs a warning for the registration at every startup. - -Use this setting for local development, or on a network that already authenticates callers. - -## Current Limitations - -- Tokens are bearer credentials. A captured token remains valid until it expires unless your service adds proof of possession or request binding. -- Extension tokens share a signing key with other tokens the gateway issues, so you cannot rotate or revoke extension credentials independently. -- mTLS client authentication and overlapping signing-key rotation are not available. diff --git a/docs/extensibility/extension-negotiation.mdx b/docs/extensibility/extension-negotiation.mdx deleted file mode 100644 index 6ffbeea9b0..0000000000 --- a/docs/extensibility/extension-negotiation.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "Extension Protocol Negotiation" -sidebar-title: "Protocol Negotiation" -slug: "extensibility/extension-negotiation" -description: "Implement version and capability negotiation for OpenShell extensions." -keywords: "OpenShell Extensions, Protocol Version, Capabilities, Version Skew, Migration" ---- - -OpenShell negotiates a common metadata envelope before it uses a compute driver, credential driver, gateway interceptor, or supervisor middleware service. Family-specific fields remain in each protocol; the common envelope determines whether the peers can safely interpret them. - -## Exchange Peer Metadata - -Both peers send `openshell.extension.v1.PeerMetadata` during the family's startup RPC. The gateway sends its metadata in `GetCapabilities` or `Describe`; the extension returns its metadata in the capability response or manifest. - -Set these fields: - -- `protocol_version` identifies the extension-family contract. OpenShell starts each family at `1.0`. -- `implementation_name` identifies the implementation, such as `example/acme-compute`. -- `implementation_version` identifies the extension build. Do not put the Docker, Kubernetes, Vault, or another backend's version here. -- `supported_capabilities` lists optional behavior the peer understands. -- `required_capabilities` lists behavior the opposite peer must support. - -Capability identifiers must start with `openshell.`, contain at least three lowercase dot-separated segments, and use only lowercase ASCII letters, digits, and hyphens within each segment. Each family requires its base contract capability: - -| Family | Base capability | -| --- | --- | -| Compute driver | `openshell.compute.contract` | -| Credential driver | `openshell.credentials.contract` | -| Gateway interceptor | `openshell.gateway-interceptor.contract` | -| Supervisor middleware | `openshell.supervisor-middleware.contract` | - -Do not repeat a capability. OpenShell rejects empty, malformed, duplicate, or oversized metadata instead of normalizing ambiguous input. - -## Version-Skew Policy - -OpenShell applies this compatibility matrix at startup: - -| Peer relationship | Result | -| --- | --- | -| Same major and same minor | Accepted when both requirement sets are satisfied. | -| Same major and different minor | Accepted when both requirement sets are satisfied. Unknown optional capabilities are retained for discovery and otherwise ignored. | -| Different major | Rejected with both protocol versions in the error. | -| Missing peer metadata or protocol version | Rejected with upgrade guidance. | -| Either peer lacks a capability required by the other | Rejected with the missing capability names. | - -Minor releases must keep existing fields and behavior compatible. Add a capability when a peer must detect an optional behavior. Increment the protocol major when requirements cannot express a safe additive transition. - -## Preserve Family-Specific Capabilities - -Keep typed family data beside the common envelope. Compute resource capabilities, credential-driver feature flags, interceptor bindings, and middleware operation/phase bindings remain authoritative for their domains. Do not flatten typed values into capability strings. - -Built-in and external extensions follow the same validator. A built-in cannot bypass protocol version or requirement checks merely because it runs in the gateway process. - -## Migrate an Extension - -1. Regenerate bindings from the current OpenShell protobuf files. Supervisor middleware authors must update `Describe` from `google.protobuf.Empty` to `MiddlewareDescribeRequest`. -2. Read and validate the gateway metadata supplied in the startup request. -3. Return protocol `1.0`, a stable implementation name, the extension build version, the family base capability, and any additional supported or required capabilities. -4. Schedule a coordinated gateway and extension upgrade. There is no supported mixed legacy/current pairing: current extensions reject legacy gateways that omit metadata, and current gateways reject legacy extensions that omit metadata. Stop traffic, upgrade both peers, and restart them together. -5. Run mixed-minor tests with required capabilities present and absent after both peers implement negotiation. Verify that a major mismatch and missing metadata fail before runtime traffic. - -The legacy compute and credential `driver_version` fields and middleware `service_version` field remain populated during migration. New integrations must use `PeerMetadata.implementation_version`; the legacy fields are diagnostic compatibility fields and may be removed in a future protocol major. - -## Inspect Negotiated Extensions - -Admins can run `openshell gateway info` or call protected `GetGatewayInfo`. The response contains a sorted snapshot captured at startup: family, configured name, implementation identity/version, protocol version, supported capabilities, and extension requirements. - -The snapshot excludes endpoints, audiences, bearer tokens, certificates, backend configuration, and free-form extension diagnostics. diff --git a/docs/extensibility/gateway-interceptors.mdx b/docs/extensibility/gateway-interceptors.mdx index 96b091dbca..212c3fe245 100644 --- a/docs/extensibility/gateway-interceptors.mdx +++ b/docs/extensibility/gateway-interceptors.mdx @@ -49,7 +49,7 @@ An interceptor implements the `openshell.gateway_interceptor.v1.GatewayIntercept - `Evaluate` handles one selected operation phase. - `SnapshotProviderProfiles` optionally returns a provider profile catalog. -`DescribeRequest` carries gateway protocol metadata, and `InterceptorManifest.extension` returns the interceptor's protocol and implementation metadata. The gateway rejects missing metadata, incompatible majors, and unmet required capabilities before it accepts bindings. See [Extension Protocol Negotiation](/extensibility/extension-negotiation). +`DescribeRequest` carries gateway protocol metadata, and `InterceptorManifest.extension` returns the interceptor's protocol and implementation metadata. The gateway rejects missing metadata, incompatible majors, and unmet required capabilities before it accepts bindings. See [Extension Protocol Negotiation](/extensibility/overview#protocol-negotiation). Each `InterceptorEvaluation` identifies the configured interceptor, manifest binding, public OpenShell service and method, authenticated principal, and active phase. The phase determines whether the payload contains a proposed operation, optional current state, or committed response. @@ -97,9 +97,9 @@ phases = ["validate"] The gateway supports `http://`, `https://`, and `unix://` interceptor endpoints. When gateway JWT signing is configured, authenticated network interceptors use `https://`; Unix sockets remain available for local integrations. HTTPS uses platform trust roots unless `tls_ca_cert_path` supplies a private CA, and normal hostname verification remains enabled. The gateway calls `Describe` and builds an immutable execution plan during startup. An unavailable service, invalid manifest, missing credential, or unauthorized configured binding prevents the gateway from starting. -When gateway JWT signing is configured, the gateway authenticates every call to the interceptor with a short-lived token. [Extension Authentication](/extensibility/extension-authentication) describes how your service validates it. Set `allow_insecure_transport = true` to use a plaintext `http://` endpoint without authentication, for local development or on a network that already authenticates callers. +When gateway JWT signing is configured, the gateway authenticates every call to the interceptor with a short-lived token. [Extension Authentication](/extensibility/overview#authentication) describes how your service validates it. Set `allow_insecure_transport = true` to use a plaintext `http://` endpoint without authentication, for local development or on a network that already authenticates callers. -Registration is static. Restart the gateway after adding, removing, or changing an interceptor. See [Gateway Configuration](/reference/gateway-config#gateway-interceptors) for the complete field reference. +Registration is static. Restart the gateway after adding, removing, or changing an interceptor. See [Gateway Configuration](/how-it-works/gateways/configuration#gateway-interceptors) for the complete field reference. ## Select RPCs and Phases @@ -170,5 +170,5 @@ The gateway emits structured evaluation logs containing the interceptor name, bi - Only explicitly allowlisted unary write RPCs are interceptable. New gateway RPCs are non-interceptable until added to the allowlist. - `current_state` is available only in the `validate` contract. The gateway does not yet populate it with method-specific state. - Registration changes require a gateway restart. -- Service health checks and runtime registration are not available. [Extension Authentication](/extensibility/extension-authentication#current-limitations) lists authentication limitations. +- Service health checks and runtime registration are not available. [Extension Authentication](/extensibility/overview#current-limitations) lists authentication limitations. - Interceptors cannot receive or mutate protobuf fields marked secret. diff --git a/docs/extensibility/isolation-backends.mdx b/docs/extensibility/isolation-backends.mdx index 5b6856c956..fc1a33b4ee 100644 --- a/docs/extensibility/isolation-backends.mdx +++ b/docs/extensibility/isolation-backends.mdx @@ -6,21 +6,43 @@ description: "Understand the runtime boundary used to launch and supervise sandb keywords: "OpenShell Extensions, Isolation Backends, Sandbox Runtime, Extensibility" --- -An isolation backend connects the OpenShell supervisor to the runtime that -launches and controls a sandboxed workload. It defines how the supervisor -starts processes, attaches terminal streams, forwards signals, reports exit -status, and applies runtime-specific isolation. - -OpenShell separates this interface from compute drivers. A compute driver -provisions the workload environment, while the isolation backend controls -process execution inside that environment. This boundary lets runtimes evolve -without changing the gateway API or policy model. - -The OpenShell runtime backend implements the authenticated OpenShell Sandbox -Protocol used by the supervisor and `openshell-sandbox`. Backend selection and -capabilities remain internal to the workload runtime; users create and manage -sandboxes through the same gateway API. - -For the deployment-level runtime architecture, refer to -[Sandbox Runtime](/kubernetes/sandbox-runtime). For driver-specific workload -behavior, refer to [Runtimes](/reference/sandbox-compute-drivers). +The supervisor uses one Rust interface, `IsolationBackend`, to launch and +control the agent workload. `OpenShellRuntimeBackend` implements that interface +by calling `openshell-sandbox` over the OpenShell Sandbox Protocol. Because the +supervisor depends only on the interface, another backend can provide the same +operations with different isolation mechanisms without changing the gateway API +or policy model. + +![The supervisor calls the IsolationBackend interface. OpenShellRuntimeBackend implements it as a supervisor-side client and talks to openshell-sandbox, the workload-side server, over the Sandbox Protocol.](../images/openshell-isolation-backend.svg) + +## The Interface + +Each step returns a new type, so the supervisor can't start an agent on a +boundary that hasn't been confirmed. The traits are defined in +[`contract.rs`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-isolation-interface/src/contract.rs) +in the +[`openshell-isolation-interface`](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-isolation-interface) +crate. `OpenShellRuntimeBackend` is implemented in +[`openshell-sandbox-backend`](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-sandbox-backend). + +| Rust surface | What it does | Returns | +|---|---|---| +| `IsolationBackend::attach()` | Binds a verified runtime descriptor to one admitted sandbox. | `BoundBoundary` | +| `BoundBoundary::confirm()` | Checks the workload's controls before any agent code runs. | `ConfirmedBoundary` | +| `ReadyBoundary::start_agent()` | Rechecks launch controls and starts the agent. | `RunningBoundary` | +| `RunningBoundary::agent()` | Waits for, signals, attaches to, or stops the agent process. | `BoundaryProcess` | +| `RunningBoundary::exec()` | Starts exec and terminal sessions inside the same boundary. | `BoundaryExec` | +| `RunningBoundary::loopback_connector()` | Reaches a loopback service inside the workload for forwarding. | `BoundaryLoopbackConnector` | +| `BoundBoundary::network_mediation_source()` | Receives TCP opens and DNS queries tagged with the calling program. | `NetworkMediationSource` | + +## Who Owns What + +| Component | Owns | +|---|---| +| Supervisor | Policy decisions. Policy, credentials, DNS resolution, and approved external connections stay outside the agent workload. | +| Compute driver | Placement and fencing. The driver creates runtime resources, installs the outer egress fence, and supplies a verified descriptor. | +| Isolation backend | Common behavior. The backend turns the shared Rust calls into a protected session with the sandbox runtime. | + +For how `openshell-sandbox` enforces the boundary, refer to +[Sandbox](/about/architecture/sandbox). For driver-specific workload behavior, +refer to [Runtimes](/how-it-works/sandboxes/runtimes). diff --git a/docs/extensibility/overview.mdx b/docs/extensibility/overview.mdx index 44c9da6f15..952d6e925f 100644 --- a/docs/extensibility/overview.mdx +++ b/docs/extensibility/overview.mdx @@ -1,43 +1,139 @@ --- -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 title: "Extensibility" sidebar-title: "Overview" slug: "extensibility/overview" -description: "Extend OpenShell with custom traffic checks, gateway governance, drivers, and isolation backends." -keywords: "OpenShell Extensions, Protocol Negotiation, Supervisor Middleware, Gateway Interceptors, Compute Drivers, Credential Drivers, Isolation Backends" +description: "Understand how OpenShell adapts to deployment-specific infrastructure, governance, and workload requirements." +keywords: "OpenShell Extensions, Middleware, Interceptors, Drivers, Isolation Backends, Protocol Negotiation" --- -OpenShell has several extension points that let you connect your own services and runtimes without changing OpenShell. Choose an extension point based on what you need to control, then implement the shared extension protocol that every extension service uses. +![OpenShell extension points across the gateway and runtime: gateway interceptors, compute and credential drivers, supervisor middleware, and isolation backends.](../images/openshell-extension-points.svg) -## Extension Protocol +Extensibility sits at the core of OpenShell. OpenShell is designed to run +everywhere and adapt to the infrastructure, governance, and workload +requirements of each deployment. Its extension points add deployment-specific +behavior while preserving the same API, policy model, and security boundaries. -Before OpenShell uses an extension service, both peers exchange their protocol version and supported capabilities. This lets OpenShell and your service detect incompatible versions at startup instead of failing on live traffic. [Extension Protocol Negotiation](/extensibility/extension-negotiation) describes the metadata to exchange and the version-skew policy. +## Extension Points -Extension services reachable over the network also need to know that a call comes from your OpenShell gateway. [Extension Authentication](/extensibility/extension-authentication) describes the tokens OpenShell attaches and how your service validates them. +### [Middleware](/extensibility/supervisor-middleware) -## Extension Points +Supervisor middleware inspects, transforms, or denies allowed HTTP and +WebSocket traffic. It runs after policy evaluation and before OpenShell injects +provider credentials, so deployments can add content controls and auditing +without exposing managed secrets. + +### [Gateway Interceptors](/extensibility/gateway-interceptors) + +Gateway interceptors add governance to selected control-plane operations. They +can modify or validate proposed API writes and observe successful changes while +the gateway retains authentication, persistence, and final validation. + +### [Drivers](/extensibility/drivers) + +Compute drivers place and manage sandboxes on deployment-specific runtimes. +Credential drivers connect provider records to the deployment's secret store. +Together, they adapt OpenShell to the infrastructure it runs on. + +### [Isolation Backends](/extensibility/isolation-backends) + +Isolation backends connect the supervisor to the sandbox runtime. They provide +a consistent contract for process launch, terminal streams, signals, status, +and runtime-specific isolation inside the provisioned workload. + +## Authentication + +When the gateway has JWT signing configured, OpenShell sends a short-lived bearer token with every call to a [gateway interceptor](/extensibility/gateway-interceptors) or [supervisor middleware](/extensibility/supervisor-middleware) service. Validate it to confirm the call comes from your gateway or one of its sandboxes. + +| Claim | Value | +|---|---| +| `iss` | `openshell-gateway:` | +| `aud` | The registration's `audience`. Defaults to `urn:openshell:extension:interceptor:` or `urn:openshell:extension:middleware:`. | +| `caller_kind` | `gateway`, or `supervisor` for middleware calls from a sandbox. | +| `sandbox_id` | The calling sandbox, when `caller_kind` is `supervisor`. | + +### Validate Each Token + +Get the gateway ID and public signing key (or JWKS) from the gateway operator and configure them in your service. Don't trust a key discovered from an unverified source. To pick up rotated keys, fetch `/.well-known/openid-configuration` from the gateway over TLS and follow its `jwks_uri`. + +For each request, check that: + +- `typ` is `openshell-ext+jwt` and `alg` is `EdDSA`. Pin the algorithm; don't read it from the token. +- The signature, expiry, and exact audience are valid. +- `iss` is `openshell-gateway:`, not the gateway URL. +- `caller_kind` and `sandbox_id` match what your service accepts. + +OpenShell reuses a token until it rotates, so don't reject a repeated `jti`. + +Services must use `https://` endpoints. OpenShell verifies the certificate and hostname against platform roots, or against `tls_ca_cert_path` for a private CA. + +### Confirm the Audience at Startup + +Return your expected audience in the `expected_audience` field of your `Describe` manifest. The gateway refuses to start if it doesn't match the configured `audience`. Leave it empty to skip the check. + +### Run Without Authentication + +Set `allow_insecure_transport = true` on a registration to use a plaintext `http://` endpoint with no token. Your service then can't tell OpenShell apart from any other client, and the gateway logs a warning at every startup. Use this only for local development or on a network that already authenticates callers. + +### Current Limitations + +- Tokens are bearer credentials: a captured token works until it expires. +- Extension tokens share the gateway's signing key, so you can't rotate or revoke them separately. +- mTLS client authentication and overlapping key rotation aren't available. + +## Building Extensions + +Start with the narrowest extension point that owns the behavior you need. Keep +control-plane governance in an interceptor, infrastructure integration in a +driver, application traffic processing in middleware, and workload control in +an isolation backend. Each extension uses a typed contract so OpenShell keeps +ownership of authentication, policy enforcement, secrets, and public API +behavior. - +Built-in and external implementations follow the same contracts and validation +rules. The extension-specific pages describe their APIs, configuration, and +security boundaries. - +### gRPC and Transports -Check or change the content an agent sends and receives over the network, such as redacting API tokens from outgoing requests or blocking prohibited content. - +External extensions implement protobuf-defined gRPC services. The transport +depends on where the extension runs and which OpenShell components must reach +it: - +| Extension | Integration | Supported transport | +| --- | --- | --- | +| Gateway interceptor | The gateway calls the interceptor service. | TCP with `http://` or `https://`, or a local Unix domain socket with `unix://`. | +| Supervisor middleware | The gateway discovers the service, and sandbox supervisors evaluate traffic through it. | TCP with `http://` or `https://`. The endpoint must be reachable from both the gateway and supervisors, so Unix sockets are not supported. | +| Compute or credential driver | The gateway calls an external driver service. | A local Unix domain socket. | +| OpenShell isolation backend | The supervisor connects to the sandbox boundary through the OpenShell Sandbox Protocol. | A private Unix socket, TLS over TCP, or virtio-vsock selected and provisioned by the compute driver. | -Enforce rules on how people and applications manage OpenShell resources, such as applying an approved policy to new sandboxes or auditing completed operations. - +Use Unix domain sockets when the gateway and extension share a host. Use +`https://` when a service crosses a host or pod boundary. Plaintext `http://` +is intended for explicitly enabled development deployments; authenticated +network extensions use TLS and short-lived gateway-issued credentials. Refer +to [Authentication](#authentication) for how services validate those credentials. - +The [governance interceptor example](https://github.com/NVIDIA/OpenShell/tree/main/examples/governance-interceptor) +and [content guard middleware example](https://github.com/NVIDIA/OpenShell/tree/main/examples/supervisor-middleware-content-guard) +include complete gRPC services, gateway configuration, and smoke tests. For +runtime integrations, refer to the first-party +[Docker compute driver](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-driver-docker) +and [VM compute driver](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-driver-vm). -Connect the gateway to the runtimes that host sandbox workloads and to the stores that hold provider credentials. - +### Protocol Negotiation - +Before OpenShell uses a compute driver, credential driver, gateway interceptor, +or supervisor middleware service, both peers exchange +`openshell.extension.v1.PeerMetadata`. The metadata identifies the protocol and +implementation versions, supported capabilities, and capabilities required +from the other peer. Family-specific features remain in their typed protocols. -Understand the runtime boundary the supervisor uses to launch and control processes inside a sandbox. - +OpenShell accepts compatible minor versions when both capability requirements +are satisfied. It rejects different major versions, missing metadata, or an +unmet required capability during startup. Built-in and external service +extensions follow the same compatibility checks. - +Use `openshell gateway info` to inspect the negotiated extension families, +implementation versions, protocol versions, and capabilities active on a +gateway. diff --git a/docs/extensibility/supervisor-middleware/configure.mdx b/docs/extensibility/supervisor-middleware/configure.mdx index 0a42dc1412..eec1bceee0 100644 --- a/docs/extensibility/supervisor-middleware/configure.mdx +++ b/docs/extensibility/supervisor-middleware/configure.mdx @@ -53,16 +53,16 @@ timeout = "500ms" - Token audience. Refer to [Extension Authentication](/extensibility/extension-authentication). + Token audience. Refer to [Extension Authentication](/extensibility/overview#authentication). Allows a plaintext `http://` endpoint with no authentication. Use it for local development or on a network that already authenticates callers. -At startup, the gateway contacts every registered service to read its capabilities and verify [protocol compatibility](/extensibility/extension-negotiation). The gateway does not start if a service is unavailable or incompatible. [Gateway Configuration](/reference/gateway-config#supervisor-middleware-services) describes the full TOML context. +At startup, the gateway contacts every registered service to read its capabilities and verify [protocol compatibility](/extensibility/overview#protocol-negotiation). The gateway does not start if a service is unavailable or incompatible. [Gateway Configuration](/how-it-works/gateways/configuration#supervisor-middleware-services) describes the full TOML context. -When the gateway has JWT signing configured, OpenShell authenticates every call to your service with a short-lived token. [Extension Authentication](/extensibility/extension-authentication) describes how your service validates it. +When the gateway has JWT signing configured, OpenShell authenticates every call to your service with a short-lived token. [Extension Authentication](/extensibility/overview#authentication) describes how your service validates it. ## Attach Middleware in Policy @@ -161,7 +161,7 @@ The map key, such as `content-guard`, is the entry's stable identity in logs. Ea Display name. Defaults to the map key. -[Policy Schema](/reference/policy-schema#network-middleware) lists every field and limit. +[Policy Schema](/how-it-works/policies/schema#network-middleware) lists every field and limit. ## Choose Failure Behavior diff --git a/docs/extensibility/supervisor-middleware/index.mdx b/docs/extensibility/supervisor-middleware/index.mdx index 50c5835621..ce084185a0 100644 --- a/docs/extensibility/supervisor-middleware/index.mdx +++ b/docs/extensibility/supervisor-middleware/index.mdx @@ -76,13 +76,13 @@ A middleware service is a gRPC server that implements the services in [`proto/su -The middleware API is still evolving. Future versions will change it to make the contract consistent across HTTP requests, HTTP responses, and WebSocket messages. Expect to update your service when you upgrade OpenShell. [Protocol negotiation](/extensibility/extension-negotiation) detects incompatible versions at startup. +The middleware API is still evolving. Future versions will change it to make the contract consistent across HTTP requests, HTTP responses, and WebSocket messages. Expect to update your service when you upgrade OpenShell. [Protocol negotiation](/extensibility/overview#protocol-negotiation) detects incompatible versions at startup. Every middleware service implements these RPCs: -- `Describe` returns the service manifest. The manifest lists the operations the service supports, with a payload limit and optional timeout for each. It also carries [protocol negotiation](/extensibility/extension-negotiation) metadata and the [expected audience](/extensibility/extension-authentication#confirm-the-audience-at-startup). +- `Describe` returns the service manifest. The manifest lists the operations the service supports, with a payload limit and optional timeout for each. It also carries [protocol negotiation](/extensibility/overview#protocol-negotiation) metadata and the [expected audience](/extensibility/overview#confirm-the-audience-at-startup). - `ValidateConfig` checks the `config` object from a policy entry. The gateway calls it before it accepts a policy. The service then implements an evaluation RPC for each operation it supports, as described in [Supported Operations](/extensibility/supervisor-middleware/operations). @@ -98,12 +98,12 @@ These guides cover the rest of the service contract: When OpenShell calls your service, what it receives, and what it can return for HTTP requests, HTTP responses, and WebSocket messages. - + How to verify that calls to your service come from your OpenShell gateway. - + How your service and OpenShell agree on a protocol version at startup. diff --git a/docs/reference/gateway-auth.mdx b/docs/how-it-works/gateways/authentication.mdx similarity index 99% rename from docs/reference/gateway-auth.mdx rename to docs/how-it-works/gateways/authentication.mdx index 644060dd2b..a05cf7f678 100644 --- a/docs/reference/gateway-auth.mdx +++ b/docs/how-it-works/gateways/authentication.mdx @@ -7,7 +7,7 @@ keywords: "Generative AI, Cybersecurity, Gateway, Authentication, mTLS, OIDC, Op position: 1 --- -This page describes how the CLI resolves a gateway, authenticates with it, and where credentials are stored. For how to deploy or register gateways, refer to [Gateways](/sandboxes/manage-gateways). +This page describes how the CLI resolves a gateway, authenticates with it, and where credentials are stored. For how to deploy or register gateways, refer to [Gateways](/how-it-works/gateways/overview). ## Gateway Resolution @@ -199,7 +199,7 @@ For a headless environment, set `OPENSHELL_NO_BROWSER=1` before registering or l 6. The gateway authorizes the gRPC method. Platform-scoped methods require the configured admin role. Workspace-scoped methods require the configured user role and a sufficient membership in the target workspace. Admin role holders satisfy user-role checks and bypass workspace membership checks. For the Platform Admin, Workspace Admin, and Workspace User permissions, refer -to [Workspaces](/sandboxes/manage-workspaces). +to [Workspaces](/how-it-works/workspaces). #### JWT validation @@ -242,7 +242,7 @@ display name when available, identity provider, roles, and scopes. The gateway returns its validated identity; the CLI does not infer these values from an unverified local token payload. Use the `subject` value when adding the user to a workspace. For membership commands, refer to -[Workspaces](/sandboxes/manage-workspaces). +[Workspaces](/how-it-works/workspaces). ### Edge JWT (cloud gateways) diff --git a/docs/reference/gateway-config.mdx b/docs/how-it-works/gateways/configuration.mdx similarity index 98% rename from docs/reference/gateway-config.mdx rename to docs/how-it-works/gateways/configuration.mdx index 79a986058d..c1963c3253 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/how-it-works/gateways/configuration.mdx @@ -362,7 +362,7 @@ Each service implements the supervisor middleware gRPC contract and exposes bind The gateway connects to every registered service and validates `Describe` before it starts. The service must therefore be running before the gateway. Policy creation and full policy updates call `ValidateConfig`; an unavailable service or invalid middleware configuration rejects the policy before persistence. -Startup also requires compatible [extension protocol metadata](/extensibility/extension-negotiation). Upgrade legacy gateways and operator-run services together during a coordinated outage; neither mixed legacy/current pairing is supported. A service rejects a gateway that omits peer metadata, and a gateway rejects a service that omits metadata, uses another protocol major, or requires unsupported gateway capabilities. Protected `GetGatewayInfo` and `openshell gateway info` report the resulting non-secret snapshot. +Startup also requires compatible [extension protocol metadata](/extensibility/overview#protocol-negotiation). Upgrade legacy gateways and operator-run services together during a coordinated outage; neither mixed legacy/current pairing is supported. A service rejects a gateway that omits peer metadata, and a gateway rejects a service that omits metadata, uses another protocol major, or requires unsupported gateway capabilities. Protected `GetGatewayInfo` and `openshell gateway info` report the resulting non-secret snapshot. `max_payload_bytes` is the shared operator limit for inspectable logical payloads across every binding exposed by the service. It caps HTTP request and response units, replacement bodies, and complete WebSocket text messages and replacements. Whole-response inspection uses it as the stage's total body limit. Streaming response inspection applies it to each unit. The value must be greater than zero, no larger than each binding's advertised `max_payload_bytes` capability, and no larger than the 4 MiB platform maximum. OpenShell rejects oversized values instead of silently clamping them. Binary WebSocket messages are not exposed to V1 middleware, so this field does not limit binary pass-through. Middleware gRPC servers should allow messages of at least 4 MiB plus 293 KiB so a maximum-size payload and its protobuf envelope fit on the transport. @@ -378,7 +378,7 @@ See [Supervisor Middleware Configuration](/extensibility/supervisor-middleware/c `[[openshell.gateway.interceptors]]` configures gateway-side interceptor services. The gateway calls each service's `Describe` RPC at startup, validates its declared OpenShell RPC bindings against the compiled service descriptor, and applies matching phases from a central gRPC middleware path. Interceptors can target only methods in the gateway's built-in allowlist of unary mutation RPCs. New RPCs are non-interceptable until they are deliberately added to that allowlist; adding one does not require handler-specific interceptor code. Request bodies are exposed as protobuf JSON objects. Fields marked secret in the protobuf schema are recursively omitted from requests and post-commit responses. Interceptors cannot patch an omitted field or a containing object. -Each interceptor must also complete [extension protocol negotiation](/extensibility/extension-negotiation) during `Describe`. Upgrade legacy gateways and interceptors together during a coordinated outage; neither mixed legacy/current pairing is supported. The interceptor rejects missing or incompatible gateway metadata, and the gateway rejects missing metadata, incompatible protocol majors, and unmet requirements before serving requests. +Each interceptor must also complete [extension protocol negotiation](/extensibility/overview#protocol-negotiation) during `Describe`. Upgrade legacy gateways and interceptors together during a coordinated outage; neither mixed legacy/current pairing is supported. The interceptor rejects missing or incompatible gateway metadata, and the gateway rejects missing metadata, incompatible protocol majors, and unmet requirements before serving requests. HTTPS interceptor endpoints use the platform trust store by default. Set `tls_ca_cert_path` to a PEM certificate bundle for a private CA; normal TLS hostname verification still applies. `audience` sets the exact audience for gateway-minted service tokens and defaults to `urn:openshell:extension:interceptor:`. After authenticated `Describe` succeeds, the gateway treats a non-empty manifest `expected_audience` as a consistency assertion and refuses to start when it differs from the configured audience. A strict verifier may reject an incorrect audience before returning the manifest. When `gateway_jwt` is configured, network interceptors must use HTTPS and receive short-lived gateway-caller bearer credentials; local Unix sockets are also supported. Set `allow_insecure_transport = true` to keep a plaintext `http://` interceptor endpoint with no credential attached and a startup warning. diff --git a/docs/reference/container-gateway.mdx b/docs/how-it-works/gateways/container-deployment.mdx similarity index 97% rename from docs/reference/container-gateway.mdx rename to docs/how-it-works/gateways/container-deployment.mdx index fc52cf2b1a..e42ede6bc4 100644 --- a/docs/reference/container-gateway.mdx +++ b/docs/how-it-works/gateways/container-deployment.mdx @@ -197,6 +197,6 @@ podman run -d \ ## Next Steps -- To prepare an image and launch an agent, refer to [Run Your First Agent](/about/run-an-agent). -- To control what the agent can access, refer to [Policies](/sandboxes/policies). -- For environment variable reference, refer to [Sandbox Runtimes](/reference/sandbox-compute-drivers). +- To prepare an image and launch an agent, refer to [Run Your First Agent](/about/run-your-first-agent). +- To control what the agent can access, refer to [Policies](/how-it-works/policies/overview). +- For environment variable reference, refer to [Sandbox Runtimes](/how-it-works/sandboxes/runtimes). diff --git a/docs/sandboxes/manage-gateways.mdx b/docs/how-it-works/gateways/overview.mdx similarity index 98% rename from docs/sandboxes/manage-gateways.mdx rename to docs/how-it-works/gateways/overview.mdx index 0514e012ed..ee1f735fa3 100644 --- a/docs/sandboxes/manage-gateways.mdx +++ b/docs/how-it-works/gateways/overview.mdx @@ -74,7 +74,7 @@ This opens your browser for the proxy's login flow when the gateway uses edge au openshell gateway login production ``` -For direct mTLS endpoints, place the CLI client certificate bundle in the gateway credential directory described in [Gateway Authentication](/reference/gateway-auth), then register or select that gateway name. +For direct mTLS endpoints, place the CLI client certificate bundle in the gateway credential directory described in [Gateway Authentication](/how-it-works/gateways/authentication), then register or select that gateway name. ## Manage Multiple Gateways @@ -195,5 +195,5 @@ For sandbox startup failures, inspect the selected compute driver: ## Next Steps - To install OpenShell and choose a compute driver, refer to [Installation](/about/installation). -- To configure workspace membership and roles, refer to [Workspaces](/sandboxes/manage-workspaces). -- To create a sandbox using the gateway, refer to [Manage Sandboxes](/sandboxes/manage-sandboxes). +- To configure workspace membership and roles, refer to [Workspaces](/how-it-works/workspaces). +- To create a sandbox using the gateway, refer to [Manage Sandboxes](/how-it-works/sandboxes/overview). diff --git a/docs/sandboxes/inference-routing.mdx b/docs/how-it-works/inference.mdx similarity index 91% rename from docs/sandboxes/inference-routing.mdx rename to docs/how-it-works/inference.mdx index 4ba63ea7ca..f01c2cf36a 100644 --- a/docs/sandboxes/inference-routing.mdx +++ b/docs/how-it-works/inference.mdx @@ -24,11 +24,13 @@ This keeps the complete access contract in one place: ## Define and Attach a Hosted Provider -Start from an existing profile, review its access, and import it under a new -ID. For example, export the NVIDIA profile: +Start from the [NVIDIA example profile](https://github.com/NVIDIA/OpenShell/blob/main/providers/nvidia.yaml), +review its access, and import an edited copy under a new ID. A new gateway has +no profiles to export. Download the example so you can add the Python paths +used by this workload: ```shell -openshell provider profile export nvidia -o yaml --global > nvidia-native.yaml +curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/nvidia.yaml -o nvidia-native.yaml ``` In `nvidia-native.yaml`, change `id` to `nvidia-native`, give the profile a @@ -50,8 +52,8 @@ Lint and import the complete edited profile, then create a provider from its new ID: ```shell -openshell provider profile lint -f nvidia-native.yaml -openshell provider profile import -f nvidia-native.yaml +openshell profile lint -f nvidia-native.yaml +openshell profile import -f nvidia-native.yaml openshell provider create \ --name nvidia-prod \ @@ -156,8 +158,8 @@ binaries: Import the profile, create an instance, and attach it: ```shell -openshell provider profile lint -f ollama-openai.yaml -openshell provider profile import -f ollama-openai.yaml +openshell profile lint -f ollama-openai.yaml +openshell profile import -f ollama-openai.yaml openshell provider create --name ollama --type ollama-openai openshell sandbox create \ @@ -248,10 +250,10 @@ Export the old provider type's profile, edit its ID and access contract, import it, and create a replacement provider from the original credential source: ```shell -openshell provider profile export nvidia -o yaml > nvidia-native.yaml +openshell profile export nvidia -o yaml > nvidia-native.yaml # Edit id, display_name, endpoints, and binaries in nvidia-native.yaml. -openshell provider profile lint -f nvidia-native.yaml -openshell provider profile import -f nvidia-native.yaml +openshell profile lint -f nvidia-native.yaml +openshell profile import -f nvidia-native.yaml openshell provider create \ --name nvidia-native-prod \ --type nvidia-native \ @@ -297,7 +299,7 @@ Special cases require additional work: - Host-local services need `host.openshell.internal` or a reachable LAN/service hostname, not `127.0.0.1` or `localhost`. - Google Vertex AI clients must use the native Vertex endpoint and - authentication behavior. See [Google](/providers/google-cloud#vertex-ai). + authentication behavior. See [Google](/how-it-works/providers/google#vertex-ai). - A bridge-fronted AWS Bedrock deployment needs a custom profile that declares the bridge endpoint and allowed client binaries. @@ -312,7 +314,7 @@ headers, model selection, request shape, streaming, and timeout behavior. ## Next Steps -- [Profiles](/providers/profiles) -- [Providers](/sandboxes/manage-providers) -- [Customize Sandbox Policies](/sandboxes/policies) -- [Google](/providers/google-cloud#vertex-ai) +- [Profiles](/how-it-works/providers/profiles) +- [Providers](/how-it-works/providers/overview) +- [Customize Sandbox Policies](/how-it-works/policies/overview) +- [Google](/how-it-works/providers/google#vertex-ai) diff --git a/docs/sandboxes/policy-advisor.mdx b/docs/how-it-works/policies/advisor.mdx similarity index 96% rename from docs/sandboxes/policy-advisor.mdx rename to docs/how-it-works/policies/advisor.mdx index 56e71f2bed..b6f7acd0af 100644 --- a/docs/sandboxes/policy-advisor.mdx +++ b/docs/how-it-works/policies/advisor.mdx @@ -191,7 +191,7 @@ For REST APIs, prefer L7 rules over broad L4 access. A good proposal allows one } ``` -The current `policy.local` JSON shape covers explicit-proxy endpoints and REST method or path rules. Agent-authored proposals cannot set `protocol: tcp` or `tls: skip`, because those modes bypass application-authority inspection. When a task requires native TCP or a raw TLS tunnel, a developer must add the rule through the normal policy-authoring workflow. Omitting `protocol` remains supported and retains the explicit proxy's default TLS termination and HTTP authority checks. Use [Customize Sandbox Policies](/sandboxes/policies) or [Policy Schema Reference](/reference/policy-schema) for policy fields that are not part of the agent-authored proposal surface, such as WebSocket credential rewrite, GraphQL operation matching, endpoint path scoping, and provider-owned policy bundles. +The current `policy.local` JSON shape covers explicit-proxy endpoints and REST method or path rules. Agent-authored proposals cannot set `protocol: tcp` or `tls: skip`, because those modes bypass application-authority inspection. When a task requires native TCP or a raw TLS tunnel, a developer must add the rule through the normal policy-authoring workflow. Omitting `protocol` remains supported and retains the explicit proxy's default TLS termination and HTTP authority checks. Use [Customize Sandbox Policies](/how-it-works/policies/overview) or [Policy Schema Reference](/how-it-works/policies/schema) for policy fields that are not part of the agent-authored proposal surface, such as WebSocket credential rewrite, GraphQL operation matching, endpoint path scoping, and provider-owned policy bundles. Policy advisor proposals do not add `allowed_ips` automatically. If an advisor-proposed hostname resolves to an internal or private address, OpenShell's SSRF protections still block the connection until a developer explicitly adds the required `allowed_ips` entry. @@ -216,7 +216,7 @@ Findings are categorical. There is no severity tier. The reviewer reads the cate Before approval, the gateway rebuilds the candidate token from the live base policy, immutable provider rules, and non-secret credential metadata. When that token is unchanged, it reuses the persisted prover result instead of rerunning the prover. When it changes, the gateway evaluates and persists the refreshed candidate, leaves the chunk pending, and requires the reviewer to inspect and approve the new token. Edits and deduplicated resubmissions follow the same path. Merge, policy-shape, provider-composition, credential, or prover failures are shown as application errors and cannot be approved. Security notes flag concerns such as internal or private destinations and `allowed_ips`, wildcard hosts, hostless `allowed_ips`, ephemeral ports, and well-known database or service ports. Any prover finding or security note keeps the chunk pending in auto mode. -The full reasoning model lives in [`crates/openshell-prover/README.md`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-prover/README.md). Provider profiles composed in via [Profiles](/providers/profiles) are part of the effective policy the prover reasons over. +The full reasoning model lives in [`crates/openshell-prover/README.md`](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-prover/README.md). Provider profiles composed in via [Profiles](/how-it-works/providers/profiles) are part of the effective policy the prover reasons over. ## Review Proposals @@ -272,7 +272,7 @@ If policy advisor is disabled, every route returns `404 feature_disabled`, the s ## What to Expect -Approved network rules hot-reload without restarting the sandbox. HTTP L7 keep-alive connections are closed at the reload boundary so the next parsed request uses the new policy. Raw streams remain connection-scoped, as described in [Customize Sandbox Policies](/sandboxes/policies#policy-structure). +Approved network rules hot-reload without restarting the sandbox. HTTP L7 keep-alive connections are closed at the reload boundary so the next parsed request uses the new policy. Raw streams remain connection-scoped, as described in [Customize Sandbox Policies](/how-it-works/policies/overview#policy-structure). Policy advisor emits audit events into the sandbox log. Use these lines to trace the full loop: @@ -284,6 +284,6 @@ Look for `HTTP:* DENIED`, `CONFIG:PROPOSED`, `CONFIG:APPROVED` or `CONFIG:REJECT ## Next Steps -- Use [Customize Sandbox Policies](/sandboxes/policies) for manual policy updates and L7 rule syntax. -- Use [Policy Schema Reference](/reference/policy-schema) for full YAML field details. +- Use [Customize Sandbox Policies](/how-it-works/policies/overview) for manual policy updates and L7 rule syntax. +- Use [Policy Schema Reference](/how-it-works/policies/schema) for full YAML field details. - Use [Logging](/observability/logging) to interpret OCSF shorthand log entries. diff --git a/docs/reference/default-policy.mdx b/docs/how-it-works/policies/default-policy.mdx similarity index 93% rename from docs/reference/default-policy.mdx rename to docs/how-it-works/policies/default-policy.mdx index fd564ed610..d670c80e2e 100644 --- a/docs/reference/default-policy.mdx +++ b/docs/how-it-works/policies/default-policy.mdx @@ -31,4 +31,4 @@ The fallback defines no network policies or provider-derived endpoints, so outbo The fallback leaves process identity selection to the compute driver. Docker and Podman honor a non-root OCI `USER`; when an image declares no user, they use numeric UID and GID `1000`. Kubernetes and MicroVM drivers apply their configured non-root identities. -Use `openshell policy get --full` to inspect the effective policy. Refer to [Customize Sandbox Policies](/sandboxes/policies) to replace the fallback. +Use `openshell policy get --full` to inspect the effective policy. Refer to [Customize Sandbox Policies](/how-it-works/policies/overview) to replace the fallback. diff --git a/docs/sandboxes/policies.mdx b/docs/how-it-works/policies/overview.mdx similarity index 97% rename from docs/sandboxes/policies.mdx rename to docs/how-it-works/policies/overview.mdx index 86d3b541e1..9b9d2a45e1 100644 --- a/docs/sandboxes/policies.mdx +++ b/docs/how-it-works/policies/overview.mdx @@ -8,7 +8,7 @@ keywords: "Generative AI, Cybersecurity, Policy, Network Policy, Sandbox, Securi position: 6 --- -Use this page to apply and iterate policy changes on running sandboxes. For a full field-by-field YAML definition, use the [Policy Schema Reference](/reference/policy-schema). +Use this page to apply and iterate policy changes on running sandboxes. For a full field-by-field YAML definition, use the [Policy Schema Reference](/how-it-works/policies/schema). ## Policy Structure @@ -67,9 +67,9 @@ When a hot reload changes rules, the supervisor publishes a new policy generatio | Section | Type | Description | |---|---|---| | `filesystem_policy` | Static | Controls which directories the agent can access on disk. Paths are split into `read_only` and `read_write` lists. Any path not listed in either list is inaccessible. Set `include_workdir: true` to automatically add the agent's working directory to `read_write`. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. | -| `landlock` | Static | Configures Landlock LSM enforcement behavior. Set `compatibility` to `best_effort` (skip individual inaccessible paths while applying remaining rules) or `hard_requirement` (fail if any path is inaccessible or the required kernel ABI is unavailable). Refer to the [Policy Schema Reference](/reference/policy-schema#landlock) for the full behavior table. | +| `landlock` | Static | Configures Landlock LSM enforcement behavior. Set `compatibility` to `best_effort` (skip individual inaccessible paths while applying remaining rules) or `hard_requirement` (fail if any path is inaccessible or the required kernel ABI is unavailable). Refer to the [Policy Schema Reference](/how-it-works/policies/schema#landlock) for the full behavior table. | | `process` | Static | Optionally overrides the OS-level identity for the agent process. Explicit values must be `sandbox` or numeric UID/GID values from `1` through `4294967294`; root and the invalid identity sentinel are rejected. Docker and Podman may use named identities through per-field OCI `USER` fallback; Kubernetes uses its platform-selected numeric identity. The agent also runs with seccomp filters that block dangerous system calls. | -| `network_policies` | Dynamic | Controls outbound traffic from the sandbox, including native model-provider endpoints. Each block has a name, a list of endpoints (host, port, protocol, and optional rules), and a list of binaries allowed to use those endpoints.
Every outbound connection passes through the network supervisor, which queries the [policy engine](/about/how-it-works#core-components) with the destination and calling binary. A connection is allowed only when both match an entry in the same policy block. Attached provider profiles can contribute endpoint and binary entries to the effective policy.
For endpoints with `protocol: rest`, the proxy auto-detects TLS and terminates it so each HTTP request can be checked against that endpoint's `rules` (method and path). For endpoints with `protocol: websocket`, the proxy validates the RFC 6455 upgrade and evaluates `GET` rules for the handshake plus either `WEBSOCKET_TEXT` rules for raw client text messages or GraphQL operation rules for GraphQL-over-WebSocket messages. Set `websocket_credential_rewrite: true` only when a WebSocket or REST compatibility endpoint must keep placeholder credentials in sandbox-owned text frames and resolve them at the OpenShell relay boundary.
Endpoints with `protocol: tcp` allow ordinary DNS resolution and native TCP connections without inspecting payloads. Endpoints without `protocol` retain L4 passthrough through an explicit proxy.
If no endpoint matches, the connection is denied. | +| `network_policies` | Dynamic | Controls outbound traffic from the sandbox, including native model-provider endpoints. Each block has a name, a list of endpoints (host, port, protocol, and optional rules), and a list of binaries allowed to use those endpoints.
Every outbound connection passes through the network supervisor, which queries the [policy engine](/about/architecture#how-a-network-request-travels) with the destination and calling binary. A connection is allowed only when both match an entry in the same policy block. Attached provider profiles can contribute endpoint and binary entries to the effective policy.
For endpoints with `protocol: rest`, the proxy auto-detects TLS and terminates it so each HTTP request can be checked against that endpoint's `rules` (method and path). For endpoints with `protocol: websocket`, the proxy validates the RFC 6455 upgrade and evaluates `GET` rules for the handshake plus either `WEBSOCKET_TEXT` rules for raw client text messages or GraphQL-over-WebSocket messages. Set `websocket_credential_rewrite: true` only when a WebSocket or REST compatibility endpoint must keep placeholder credentials in sandbox-owned text frames and resolve them at the OpenShell relay boundary.
Endpoints with `protocol: tcp` allow ordinary DNS resolution and native TCP connections without inspecting payloads. Endpoints without `protocol` retain L4 passthrough through an explicit proxy.
If no endpoint matches, the connection is denied. | | `network_middlewares` | Dynamic | Declares keyed HTTP and WebSocket middleware configs. After network and L7 policy admit a request or upgrade, OpenShell matches each config's host selectors independently and runs matching entries by their unique ascending `order` before credential injection. WebSocket-capable entries continue on complete client text messages. | When REST body credential rewriting is disabled, OpenShell forwards placeholder @@ -285,7 +285,7 @@ openshell sandbox provider detach ``` These are alternative repairs; choose the one that matches the intended access. -Startup has a [300-second provisioning repair window](/sandboxes/manage-sandboxes#sandbox-lifecycle). +Startup has a [300-second provisioning repair window](/how-it-works/sandboxes/overview#sandbox-lifecycle). Effective configuration changes and their first failed load reset the window; repeated failures do not. If it expires, the gateway records `ProvisioningTimedOut` and reclaims compute. Repair the configuration, wait for cleanup, then run @@ -438,7 +438,7 @@ Static provider placeholders resolve only when the request host, port, and path also match an endpoint in the provider profile. A sandbox policy allow does not expand that binding. A mismatch returns HTTP 403 with `credential_endpoint_mismatch`. Refer to [Static Credential Endpoint -Binding](/providers/profiles#understand-static-credential-endpoint-binding). +Binding](/how-it-works/providers/profiles#understand-static-credential-endpoint-binding). For example: @@ -685,7 +685,7 @@ openshell settings get Check `openshell logs --tail --source sandbox` for the denied host, path, and binary. -For agent-authored draft updates on running sandboxes, enable [Policy Advisor](/sandboxes/policy-advisor). Policy advisor lets the sandboxed agent submit a narrow proposal through `policy.local` while a developer still approves or rejects the structured rule from outside the sandbox. +For agent-authored draft updates on running sandboxes, enable [Policy Advisor](/how-it-works/policies/advisor). Policy advisor lets the sandboxed agent submit a narrow proposal through `policy.local` while a developer still approves or rejects the structured rule from outside the sandbox. When triaging denied requests, check: @@ -701,7 +701,7 @@ Do not fix `credential_endpoint_mismatch` by widening sandbox policy. Export the provider profile with `openshell profile export -o yaml`. Update the custom provider profile only when the destination is an intended credential recipient. Refer to [Static Credential Endpoint -Binding](/providers/profiles#understand-static-credential-endpoint-binding) +Binding](/how-it-works/providers/profiles#understand-static-credential-endpoint-binding) for the complete authorization model. For small changes, prefer `openshell policy update` over rewriting the full YAML: @@ -739,7 +739,7 @@ Endpoints without `protocol` use explicit-proxy TCP passthrough, where OpenShell Allow Claude and the GitHub CLI to reach `api.github.com` with separate REST and GraphQL endpoint scopes: read-only REST for general API paths, GraphQL operation inspection on `/graphql`, full REST write access for `alpha-repo`, and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. -For an end-to-end walkthrough that combines this policy with a GitHub credential provider and sandbox creation, refer to [GitHub Sandbox](/get-started/tutorials/github-sandbox). +For an end-to-end walkthrough that combines this policy with a GitHub credential provider and sandbox creation, refer to [GitHub Sandbox](/tutorials/github-push-access). @@ -969,6 +969,6 @@ GraphQL field names are application-specific, so treat these as starting shapes Explore related topics: -- To learn about the built-in sandbox policy, refer to [Default Policy](/reference/default-policy). -- To view the full field-by-field YAML definition, refer to the [Policy Schema Reference](/reference/policy-schema). -- To review the default policy breakdown, refer to [Default Policy](/reference/default-policy). +- To learn about the built-in sandbox policy, refer to [Default Policy](/how-it-works/policies/default-policy). +- To view the full field-by-field YAML definition, refer to the [Policy Schema Reference](/how-it-works/policies/schema). +- To review the default policy breakdown, refer to [Default Policy](/how-it-works/policies/default-policy). diff --git a/docs/reference/policy-prover.mdx b/docs/how-it-works/policies/prover.mdx similarity index 98% rename from docs/reference/policy-prover.mdx rename to docs/how-it-works/policies/prover.mdx index cc2bc9f97e..85c00d8d77 100644 --- a/docs/reference/policy-prover.mdx +++ b/docs/how-it-works/policies/prover.mdx @@ -27,7 +27,7 @@ openshell-prover --version The prover remains independent of the gateway at runtime. If you only need the standalone binary, use the artifacts listed in the -[Support Matrix](/reference/support-matrix#standalone-policy-prover). These +[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). @@ -266,6 +266,6 @@ state. In particular: If the boundary grants no access of the requested kind, adding that access returns `exceeds_boundary`. -Use the [Policy Schema Reference](/reference/policy-schema) for the full policy +Use the [Policy Schema Reference](/how-it-works/policies/schema) for the full policy language. A successful prover result covers only the policy domains reported in its evidence. diff --git a/docs/reference/policy-schema.mdx b/docs/how-it-works/policies/schema.mdx similarity index 99% rename from docs/reference/policy-schema.mdx rename to docs/how-it-works/policies/schema.mdx index f3072da5b5..929afdb7e8 100644 --- a/docs/reference/policy-schema.mdx +++ b/docs/how-it-works/policies/schema.mdx @@ -76,7 +76,7 @@ Each message contains at most eight error items and 512 UTF-8 bytes, including t - YAML errors report a fixed parser category, with numeric line and column when the parser provides them. - File I/O, Rego loading, and internal policy-data failures return fixed messages. -A candidate rejected during validation does not replace the active engine or advance its generation. The supervisor then applies the gateway's `policy_validation_failure_mode`; `fail_closed` can publish a quarantine generation that denies egress, while `retain_last_valid` keeps an existing valid generation active. See [Gateway Configuration](/reference/gateway-config) for that setting and startup behavior. +A candidate rejected during validation does not replace the active engine or advance its generation. The supervisor then applies the gateway's `policy_validation_failure_mode`; `fail_closed` can publish a quarantine generation that denies egress, while `retain_last_valid` keeps an existing valid generation active. See [Gateway Configuration](/how-it-works/gateways/configuration) for that setting and startup behavior. These bounds apply to returned OPA load errors. Warnings for accepted policies, runtime request diagnostics, and gateway-authored policy parser messages have separate reporting behavior. @@ -222,7 +222,7 @@ Each endpoint defines a reachable destination and optional inspection rules. | `websocket_credential_rewrite` | bool | No | When `true` on a `protocol: rest` or `protocol: websocket` endpoint, OpenShell rewrites credential placeholders in client-to-server WebSocket text messages after an allowed HTTP `101` upgrade. On provider-credentialed endpoints without `allow_uninspected_credentials`, OpenShell uses the parsed relay and rejects binary frames; text frames containing placeholders fail closed when rewrite is disabled. Defaults to `false`. | | `request_body_credential_rewrite` | bool | No | When `true` on a `protocol: rest` endpoint, OpenShell rewrites credential placeholders in UTF-8 `application/json`, `application/x-www-form-urlencoded`, and `text/*` request bodies before forwarding upstream. The proxy buffers at most 256 KiB and updates `Content-Length` after rewriting. For chunked requests, the limit counts framing, extensions, and trailers. When rewrite is disabled and the sandbox has provider credentials, bodies continue to stream. Authoritatively unknown placeholder keys and valid issued credentials pass unchanged, including credentials bound to the destination. Invalid or unavailable credentials, and unavailable classification metadata fail closed with `credential_placeholder_in_request_body` (HTTP 403). Candidates are limited to 4096 wire bytes. No secret is substituted. Defaults to `false`. Mutually exclusive with `credential_signing`. | | `allow_uninspected_credentials` | bool | No | Explicit security-sensitive opt-in that permits a provider-credentialed endpoint to use traffic paths OpenShell cannot inspect or rewrite, including L4-only and `tls: skip` tunnels. Defaults to `false`. Policy proposals that set it require explicit security-flagged approval. | -| `credential_signing` | string | No | Proxy-side credential signing mode. When set, the proxy strips the sandbox client's `Authorization` header and re-signs with real provider credentials. Values: `sigv4` (auto-detect payload mode from client headers), `sigv4:body` (buffer and hash body, max 10 MiB), `sigv4:no_body` (unsigned payload, stream body). Mutually exclusive with `request_body_credential_rewrite`. See [AWS SigV4](/providers/aws-sigv4). | +| `credential_signing` | string | No | Proxy-side credential signing mode. When set, the proxy strips the sandbox client's `Authorization` header and re-signs with real provider credentials. Values: `sigv4` (auto-detect payload mode from client headers), `sigv4:body` (buffer and hash body, max 10 MiB), `sigv4:no_body` (unsigned payload, stream body). Mutually exclusive with `request_body_credential_rewrite`. See [AWS SigV4](/how-it-works/providers/aws). | | `signing_service` | string | No | AWS service name for SigV4 signing (e.g. `bedrock`, `s3`, `sts`). Required when `credential_signing` is set. | | `signing_region` | string | No | AWS region override for SigV4 signing (e.g. `us-east-1`). When omitted, the region is extracted from the endpoint hostname. Required for non-standard AWS endpoints where the region cannot be inferred. | | `credential_binding` | object | No | Binds static credentials from an attached provider to this endpoint when that provider's profile defines no endpoints. This field is valid only in a sandbox-scoped policy. | @@ -283,7 +283,7 @@ global policies that use this field. Network policy admission does not expand the credential boundary unless the endpoint explicitly supplies this binding. OpenShell rejects a request mismatch with HTTP 403 and `credential_endpoint_mismatch`. Refer to [Static Credential Endpoint -Binding](/providers/profiles#understand-static-credential-endpoint-binding). +Binding](/how-it-works/providers/profiles#understand-static-credential-endpoint-binding). This example allows the sandbox to reach Google Cloud Storage and binds the static credentials from the attached `work-gcp` provider to that endpoint: diff --git a/docs/providers/aws-sigv4.mdx b/docs/how-it-works/providers/aws.mdx similarity index 97% rename from docs/providers/aws-sigv4.mdx rename to docs/how-it-works/providers/aws.mdx index a9251f134d..087161faa9 100644 --- a/docs/providers/aws-sigv4.mdx +++ b/docs/how-it-works/providers/aws.mdx @@ -21,8 +21,7 @@ Import the `aws` profile first; a gateway serves only the profiles you imported: ```shell -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/aws.yaml -openshell provider profile import -f aws.yaml --global +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/aws.yaml --global ``` Create a provider with AWS credentials: @@ -50,7 +49,7 @@ To have the gateway mint and rotate STS credentials for you instead of supplying them statically, use the `aws` or `aws-s3` profile with the `aws_sts_assume_role` refresh strategy. A single `sts:AssumeRole` mints all three env vars (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`) that the -signer reads. See [Manage Providers](/sandboxes/manage-providers#aws-sts). +signer reads. See [Manage Providers](/how-it-works/providers/overview#aws-sts). ## Policy Configuration diff --git a/docs/providers/google-cloud.mdx b/docs/how-it-works/providers/google.mdx similarity index 97% rename from docs/providers/google-cloud.mdx rename to docs/how-it-works/providers/google.mdx index dee210b77b..1df8cead1a 100644 --- a/docs/providers/google-cloud.mdx +++ b/docs/how-it-works/providers/google.mdx @@ -20,8 +20,7 @@ Import the `google-cloud` profile first; a gateway serves only the profiles you imported: ```shell -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/google-cloud.yaml -openshell provider profile import -f google-cloud.yaml --global +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/google-cloud.yaml --global ``` If you already have `gcloud` configured with Application Default Credentials, @@ -223,8 +222,7 @@ native Vertex endpoint and request format for its selected model. Import the `google-vertex-ai` profile first: ```shell -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/google-vertex-ai.yaml -openshell provider profile import -f google-vertex-ai.yaml --global +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/google-vertex-ai.yaml --global ``` #### Service Account Key diff --git a/docs/sandboxes/manage-providers.mdx b/docs/how-it-works/providers/overview.mdx similarity index 95% rename from docs/sandboxes/manage-providers.mdx rename to docs/how-it-works/providers/overview.mdx index 8da46617e9..908adf64d8 100644 --- a/docs/sandboxes/manage-providers.mdx +++ b/docs/how-it-works/providers/overview.mdx @@ -14,7 +14,7 @@ Create and manage providers that supply credentials to sandboxes. Provider profiles define provider credentials, policy, and refresh behavior. See -[Profiles](/providers/profiles) for the profile format and custom +[Profiles](/how-it-works/providers/profiles) for the profile format and custom profile workflow. @@ -187,7 +187,7 @@ openshell provider update my-claude --from-existing --wait --timeout 30 --output The update records which sandboxes are attached before saving the new credentials. Its result includes a change ID and outcome for each of those sandboxes. Sandboxes attached later are outside this wait. The timeout applies to the whole group; if any selected sandbox fails or times out, the command exits with an error and still reports each sandbox's outcome. When no sandboxes are attached, it reports the saved change and an empty target list. -Credential refresh status tells you whether OpenShell obtained credentials. [Provider readiness](/providers/profiles#inspect-provider-readiness) tells you whether the sandbox applied the credentials, policy, and environment for new processes. It does not test access to a backend model or cancel requests already sent upstream. +Credential refresh status tells you whether OpenShell obtained credentials. [Provider readiness](/how-it-works/providers/profiles#inspect-provider-readiness) tells you whether the sandbox applied the credentials, policy, and environment for new processes. It does not test access to a backend model or cancel requests already sent upstream. After a static credential update completes, launch a new client process to use the updated reference. An existing process keeps its revision-scoped reference; readiness does not make that old reference resolve the new value. Acknowledged detach revokes retained references and removes them from environments for future launches. @@ -337,7 +337,7 @@ be resolved. Use `--provider` to attach providers when creating a sandbox. To change the providers attached to a running sandbox, use `openshell sandbox provider attach` and `openshell sandbox provider detach`. See -[Profiles](/providers/profiles#attach-and-detach-providers) for details. +[Profiles](/how-it-works/providers/profiles#attach-and-detach-providers) for details. @@ -388,7 +388,7 @@ profile. Credential resolution requires the proxy to handle the request as HTTP. Raw `tls: skip` and non-HTTP tunnels remain opaque and do not support credential -rewrite. Refer to [Profiles](/providers/profiles#understand-static-credential-endpoint-binding) +rewrite. Refer to [Profiles](/how-it-works/providers/profiles#understand-static-credential-endpoint-binding) for endpoint matching and migration guidance. ### Supported injection locations @@ -435,7 +435,7 @@ there returns `credential_endpoint_mismatch`. For another service, define the credential in its own provider profile. Put stable endpoints in the profile, or leave the profile endpointless and bind each concrete provider instance from sandbox policy. Refer to -[Profiles](/providers/profiles#provider-profiles) for the profile workflow +[Profiles](/how-it-works/providers/profiles#provider-profiles) for the profile workflow and schema. ## Available Provider Types @@ -476,14 +476,14 @@ An OpenAI-compatible protocol does not make the `openai` profile safe for an arbitrary host. Baseten, Bitdeer, Groq, Ollama, LM Studio, self-hosted NIM, and other alternate endpoints need their own profile declaring the actual host, port, credential, and allowed binaries. See -[Inference](/sandboxes/inference-routing) for complete examples +[Inference](/how-it-works/inference) for complete examples and migration guidance. ## Next Steps Explore related topics: -- To manage workspace access for providers, refer to [Workspaces](/sandboxes/manage-workspaces). -- To control what the agent can access, refer to [Policies](/sandboxes/policies). -- To use the default workload image, refer to [Sandboxes](/sandboxes/manage-sandboxes#default-workload-image). -- To view the complete field reference for the policy YAML, refer to the [Policy Schema Reference](/reference/policy-schema). +- To manage workspace access for providers, refer to [Workspaces](/how-it-works/workspaces). +- To control what the agent can access, refer to [Policies](/how-it-works/policies/overview). +- To use the default workload image, refer to [Sandboxes](/how-it-works/sandboxes/overview#default-workload-image). +- To view the complete field reference for the policy YAML, refer to the [Policy Schema Reference](/how-it-works/policies/schema). diff --git a/docs/providers/profiles.mdx b/docs/how-it-works/providers/profiles.mdx similarity index 97% rename from docs/providers/profiles.mdx rename to docs/how-it-works/providers/profiles.mdx index df39087d37..a5beaacad0 100644 --- a/docs/providers/profiles.mdx +++ b/docs/how-it-works/providers/profiles.mdx @@ -209,7 +209,7 @@ The following provider profile design items are not part of the current behavior | Policy prover integration | OpenShell does not yet run the policy prover automatically on sandbox startup or block startup based on prover findings. | | Refresh telemetry as OCSF events | Credential refresh logs are secret-safe gateway logs. OCSF refresh events and metrics are future work. | -Use [Inference](/sandboxes/inference-routing) to attach an +Use [Inference](/how-it-works/inference) to attach an inference provider and call its native endpoint. ## Provider Profiles @@ -259,37 +259,38 @@ reviewable starting points, not platform defaults. Read a file's header before importing it. Each one names the client binaries it expects, the reference image layout those paths assume, the credential scope, the endpoint access it grants, and a smoke test. Several name layout-specific -paths, such as `/sandbox/.venv` or `/usr/lib/node_modules/@openai`. Imported -unchanged into a different image the -profile matches nothing: the catalog still lists it, but the credential is never -injected and the traffic is denied. Copy the file, edit `binaries` and -`endpoints` for your image and workload, and import your copy. - -Lint a profile before importing it: +paths, such as `/sandbox/.venv` or `/usr/lib/node_modules/@openai`. If the +profile's `binaries` and `endpoints` match your image and workload, import it +directly from the repository: ```shell -openshell profile lint -f providers/github.yaml +openshell profile lint --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/github.yaml +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/github.yaml --global ``` -Import one profile file at platform scope: +`--url` accepts one HTTP or HTTPS `.yaml`, `.yml`, or `.json` profile. It cannot +import a directory or be combined with `-f` or `--from`. The download has a +15-second timeout and a 1 MiB limit; URL query parameters are allowed. Review +the source and its grants before importing; lint checks the profile but does not +establish whether you trust it. + +If the paths or endpoint grants need to change, copy the profile, edit +`binaries` and `endpoints`, then lint and import your local copy. An imported +profile with binaries that do not match the image still appears in the catalog, +but its credential is not injected and its traffic is denied. + +Lint a local profile before importing it: ```shell -openshell profile import -f providers/github.yaml --global +openshell profile lint -f providers/github.yaml ``` -Import a published YAML or JSON profile directly from an HTTP or HTTPS URL: +Import one profile file at platform scope: ```shell -openshell profile lint --url https://example.com/profiles/github.yaml -openshell profile import --url https://example.com/profiles/github.yaml --global +openshell profile import -f providers/github.yaml --global ``` -Review profiles from remote sources before importing them. A profile can grant -network access and bind credentials to the endpoints and binaries it declares. -The URL path must end in `.yaml`, `.yml`, or `.json`; query parameters are allowed. -Remote downloads have a 1 MiB size limit and a 15 second timeout. `--url` is -mutually exclusive with `-f` and `--from`. - Import all non-recursive `*.yaml`, `*.yml`, and `*.json` files from a directory: ```shell @@ -341,7 +342,7 @@ The `category` field supplies the `CATEGORY` column in `openshell profile list`. ### Profile Schema -Provider profile YAML and JSON use this shape. Treat this as a field map, not a profile to import verbatim. The endpoint and rule fields mirror the network policy schema used under `network_policies`. Refer to [Policy Schema Reference](/reference/policy-schema) for field semantics. +Provider profile YAML and JSON use this shape. Treat this as a field map, not a profile to import verbatim. The endpoint and rule fields mirror the network policy schema used under `network_policies`. Refer to [Policy Schema Reference](/how-it-works/policies/schema) for field semantics. Use `annotations` only for non-secret metadata such as source, signature, or governance markers. OpenShell preserves annotations through profile import, export, and interceptor-managed profile snapshots. ```yaml wordWrap showLineNumbers={false} @@ -739,7 +740,7 @@ cannot replace or delete its primary credential or any co-minted output. Use management. You can still update unrelated credentials, configuration, and credential expiry metadata. -For a complete Microsoft Graph OAuth2 refresh-token walkthrough, see [Refresh Microsoft Graph Credentials with a Provider Profile](/get-started/tutorials/microsoft-graph-provider-refresh). +For a complete Microsoft Graph OAuth2 refresh-token walkthrough, see [Refresh Microsoft Graph Credentials with a Provider Profile](/tutorials/microsoft-graph-provider-refresh). The profile YAML strategy values use underscores, while the CLI `--strategy` values use kebab-case: @@ -1060,7 +1061,7 @@ An unavailable supervisor, an expired report, a failed installation, or a missin JSON and YAML output include change IDs, requested and installed revisions, timestamps, reason categories, and a result for each sandbox. Revision strings identify configurations; compare them for equality rather than numerical order. Status output excludes credential values, credential references, authorization headers, and raw installation errors. -The `persisted_time`, `observed_time`, and `evaluated_time` fields use RFC 3339 timestamp strings. An absent `observed_time` means the current supervisor session has not supplied accepted evidence. API operation timestamps use protobuf `Timestamp`, and report intervals and observation lifetimes use protobuf `Duration`, following the [protobuf time representation](/reference/protobuf-time-types). +The `persisted_time`, `observed_time`, and `evaluated_time` fields use RFC 3339 timestamp strings. An absent `observed_time` means the current supervisor session has not supplied accepted evidence. API operation timestamps use protobuf `Timestamp`, and report intervals and observation lifetimes use protobuf `Duration`, following the [protobuf time representation](/sdk/protobuf-time-types). The API's `operation` field records the common operation's historical outcome; its `operation_id` equals the receipt ID. Use the provider `state` and the wait result for current readiness. A disconnected supervisor can make the live state pending even after the operation previously applied, and a newer change can supersede the live result. Historical completion does not override those checks. @@ -1080,6 +1081,6 @@ OpenShell rejects provider updates and refresh configuration when they would mak ## Next Steps -- Use [Providers](/sandboxes/manage-providers) for the current provider command reference. -- Use [Customize Sandbox Policies](/sandboxes/policies) to apply user-authored policy rules. -- Use [Policy Schema Reference](/reference/policy-schema) for endpoint and L7 rule field details. +- Use [Providers](/how-it-works/providers/overview) for the current provider command reference. +- Use [Customize Sandbox Policies](/how-it-works/policies/overview) to apply user-authored policy rules. +- Use [Policy Schema Reference](/how-it-works/policies/schema) for endpoint and L7 rule field details. diff --git a/docs/sandboxes/manage-sandboxes.mdx b/docs/how-it-works/sandboxes/overview.mdx similarity index 90% rename from docs/sandboxes/manage-sandboxes.mdx rename to docs/how-it-works/sandboxes/overview.mdx index a475eb57de..f1535dc487 100644 --- a/docs/sandboxes/manage-sandboxes.mdx +++ b/docs/how-it-works/sandboxes/overview.mdx @@ -220,62 +220,7 @@ driver's `rootfs_tar_max_bytes`), and reclaims an unused staging slot after 30 minutes. The cap applies to the expanded archive too: a compressed source that decompresses past the limit is rejected. -## Reuse Workload Templates - -Sandbox workload templates let workspace admins define reusable runtime shapes for a workspace. A template stores the image, environment, resource requests, and driver-specific configuration that sandboxes should inherit. When you create a sandbox from a template, the create request can still attach providers, labels, and policy, but the workload comes from the named template. - -Create a template: - -```shell -openshell sandbox template create gpu-kata \ - --image registry.example.com/agent:latest \ - --cpu 2 \ - --memory 4Gi \ - --gpu 1 \ - --label team=runtime \ - --env FEATURE_FLAG=on -``` - -Use `--gpu` without a count when the template should request the active -driver's default GPU assignment. Use `--gpu COUNT` when the template needs a -specific number of GPUs. - -Add driver-specific settings when the active compute driver needs them: - -```shell -openshell sandbox template create gpu-kata \ - --image registry.example.com/agent:latest \ - --driver-config-json '{"kubernetes":{"pod":{"runtime_class_name":"kata-containers","node_selector":{"pool":"gpu"}}}}' -``` - -If you omit `--image`, the gateway applies its default sandbox image when a sandbox is created from the template. Use this when the template should only define resource, environment, or driver settings. - -Create a sandbox from a template: - -```shell -openshell sandbox create --template gpu-kata --provider github -- claude -``` - -The `--template` flag cannot be combined with inline workload flags such as `--from`, `--cpu`, `--memory`, `--gpu`, `--env`, or `--driver-config-json`. Put those values on the template instead. Create-time policy and provider attachments remain part of the sandbox request, so each sandbox can keep its own access boundary. - -Inspect and manage templates: - -```shell -openshell sandbox template list -openshell sandbox template list --label-selector team=runtime -openshell sandbox template get gpu-kata -openshell sandbox template delete gpu-kata -``` - -Use `--all-workspaces` with `sandbox template list` when you need an admin view across workspaces: - -```shell -openshell sandbox template list --all-workspaces -``` - -For JSON or YAML, template list output contains `templates` and -`next_page_token` fields. Pass the returned token to `--page-token` to -continue. +To reuse image and resource settings across sandboxes, see [Templates](/how-it-works/sandboxes/templates). ## Default Workload Image @@ -297,7 +242,7 @@ Override it with any image visible to the active compute driver: openshell sandbox create --from registry.example.com/agents/my-agent:1.0 ``` -Refer to [Default Policy](/reference/default-policy), [Run Your First Agent](/about/run-an-agent), and the [bring-your-own-container example](https://github.com/NVIDIA/OpenShell/tree/main/examples/bring-your-own-container). +Refer to [Default Policy](/how-it-works/policies/default-policy), [Run Your First Agent](/about/run-your-first-agent), and the [bring-your-own-container example](https://github.com/NVIDIA/OpenShell/tree/main/examples/bring-your-own-container). ## Connect to a Sandbox @@ -307,10 +252,11 @@ Attach to the canonical main process in a running sandbox: openshell sandbox connect my-sandbox ``` -Disconnecting does not stop the process or close its stdin. A later `connect` -attaches to the same process instance and replays up to 1 MiB of recent -output. One attachment owns stdin at a time. Use `sandbox exec --tty -- -/bin/bash -l` when you want a new independent shell instead. +Press `Ctrl-P`, then `Ctrl-Q` in sequence to disconnect. The main process keeps +running and its stdin stays open. A later `connect` attaches to the same process +instance and replays up to 1 MiB of recent output. One attachment owns stdin +at a time. Use `sandbox exec --tty -- /bin/bash -l` when you want a new +independent shell instead. If an established connection is interrupted, for example when a laptop sleeps and wakes, the CLI obtains a new SSH session and reattaches to the same main @@ -318,13 +264,12 @@ process. It retries transient transport failures for up to 60 seconds. Initial authentication failures, sandbox lifecycle changes, and clean SSH exits are not retried. -Press `Ctrl-P`, then `Ctrl-Q` to disconnect without terminating the main -process. `Ctrl-C` retains its normal terminal behavior and interrupts the -foreground process. For read-only attachments, `Ctrl-C` only exits the -current viewer. OpenSSH's `~.` escape reports the same status as a broken -transport, so it starts automatic recovery instead of exiting. After `~.`, use -`Ctrl-P`, then `Ctrl-Q` once OpenShell reattaches, or press `Ctrl-C` while the -CLI is between retry attempts to cancel recovery. +`Ctrl-C` retains its normal terminal behavior and interrupts the foreground +process. For read-only attachments, `Ctrl-C` only exits the current viewer. +OpenSSH's `~.` escape reports the same status as a broken transport, so it +starts automatic recovery instead of exiting. After `~.`, use `Ctrl-P`, then +`Ctrl-Q` once OpenShell reattaches, or press `Ctrl-C` while the CLI is between +retry attempts to cancel recovery. Launch VS Code or Cursor directly into the sandbox workspace: @@ -377,6 +322,8 @@ Run an interactive shell with a TTY: openshell sandbox exec -n my-sandbox --tty -- /bin/bash ``` +Run `exit` or press `Ctrl-D` to close this separate shell. + OpenShell allocates a TTY automatically when both stdin and stdout are terminals. Force the behavior with `--tty` or disable it with `--no-tty`. | Flag | Purpose | @@ -411,7 +358,7 @@ openshell sandbox create --env API_KEY=sk-test --env DEBUG=1 -- my-agent Variables set with `--env` are available to all processes in the sandbox, including the initial command, interactive shells, and exec commands. -When an `--env` key looks like a credential — a known provider variable, or a name whose underscore-separated segments include a credential word such as `TOKEN`, `SECRET`, `PASSWORD`, `CREDENTIAL`, `API_KEY`, `ACCESS_KEY`, or `SECRET_KEY` (for example `DB_TOKEN` or `MY_ACCESS_KEY`) — `sandbox create` prints a non-blocking warning. Matching is on whole segments, so unrelated names like `TOKENIZERS_PARALLELISM` or `PASSWORDLESS_LOGIN` do not warn. The agent inside the sandbox can read plain environment values directly, so to hide a secret from the agent, attach it through a [profile-backed provider](/providers/profiles) with `--provider` instead. Suppress the warning with `--no-credential-warnings`. Detection uses the key name only; values are never inspected or printed. +When an `--env` key looks like a credential — a known provider variable, or a name whose underscore-separated segments include a credential word such as `TOKEN`, `SECRET`, `PASSWORD`, `CREDENTIAL`, `API_KEY`, `ACCESS_KEY`, or `SECRET_KEY` (for example `DB_TOKEN` or `MY_ACCESS_KEY`) — `sandbox create` prints a non-blocking warning. Matching is on whole segments, so unrelated names like `TOKENIZERS_PARALLELISM` or `PASSWORDLESS_LOGIN` do not warn. The agent inside the sandbox can read plain environment values directly, so to hide a secret from the agent, attach it through a [profile-backed provider](/how-it-works/providers/profiles) with `--provider` instead. Suppress the warning with `--no-credential-warnings`. Detection uses the key name only; values are never inspected or printed. You can also set per-command environment variables with `sandbox exec`: @@ -605,7 +552,7 @@ openshell service delete my-sandbox ``` -Loopback gateways return local `openshell.localhost` URLs. Remote gateways return HTTPS URLs that require normal gateway authentication. For gateway service-domain configuration, refer to [Manage Gateways](/sandboxes/manage-gateways#configure-service-forwarding). +Loopback gateways return local `openshell.localhost` URLs. Remote gateways return HTTPS URLs that require normal gateway authentication. For gateway service-domain configuration, refer to [Manage Gateways](/how-it-works/gateways/overview#configure-service-forwarding). ## Monitor and Debug @@ -706,7 +653,7 @@ OpenShell Terminal combines sandbox status and live logs in a single real-time d openshell term ``` -Use the terminal to spot blocked connections marked `action=deny` and provider-related proxy activity. If a connection is blocked unexpectedly, add the host to your network policy or update the attached provider profile. Refer to [Policies](/sandboxes/policies) for the workflow. +Use the terminal to spot blocked connections marked `action=deny` and provider-related proxy activity. If a connection is blocked unexpectedly, add the host to your network policy or update the attached provider profile. Refer to [Policies](/how-it-works/policies/overview) for the workflow. The dashboard has three panels stacked vertically: Gateways, Providers (or Global Settings), and Sandboxes. Navigate within a panel with `Up`/`Down` or `j`/`k`. At a list boundary the cursor overflows into the adjacent panel, skipping empty panels. Use `Tab`/`Shift+Tab` to cycle panels directly. Press `h`/`l` or `Left`/`Right` in the middle panel to switch between the Providers and Global Settings tabs. @@ -844,7 +791,7 @@ The command can return while cleanup is pending. `deletion accepted` means the gateway started deletion; inspect the sandbox until it disappears if your next step requires completion. An already-absent sandbox is a successful no-op, but missing workspaces and authorization failures remain errors. SDK callers can -inspect [typed deletion outcomes](/reference/api-errors#deletion-outcomes). +inspect [typed deletion outcomes](/sdk/api-errors#deletion-outcomes). ```shell openshell sandbox delete my-sandbox @@ -867,7 +814,7 @@ Every sandbox moves through a defined set of phases: Before workload activation, OpenShell validates the effective policy and matching provider configuration. A rejection keeps the workload unstarted and exposes a `ConfigurationInvalid` condition in `Provisioning`. Use `openshell sandbox get` -to inspect the diagnostic, then [repair the policy or provider configuration](/sandboxes/policies#validation-failures). +to inspect the diagnostic, then [repair the policy or provider configuration](/how-it-works/policies/overview#validation-failures). Management operations remain available while startup is blocked. After repair, the supervisor completes startup without recreating the sandbox. Starting a stopped sandbox repeats configuration admission before launching its workload. @@ -925,12 +872,12 @@ not automatically restart that process. The gateway's configured compute driver determines how OpenShell creates each sandbox. The CLI workflow stays the same across drivers: you create, connect to, inspect, and delete sandboxes through the gateway API. -For Docker, Podman, MicroVM, and Kubernetes behavior, refer to [Sandbox Runtimes](/reference/sandbox-compute-drivers). +For Docker, Podman, MicroVM, and Kubernetes behavior, refer to [Sandbox Runtimes](/how-it-works/sandboxes/runtimes). ## Next Steps -- To follow a complete end-to-end example, refer to the [GitHub Sandbox](/get-started/tutorials/github-sandbox) tutorial. -- To select a workspace or understand access roles, refer to [Workspaces](/sandboxes/manage-workspaces). -- To supply API keys or tokens, refer to [Manage Providers](/sandboxes/manage-providers). -- To control what the agent can access, refer to [Policies](/sandboxes/policies). +- To follow a complete end-to-end example, refer to the [GitHub Sandbox](/tutorials/github-push-access) tutorial. +- To select a workspace or understand access roles, refer to [Workspaces](/how-it-works/workspaces). +- To supply API keys or tokens, refer to [Manage Providers](/how-it-works/providers/overview). +- To control what the agent can access, refer to [Policies](/how-it-works/policies/overview). - To use the default runtime image, refer to [Default Workload Image](#default-workload-image). diff --git a/docs/how-it-works/sandboxes/runtimes.mdx b/docs/how-it-works/sandboxes/runtimes.mdx new file mode 100644 index 0000000000..b36128aca5 --- /dev/null +++ b/docs/how-it-works/sandboxes/runtimes.mdx @@ -0,0 +1,268 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Sandbox Runtimes" +sidebar-title: "Runtimes" +description: "Configure the Docker, Podman, MicroVM, or Kubernetes runtime that runs OpenShell sandboxes." +keywords: "Generative AI, Cybersecurity, AI Agents, Sandboxing, Docker, Podman, MicroVM, Kubernetes, MXC, Reference" +position: 4 +--- + +Each gateway runs agent workloads on one compute runtime, selected by its compute driver. Pick the runtime that matches the isolation boundary and infrastructure you need. The CLI workflow stays the same across runtimes: you create, connect to, stop, start, and delete sandboxes through the gateway. + +| Runtime | Driver | Use when | +|---|---|---| +| [Docker](#docker-driver) | `docker` | Local development and single-machine gateways. | +| [Podman](#podman-driver) | `podman` | Rootless Linux workstations without a Docker daemon. | +| [MicroVM](#microvm-driver) | `vm` | Workloads need a VM boundary instead of a container boundary. | +| [Kubernetes](#kubernetes-driver) | `kubernetes` | Shared clusters, remote compute, and GPU scheduling. | +| Windows MXC | `mxc` | Coming soon. | + +## Select a Compute Driver + +Set `compute_driver` in the gateway TOML file. A gateway uses one driver at a time. + +```toml +[openshell.gateway] +compute_driver = "docker" +``` + +When `compute_driver` is unset, the gateway auto-detects Kubernetes, then Podman, then Docker. The VM driver is never auto-detected. + +Configure driver-specific values, such as images, endpoints, and sizing, under `[openshell.drivers.]`. See the [Gateway Configuration File](/how-it-works/gateways/configuration) reference for every option. + +### Extension Drivers + +Any name other than a built-in driver selects an extension driver. Point the gateway at the Unix socket where the driver listens: + +```toml +[openshell.gateway] +compute_driver = "kyma" + +[openshell.drivers.kyma] +socket_path = "/run/openshell/kyma.sock" +``` + +The gateway does not start or supervise extension drivers. Restrict the socket so only the gateway user can access it. + +## Size Sandboxes + +Use `--cpu`, `--memory`, and `--gpu` on `openshell sandbox create` to request resources. `--gpu` alone requests one GPU; `--gpu COUNT` requests more. + +| Driver | CPU and memory | GPU | +|---|---|---| +| Docker, Podman | Runtime limits | NVIDIA CDI devices | +| Kubernetes | Container requests and limits | `nvidia.com/gpu` resource limit | +| MicroVM | Ignored; use `vcpus` and `mem_mib` | One GPU through `gpu_device_ids` | + +## Pass Driver Config + +`--driver-config-json` passes driver-specific settings that have no dedicated flag. The value is a JSON object keyed by driver name, and the gateway forwards only the block for the active driver: + +```shell +openshell sandbox create \ + --from registry.example.com/team/claude-code:1.0 \ + --driver-config-json '{"kubernetes":{"pod":{"runtime_class_name":"kata-containers"}}}' \ + -- claude +``` + +Driver config is disabled by default. Enable it with `allow_driver_config = true` in the driver's gateway configuration. Attached resources such as volumes must carry operator-approved labels. See [External Resource Admission](/how-it-works/gateways/configuration#external-resource-admission). + +To pin specific GPUs, pass `cdi_devices` for Docker or Podman, or `gpu_device_ids` for MicroVM, together with `--gpu`: + +```shell +--gpu --driver-config-json '{"docker":{"cdi_devices":["nvidia.com/gpu=0"]}}' +--gpu --driver-config-json '{"vm":{"gpu_device_ids":["0000:2d:00.0"]}}' +``` + +## Docker Driver + +[Docker](https://www.docker.com/get-started/) runs sandboxes as containers on the gateway host. Docker is also required to build sandbox images from local directories or Dockerfiles. + +```toml +[openshell.gateway] +compute_driver = "docker" + +[openshell.drivers.docker] +socket_path = "/var/run/docker.sock" +``` + +Common options in `[openshell.drivers.docker]` are `socket_path`, `grpc_endpoint`, `sandbox_runtime_image`, `supervisor_image`, `image_pull_policy`, and `sandbox_pids_limit`. When `socket_path` is unset, the driver uses the socket found by auto-detection. + +Docker Desktop must have host networking enabled, and it cannot use Enhanced Container Isolation. Set `grpc_endpoint` when sandboxes cannot reach the gateway on host loopback. For GPU sandboxes, configure Docker CDI before starting the gateway. + +### Docker Mounts + +Mount existing named volumes or `tmpfs` through driver config. Label volumes so resource admission accepts them: + +```shell +docker volume create --label openshell.ai/sandbox-attachable=true \ + --label openshell.ai/sandbox-attachable-workspace=default openshell-work + +openshell sandbox create \ + --from registry.example.com/team/claude-code:1.0 \ + --driver-config-json '{"docker":{"mounts":[{"type":"volume","source":"openshell-work","target":"/sandbox/work","read_only":false}]}}' \ + -- claude +``` + +| Type | Fields | +|---|---| +| `volume` | `source`, `target`, optional `read_only` (default `true`), optional `subpath`. | +| `tmpfs` | `target`, optional `options`, `size_bytes`, `mode`. | +| `bind` | `source` (absolute host path), `target`, optional `read_only` (default `true`), optional `selinux_label`. | + + +Bind mounts expose gateway-host files to the sandbox and can bypass workspace isolation and filesystem policy. They require `enable_bind_mounts = true` and disabling resource admission for the driver: + +```toml +[openshell.drivers.docker] +allow_driver_config = true +enable_bind_mounts = true + +[openshell.drivers.docker.resource_admission] +enabled = false +``` + + + +Mount targets cannot replace the workspace root, the container root, or OpenShell paths under `/opt/openshell`, `/etc/openshell`, and `/run/openshell`. + +## Podman Driver + +[Podman](https://podman.io/) runs sandboxes as rootless containers on the gateway host. It requires Podman 5.x, cgroups v2, and an active Podman user socket: + +```shell +systemctl --user start podman.socket +``` + +```toml +[openshell.gateway] +compute_driver = "podman" +``` + +Common options in `[openshell.drivers.podman]` are `socket_path`, `network_name`, `sandbox_runtime_image`, `supervisor_image`, `image_pull_policy`, `stop_timeout_secs`, and `grpc_endpoint`. When `socket_path` is unset, the driver finds the socket automatically, including `podman machine` sockets on macOS. + +On macOS, set `host_gateway_ip` only if your Podman machine uses a non-standard host-loopback address. Set `grpc_endpoint` when the gateway is remote. + +For networks that require a corporate proxy, set `https_proxy`, `no_proxy`, and related `proxy_*` options. See the [Gateway Configuration File](/how-it-works/gateways/configuration) reference. + +### Podman Mounts + +Podman supports the same `volume`, `tmpfs`, and `bind` mounts as [Docker](#docker-mounts), using the `podman` key in driver config, and the same bind-mount warning applies. Podman `volume` mounts do not support `subpath`. + +Podman also supports `image` mounts, which mount a container image read-only at `target`. Image mounts require disabling resource admission. + +## MicroVM Driver + +The MicroVM driver runs each sandbox in its own lightweight VM. It requires host virtualization: Apple Hypervisor on macOS or KVM on Linux. + +The VM driver is opt-in. Enable it in the gateway TOML file: + +```toml +[openshell.gateway] +compute_driver = "vm" + +[openshell.drivers.vm] +default_image = "registry.example.com/team/agent-base:1.0" +vcpus = 4 +mem_mib = 8192 +``` + +You can also set `OPENSHELL_COMPUTE_DRIVER=vm` in the gateway environment. + +Common options in `[openshell.drivers.vm]` are `default_image`, `bootstrap_image`, `vcpus`, `mem_mib`, `overlay_disk_mib`, `state_dir`, and `grpc_endpoint`. The default image is `nvcr.io/nvidia/base/ubuntu:24.04`. Use an image that includes the agents and tools your workloads need. + +The driver looks up sandbox images in local Docker or Podman before pulling from a registry. On Linux with Podman, start `podman.socket` so the driver can find local images. + +VM sandboxes have no network interface. All traffic flows through the OpenShell supervisor on the host. For networks that require a corporate proxy, the VM driver accepts the same `https_proxy` and `proxy_*` options as Podman. To reach a proxy on the gateway host, use `http://host.openshell.internal:`. + +## Kubernetes Driver + +The Kubernetes driver runs sandboxes as pods in a sandbox namespace. It requires the [Agent Sandbox](https://github.com/kubernetes-sigs/agent-sandbox) controller. Install the gateway with the Helm chart; see [Kubernetes setup](/kubernetes/setup). + + +The cluster CNI must enforce `NetworkPolicy` in every sandbox namespace. Without it, sandbox pods can bypass OpenShell network policy. + +Only the OpenShell gateway and the Agent Sandbox controller should be able to manage sandbox pods and the sandbox ServiceAccount in those namespaces. + + +| Gateway option | Helm value | Description | +|---|---|---| +| `namespace` | `server.sandboxNamespace` | Namespace for sandbox resources. Defaults to the release namespace. | +| `service_account_name` | `sandboxServiceAccount.name` | ServiceAccount for sandbox pods. | +| `default_image` | `sandbox.image.repository` / `.tag` / `.digest` | Default sandbox image. | +| `image_pull_policy` | `sandbox.image.pullPolicy` | `always`, `if_not_present`, or `never`. | +| `image_pull_secrets` | `server.sandboxImagePullSecrets` | Image-pull Secrets for sandbox pods. | +| `grpc_endpoint` | `server.grpcEndpoint` | Gateway endpoint reachable from sandbox pods. | +| `client_tls_secret_name` | `server.tls.clientTlsSecretName` | Secret with sandbox client TLS material. | +| `sandbox_runtime_image` | `sandboxRuntime.image.*` | Override the sandbox runtime image. | +| `supervisor_image` | `supervisor.image.*` | Override the supervisor image. | +| `workspace_default_storage_size` | `server.workspaceDefaultStorageSize` | Default workspace PVC size. | +| `workspace_storage_class` | `server.workspaceStorageClass` | `StorageClass` for workspace PVCs. Set this if the cluster has no default `StorageClass`. | +| `https_proxy` | `upstreamProxy.url` | Corporate proxy for sandbox egress. | +| `no_proxy` | `upstreamProxy.noProxy` | Destinations that bypass the corporate proxy. | +| `proxy_auth_secret_name` / `proxy_auth_secret_key` | `upstreamProxy.authSecret.name` / `.key` | Secret holding the proxy `user:pass` credential. | +| `proxy_ca_bundle` | `upstreamProxy.caBundle.configMapName` / `.key` | ConfigMap with the proxy's CA certificate. | + +For the full list, see the [Gateway Configuration File](/how-it-works/gateways/configuration) reference. + +On OpenShift, copy the cluster proxy's CA into the gateway namespace and set `upstreamProxy.caBundle.configMapName` to `corporate-proxy-ca`: + +```shell +CORP_CA=$(oc get proxy/cluster -o jsonpath='{.spec.trustedCA.name}') +oc -n openshift-config get cm "$CORP_CA" -o jsonpath='{.data.ca-bundle\.crt}' > corp-ca.pem +oc -n openshell create configmap corporate-proxy-ca --from-file=ca.crt=corp-ca.pem +``` + +After upgrading Agent Sandbox, restart the gateway. + + +Workspace storage settings cannot change after a sandbox is created. Delete and recreate the sandbox to change them. + + +### Kubernetes PVC Mounts + +Mount existing PersistentVolumeClaims into the agent container through driver config. Any mount under `/sandbox` replaces the default workspace PVC for that sandbox. + +```shell +openshell sandbox create \ + --from registry.example.com/team/claude-code:1.0 \ + --driver-config-json '{ + "kubernetes": { + "volumes": [{ + "name": "user-data", + "persistent_volume_claim": {"claim_name": "pvc-user-data-123", "read_only": false} + }], + "containers": { + "agent": { + "volume_mounts": [ + {"name": "user-data", "mount_path": "/sandbox/.openshell/workspace", "sub_path": "workspace", "read_only": false} + ] + } + } + } + }' \ + -- claude +``` + +| Field | Description | +|---|---| +| `volumes[].name` | Volume name. | +| `volumes[].persistent_volume_claim.claim_name` | Existing PVC in the sandbox namespace. | +| `volumes[].persistent_volume_claim.read_only` | Defaults to `true`. | +| `containers.agent.volume_mounts[].name` | Volume to mount. | +| `containers.agent.volume_mounts[].mount_path` | Absolute path in the agent container. | +| `containers.agent.volume_mounts[].sub_path` | Optional relative path within the PVC. | +| `containers.agent.volume_mounts[].read_only` | Defaults to `true`. Read-write mounts require a read-write volume. | + +## Sandbox User Identity + +Set `process.run_as_user` and `process.run_as_group` in the sandbox policy to choose the sandbox user. Any non-root UID or GID is allowed. When a field is unset, the driver supplies it: + +| Driver | Default identity | +|---|---| +| Docker, Podman | The image's `USER`. Images without `USER` must set both fields in policy. | +| Kubernetes | OpenShift SCC namespace annotations, otherwise `1000`. Override with `sandbox_uid` and `sandbox_gid`. | +| MicroVM | The image's `sandbox` account, otherwise `1000`. Override with `sandbox_uid` and `sandbox_gid`. | + +On Docker, the image's `WORKDIR` becomes the workspace. Images with no `WORKDIR`, `/`, or `/sandbox` use `/sandbox`. Any other `WORKDIR` must exist in the image and be writable by the sandbox user. Podman, Kubernetes, and MicroVM always use `/sandbox`. diff --git a/docs/how-it-works/sandboxes/templates.mdx b/docs/how-it-works/sandboxes/templates.mdx new file mode 100644 index 0000000000..e8f895e504 --- /dev/null +++ b/docs/how-it-works/sandboxes/templates.mdx @@ -0,0 +1,65 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Sandbox Templates" +sidebar-title: "Templates" +slug: "how-it-works/sandboxes/templates" +description: "Define reusable sandbox workload settings and create sandboxes from templates." +keywords: "OpenShell, Sandboxes, Workload Templates, Images, Resources, Compute Drivers" +--- + +Sandbox workload templates let workspace admins define reusable runtime shapes for a workspace. A template stores the image, environment, resource requests, and driver-specific configuration that sandboxes should inherit. When you create a sandbox from a template, the create request can still attach providers, labels, and policy, but the workload comes from the named template. + +## Create a Template + +```shell +openshell sandbox template create gpu-kata \ + --image registry.example.com/agent:latest \ + --cpu 2 \ + --memory 4Gi \ + --gpu 1 \ + --label team=runtime \ + --env FEATURE_FLAG=on +``` + +Use `--gpu` without a count when the template should request the active +driver's default GPU assignment. Use `--gpu COUNT` when the template needs a +specific number of GPUs. + +For a separate template with driver-specific settings, create it with +`--driver-config-json`: + +```shell +openshell sandbox template create gpu-kata-custom \ + --image registry.example.com/agent:latest \ + --driver-config-json '{"kubernetes":{"pod":{"runtime_class_name":"kata-containers","node_selector":{"pool":"gpu"}}}}' +``` + +If you omit `--image`, the gateway applies its default sandbox image when a sandbox is created from the template. Use this when the template should only define resource, environment, or driver settings. + +## Create a Sandbox from a Template + +```shell +openshell sandbox create --template gpu-kata --provider github -- claude +``` + +The `--template` flag cannot be combined with inline workload flags such as `--from`, `--cpu`, `--memory`, `--gpu`, `--env`, or `--driver-config-json`. Put those values on the template instead. Create-time policy and provider attachments remain part of the sandbox request, so each sandbox can keep its own access boundary. + +## Manage Templates + +```shell +openshell sandbox template list +openshell sandbox template list --label-selector team=runtime +openshell sandbox template get gpu-kata +openshell sandbox template delete gpu-kata +``` + +Use `--all-workspaces` with `sandbox template list` when you need an admin view across workspaces: + +```shell +openshell sandbox template list --all-workspaces +``` + +For JSON or YAML, template list output contains `templates` and +`next_page_token` fields. Pass the returned token to `--page-token` to +continue. diff --git a/docs/sandboxes/manage-workspaces.mdx b/docs/how-it-works/workspaces.mdx similarity index 97% rename from docs/sandboxes/manage-workspaces.mdx rename to docs/how-it-works/workspaces.mdx index 74ae99a71d..50bb248a0d 100644 --- a/docs/sandboxes/manage-workspaces.mdx +++ b/docs/how-it-works/workspaces.mdx @@ -38,7 +38,7 @@ must also contain the scope required by the operation. Common scopes include `workspace:read`, `workspace:write`, `sandbox:read`, `sandbox:write`, `provider:read`, `provider:write`, `config:read`, and `config:write`. `openshell:all` satisfies every scope requirement. For OIDC and scope -configuration, refer to [Gateway Authentication](/reference/gateway-auth). +configuration, refer to [Gateway Authentication](/how-it-works/gateways/authentication). The following table summarizes common operations. @@ -235,6 +235,6 @@ workspace deletion. ## Next Steps -- To configure OIDC roles and scopes, refer to [Gateway Authentication](/reference/gateway-auth). -- To create resources in a workspace, refer to [Manage Sandboxes](/sandboxes/manage-sandboxes). -- To manage workspace credentials, refer to [Providers](/sandboxes/manage-providers). +- To configure OIDC roles and scopes, refer to [Gateway Authentication](/how-it-works/gateways/authentication). +- To create resources in a workspace, refer to [Manage Sandboxes](/how-it-works/sandboxes/overview). +- To manage workspace credentials, refer to [Providers](/how-it-works/providers/overview). diff --git a/docs/images/openshell-extension-points.svg b/docs/images/openshell-extension-points.svg new file mode 100644 index 0000000000..4f433725de --- /dev/null +++ b/docs/images/openshell-extension-points.svg @@ -0,0 +1,116 @@ + + + + + OpenShell extension points + Gateway interceptors and drivers extend the control plane. Middleware and isolation backends extend the OpenShell runtime. Middleware connects approved traffic to external services, while the compute driver provisions the sandbox boundary. + + + + + + + + + + + + + GATEWAY (CONTROL PLANE) + EXTERNAL SERVICES + OPENSHELL RUNTIME (DATA PLANE) + + + + + + + + API Server + auth · state · lifecycle + + + EXTENSION POINT + Gateway interceptors + modify · validate · observe + + + EXTENSION POINT + Credential driver + stores secret handles + + + EXTENSION POINT + Compute driver + places sandboxes + + + Credential store + + + + + + + + + Services and models + APIs · tools · inference + + + + + + Supervisor + policy · credentials + network mediation + + + EXTENSION POINT + Middleware + inspect · transform · deny + + + EXTENSION POINT + Isolation backend + controls the workload + + + SANDBOX BOUNDARY + + Agent + workload + + + + + + + + PROVISION + + + + Core component + + Extension point + + Workload + + Sandbox boundary + + diff --git a/docs/images/openshell-isolation-backend.svg b/docs/images/openshell-isolation-backend.svg new file mode 100644 index 0000000000..0955086d0b --- /dev/null +++ b/docs/images/openshell-isolation-backend.svg @@ -0,0 +1,62 @@ + + + + + OpenShell isolation backend + The supervisor calls the IsolationBackend Rust interface. OpenShellRuntimeBackend implements that interface as a supervisor-side client and talks to openshell-sandbox, the workload-side server, over the OpenShell Sandbox Protocol. + + + + + + + + + + + + + TRUSTED + SANDBOX + + + + SUPERVISOR PROCESS + + + Supervisor + consumer + + + CALLS + + + IsolationBackend + shared interface + + + IMPL + + + OpenShellRuntimeBackend + supervisor-side client + + + + + openshell-sandbox + workload-side server + + + SANDBOX + PROTOCOL + diff --git a/docs/images/openshell-kubernetes-runtime.svg b/docs/images/openshell-kubernetes-runtime.svg new file mode 100644 index 0000000000..112cde55d2 --- /dev/null +++ b/docs/images/openshell-kubernetes-runtime.svg @@ -0,0 +1,108 @@ + + + + + OpenShell runtime on Kubernetes + The gateway creates an Agent Sandbox custom resource and a separate supervisor Pod. The Agent Sandbox controller creates the workload Pod. A NetworkPolicy denies workload-initiated egress and admits only supervisor traffic to the workload's boundary Service. The supervisor initiates an authenticated TLS channel, evaluates agent requests, and opens policy-approved upstream connections. + + + + + + + + + + + + + + + GATEWAY + + + API Server + Deployment or StatefulSet + + Compute driver + provisions resources + + + + + Sandbox CR + Agent Sandbox API + controller creates Pod + + + NetworkPolicy + no workload egress + supervisor ingress only + + + Workspace PVC + /sandbox persists + + + SUPERVISOR POD + + Supervisor + Policy evaluation + Credentials and proxying + Gateway session + DIRECTLY MANAGED + BY OPENSHELL + + + WORKLOAD POD + + OpenShell Sandbox + process and syscall boundary + + + Agent + untrusted workload + AGENT SANDBOX CONTROLLER POD + + SUPERVISOR DIALS + TLS CHANNEL + + Service + TLS · 5500 + boundary + + + Agent requests return + on this channel + + + K8S API + + OUTBOUND + SESSION + + + External services + APIs · tools · models + + POLICY-APPROVED EGRESS + + + + + NO WORKLOAD-INITIATED EGRESS + + diff --git a/docs/images/openshell-sandbox-authentication.svg b/docs/images/openshell-sandbox-authentication.svg new file mode 100644 index 0000000000..d2beafc8bf --- /dev/null +++ b/docs/images/openshell-sandbox-authentication.svg @@ -0,0 +1,84 @@ + + + + + OpenShell sandbox authentication + The compute driver gives the supervisor a bootstrap credential. The supervisor presents it to the gateway, which issues a gateway JWT and a sandbox JWT. The supervisor uses the gateway JWT with the gateway and the sandbox JWT over mutual TLS with the OpenShell Sandbox, which holds only the gateway's public key. + + + + + + + + + + + + + GATEWAY (CONTROL PLANE) + TRUSTED + SANDBOX · NETWORK ISOLATED + + + + + API Server + signs every JWT + checks the sandbox record + + Compute driver + delivers or verifies the + bootstrap credential + + + + Supervisor + HOLDS TOKENS IN MEMORY + Gateway JWT for the gateway + Sandbox JWT for the sandbox + + Renews both together + while the sandbox exists + + + + + OpenShell Sandbox + VERIFIES, NEVER SIGNS + Gateway public key only + Checks the sandbox JWT + Fresh TLS certs per run + + Agent + sees no credentials + + + + + 1 · BOOTSTRAP + + + 2 · AUTHENTICATES + + + 3 · ISSUES JWT PAIR + + + 4 · SANDBOX JWT + MUTUAL TLS + + Every JWT names one sandbox and one run of it. Restarting a sandbox issues new tokens and TLS certificates. + diff --git a/docs/images/openshell-sandbox-enforcement.svg b/docs/images/openshell-sandbox-enforcement.svg new file mode 100644 index 0000000000..6d7b7bf7a6 --- /dev/null +++ b/docs/images/openshell-sandbox-enforcement.svg @@ -0,0 +1,105 @@ + + + + + OpenShell sandbox enforcement flow + The sandbox workload and trusted supervisor are separate boundaries. All workload network egress is denied except the authenticated Sandbox Protocol connection to the supervisor. + + + + + + + + + + + + + + + SANDBOX · NETWORK ISOLATED + + CONTAINER · VM + + Agent + process + + OpenShell + Sandbox + process owner + + + 1 + TCP or DNS request + Identifies the program + + + + ALL OTHER EGRESS DENIED + + ONLY ALLOWED EGRESS + Sandbox Protocol + Unix socket · TCP · vsock + + + 2 + + SUPERVISOR · TRUSTED + + + Isolation + backend + verifies boundary + + Policy + enforcement + policy · credentials + + + 3 + Receives request with + trusted process identity + Checks destination, binary, + L7 rules, and credentials + + + Upstream + service + approved connection + + + 4 + + LAUNCH GATE + + + + ATTACH + + BOUND + + CONFIRMED + + READY + + ✓ + RUNNING + + + Agent cannot start until the boundary is confirmed + + diff --git a/docs/images/openshell-sandbox-protocol.svg b/docs/images/openshell-sandbox-protocol.svg new file mode 100644 index 0000000000..51afd7e860 --- /dev/null +++ b/docs/images/openshell-sandbox-protocol.svg @@ -0,0 +1,84 @@ + + + + + OpenShell Sandbox Protocol + The trusted supervisor and the network-isolated OpenShell Sandbox share one mutually authenticated connection. Separate streams carry control, DNS, and each TCP connection. The agent reaches the supervisor only through the OpenShell Sandbox. + + + + + + + + + + + + + TRUSTED + OPENSHELL SANDBOX PROTOCOL + SANDBOX · NETWORK ISOLATED + + + + Supervisor + POLICY AND EGRESS + Policy evaluation + Credential injection + DNS resolution + Upstream connections + + Holds the gateway session + + + + + OpenShell Sandbox + PROCESS AND SYSCALL BOUNDARY + Owns the agent process + Identifies each program + Intercepts TCP and DNS + Freezes the agent on disconnect + + Agent + untrusted workload + + + + + + + + + + Control + attach · confirm · start · exec · signals · health + + + DNS + query and mediated response + + + TCP stream 1 + destination · program identity · bytes + + + TCP stream N + independent connection and backpressure + + ONE MUTUALLY AUTHENTICATED HTTP/2 CONNECTION + + Transport: Unix socket (Docker, Podman), TCP (Kubernetes), or vsock (MicroVM). Authentication and protocol behavior stay the same. + diff --git a/docs/images/openshell-system-architecture.svg b/docs/images/openshell-system-architecture.svg new file mode 100644 index 0000000000..7a6d4b59fa --- /dev/null +++ b/docs/images/openshell-system-architecture.svg @@ -0,0 +1,112 @@ + + + + + OpenShell system architecture + User interfaces connect to the gateway. The OpenShell Runtime places a trusted supervisor separately from a network-isolated sandbox workload. The workload's only allowed network path is its mediated connection to the supervisor, which connects to approved external services. + + + + + + + + + + + + + + USER INTERFACES + + + CLI + + SDK + + TUI + + EXTERNAL SERVICES + + + Services + APIs and tools + + Models + inference APIs + + GATEWAY (CONTROL PLANE) + + + API Server + API, authentication, lifecycle, relays + + Durable state + sandboxes · policies · providers · settings + + Compute driver + places and fences each sandbox + + + + OPENSHELL RUNTIME (DATA PLANE) + + + + Supervisor + GOVERNS THE AGENT + Policy evaluation + Credential resolution + DNS and proxying + Agent session multiplexing + + Maintains the gateway session + + + SANDBOX · NETWORK ISOLATED + (CONTAINER · VM) + + OpenShell Sandbox + process owner and syscall boundary + + Agent + untrusted workload + + + + MEDIATED CHANNEL + + + + + + WORKLOAD NETWORK RULE + Deny all egress + except to the supervisor + + + gRPC / HTTP + + OUTBOUND + SESSION + + PROVISION + + + POLICY-APPROVED EGRESS + + diff --git a/docs/index.mdx b/docs/index.mdx index a48bff2bca..c05fe445cf 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -35,6 +35,12 @@ that protect your data, credentials, and infrastructure. Agents run with exactly nothing more, governed by declarative policies that prevent unauthorized file access, data exfiltration, and uncontrolled network activity. + +New in OpenShell 0.1.0: a [stable release cadence](/about/support-matrix#releases), new [isolation primitives](/about/architecture), and an expanded [extension surface](/extensibility/overview), along with much more. + +See our [upgrade guide](/upgrade/0-1-0) for everything that's changed. + + ## Get Started Install OpenShell and create your first sandbox in two commands. @@ -54,7 +60,7 @@ openshell sandbox create -Refer to [Run Your First Agent](/about/run-an-agent) for the complete image, +Refer to [Run Your First Agent](/about/run-your-first-agent) for the complete image, provider, and policy workflow. --- @@ -71,28 +77,28 @@ Learn about OpenShell and its capabilities. Concept
- + Prepare an image, attach providers, and launch an agent in a sandbox. Tutorial - + Hands-on walkthroughs from first sandbox to custom policies. Concept - + Deploy gateways, create sandboxes, configure policies, providers, and workload images for your AI agents. Concept - + Attach model providers to selected sandboxes and call their native endpoints without exposing credentials. @@ -106,7 +112,7 @@ Understand sandbox logs, access them with the CLI and TUI, and export OCSF JSON How-To - + Define filesystem, process, and network controls for sandbox workloads. diff --git a/docs/index.yml b/docs/index.yml index d549ac1986..6535fd9005 100644 --- a/docs/index.yml +++ b/docs/index.yml @@ -12,71 +12,69 @@ navigation: - page: "Why OpenShell" path: about/overview.mdx - page: "Architecture" - path: about/how-it-works.mdx + path: about/architecture.mdx - page: "Installation" path: about/installation.mdx - page: "Run Your First Agent" path: about/run-an-agent.mdx - page: "Support Matrix" - path: reference/support-matrix.mdx + path: about/support-matrix.mdx - section: "How It Works" - slug: manage + slug: how-it-works contents: - section: "Gateways" slug: gateways contents: - page: "Overview" - path: sandboxes/manage-gateways.mdx + path: how-it-works/gateways/overview.mdx - page: "Authentication" - path: reference/gateway-auth.mdx + path: how-it-works/gateways/authentication.mdx - page: "Configuration" - path: reference/gateway-config.mdx + path: how-it-works/gateways/configuration.mdx - page: "Container Deployment" - path: reference/container-gateway.mdx + path: how-it-works/gateways/container-deployment.mdx - page: "Workspaces" - path: sandboxes/manage-workspaces.mdx + path: how-it-works/workspaces.mdx - section: "Sandboxes" slug: sandboxes contents: - page: "Overview" - path: sandboxes/manage-sandboxes.mdx + path: how-it-works/sandboxes/overview.mdx + - page: "Templates" + path: how-it-works/sandboxes/templates.mdx - page: "Runtimes" - path: reference/sandbox-compute-drivers.mdx + path: how-it-works/sandboxes/runtimes.mdx - section: "Providers" slug: providers contents: - page: "Overview" - path: sandboxes/manage-providers.mdx + path: how-it-works/providers/overview.mdx - page: "Profiles" - path: providers/profiles.mdx + path: how-it-works/providers/profiles.mdx - page: "AWS" - path: providers/aws-sigv4.mdx + path: how-it-works/providers/aws.mdx - page: "Google" - path: providers/google-cloud.mdx + path: how-it-works/providers/google.mdx - section: "Policies" slug: policies contents: - page: "Overview" - path: sandboxes/policies.mdx + path: how-it-works/policies/overview.mdx - page: "Advisor" - path: sandboxes/policy-advisor.mdx + path: how-it-works/policies/advisor.mdx - page: "Schema" - path: reference/policy-schema.mdx + path: how-it-works/policies/schema.mdx - page: "Prover" - path: reference/policy-prover.mdx + path: how-it-works/policies/prover.mdx - page: "Default Policy" - path: reference/default-policy.mdx + path: how-it-works/policies/default-policy.mdx - page: "Inference" - path: sandboxes/inference-routing.mdx + path: how-it-works/inference.mdx - section: "Extensibility" slug: extensibility contents: - page: "Overview" path: extensibility/overview.mdx - - page: "Protocol Negotiation" - path: extensibility/extension-negotiation.mdx - - page: "Authentication" - path: extensibility/extension-authentication.mdx - section: "Supervisor Middleware" slug: supervisor-middleware path: extensibility/supervisor-middleware/index.mdx @@ -98,12 +96,14 @@ navigation: - section: "Tutorials" slug: tutorials contents: + - page: "Run Pi" + path: tutorials/run-pi.mdx - page: "First Network Policy" - path: get-started/tutorials/first-network-policy.mdx + path: tutorials/first-network-policy.mdx - page: "GitHub Push Access" - path: get-started/tutorials/github-sandbox.mdx + path: tutorials/github-sandbox.mdx - page: "Microsoft Graph Provider Refresh" - path: get-started/tutorials/microsoft-graph-provider-refresh.mdx + path: tutorials/microsoft-graph-provider-refresh.mdx - section: "SDK Reference" slug: sdk contents: @@ -116,9 +116,9 @@ navigation: - page: "TypeScript" path: sdk/typescript.mdx - page: "API Errors" - path: reference/api-errors.mdx + path: sdk/api-errors.mdx - page: "Protobuf Time Types" - path: reference/protobuf-time-types.mdx + path: sdk/protobuf-time-types.mdx - folder: security title: "Security" - section: "Upgrade Guides" diff --git a/docs/kubernetes/access-control.mdx b/docs/kubernetes/access-control.mdx index 3d17597fbe..5b295e3211 100644 --- a/docs/kubernetes/access-control.mdx +++ b/docs/kubernetes/access-control.mdx @@ -17,7 +17,7 @@ The OpenShell gateway supports two access-control models for human callers on Ku The Helm chart always generates mTLS certificates at install time. The gateway uses them for transport-layer security regardless of which access-control model you choose. The client bundle in the `openshell-client-tls` secret is used internally by sandbox supervisors, not for granting access to individual users. -For how the CLI resolves gateways and stores credentials, refer to [Gateway Authentication](/reference/gateway-auth). +For how the CLI resolves gateways and stores credentials, refer to [Gateway Authentication](/how-it-works/gateways/authentication). ## Sandbox Supervisor Identity diff --git a/docs/kubernetes/openshift.mdx b/docs/kubernetes/openshift.mdx index ecfddefd0e..c6189b1ebb 100644 --- a/docs/kubernetes/openshift.mdx +++ b/docs/kubernetes/openshift.mdx @@ -30,7 +30,7 @@ operations that write results back into workload memory — `getpeername`, per-message length write-backs. Outbound-oriented workloads run unchanged; server workloads that read the peer address on accept need a node kernel with `WAIT_KILLABLE_RECV` (Linux 5.19+, or a distribution backport). See the -[support matrix](/reference/support-matrix#legacy-read-only-mode-kernels-before-linux-519) +[support matrix](/about/support-matrix#legacy-read-only-mode-kernels-before-linux-519) for the full behavior; the selected mode is reported as `seccomp_listener_mode` in the sandbox qualification output. diff --git a/docs/kubernetes/sandbox-runtime.mdx b/docs/kubernetes/sandbox-runtime.mdx deleted file mode 100644 index ac22288af4..0000000000 --- a/docs/kubernetes/sandbox-runtime.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "Kubernetes Sandbox Runtime" -sidebar-title: "Sandbox runtime" -description: "Understand how Kubernetes places and protects the sandbox runtime and supervisor." -keywords: "Generative AI, Cybersecurity, Kubernetes, Sandboxing, Network Policy, Seccomp, Landlock" -position: 2 ---- - -OpenShell runs each Kubernetes sandbox as two separately scheduled workloads. -The sandbox owns the agent process. The supervisor owns gateway credentials, -policy decisions, and upstream connections. - -## Understand the Components - -The Kubernetes driver always uses this placement: - -```mermaid -flowchart LR - Gateway[OpenShell gateway] - Supervisor[Supervisor Pod] - Sandbox[Sandbox workload Pod] - Agent[Agent processes] - External[External services] - - Gateway <-->|JWT-authenticated session| Supervisor - Supervisor <-->|TLS and bootstrap token| Sandbox - Sandbox --> Agent - Supervisor --> External -``` - -`openshell-sandbox` runs as PID 1 in the workload container. It launches the -agent, applies Landlock and child seccomp filters, identifies the process behind -each network operation, and relays approved streams. `openshell-supervisor` runs -in a directly managed Pod. It authenticates to the gateway, evaluates policy, -handles L7 and provider transformations, and opens upstream connections. - -Both containers run as the same namespace-resolved non-root UID and GID. Their -Pod specs set `allowPrivilegeEscalation: false`, drop every Linux capability, -and use `RuntimeDefault` seccomp. The sandbox installs an additional nested -seccomp user-notification filter without requesting a capability. Startup fails -closed if the runtime blocks the required seccomp or Landlock operations. - -The supervisor Pod points directly to the Sandbox resource with a non-controller -owner reference. Kubernetes therefore removes it when the Sandbox is deleted, -while the Agent Sandbox controller remains the sole controller of the workload -Pod. - -## Enforce Network Isolation - -The driver creates one workload fence per sandbox namespace before it releases -any workload Pod: - -```yaml -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -spec: - podSelector: - matchLabels: - openshell.ai/boundary-role: workload - policyTypes: [Ingress, Egress] - ingress: - - from: - - podSelector: - matchLabels: - openshell.ai/boundary-role: supervisor - ports: - - protocol: TCP - port: 5500 - egress: [] -``` - -The empty egress list blocks direct DNS, gateway, node, metadata, and Internet -connections from every OpenShell workload in the namespace. The ingress rule -allows OpenShell supervisor Pods to reach sandbox TLS listeners. TLS, JWT -claims, session generation, and recorded Pod UIDs—not the NetworkPolicy—bind a -supervisor to its exact sandbox. Supervisors can reach cluster DNS, the gateway, -and policy-approved upstream destinations unless another namespace policy -restricts them. - -Kubernetes policies are additive. Keep sandbox namespaces under administrative -control so another principal cannot add permissive policies, create Pods with -OpenShell labels, or read bootstrap Secrets. The cluster CNI MUST enforce both -ingress and egress `NetworkPolicy` in every sandbox namespace. Kubernetes accepts -policy objects even when no CNI enforces them; OpenShell does not test traffic -to verify enforcement. - -## Bootstrap a Sandbox - -Resource admission checks external references selected through the OpenShell-owned -Pod template before provisioning and again before releasing the workload's -scheduling gate. Kubernetes API-server and admission-webhook mutations of the -live Pod are trusted cluster-operator behavior and are not used as Workspace User -authorization inputs. PVCs and other supported external references require -operator approval labels, including same-namespace and read-only mounts. -Unexpected references, changed resource UIDs, and unsupported volume sources fail -closed. GPU device attachments are temporarily exempt. The driver rechecks -persisted references on restart and every 30 seconds during reconciliation; -confirmed revocation suspends compute, while transient lookup failures block new -launches and recovery. - -See [External Resource Admission](../reference/gateway-config#external-resource-admission) -for label configuration and upgrade requirements. Admission cannot repair data -or credentials compromised before upgrade. - -The driver creates each sandbox generation in a fail-closed order: - -1. Create and validate the workload egress fence. -2. Create the Sandbox resource with a scheduling gate. -3. Inspect the admitted Pod identity, security context, DNS settings, and - generation-specific Secret reference. -4. Create a gated supervisor Pod and separate immutable Secrets for sandbox and - supervisor trust material. Outside shared mode, the supervisor Secret also - carries the gateway client TLS material. In managed mode, the driver also - creates immutable copies of the configured image-pull Secrets for the - generation. -5. Remove both scheduling gates. -6. Publish readiness only after the supervisor attaches, confirms enforcement, - and registers the gateway relay. - -The trusted sandbox init container copies its Secret into a memory-backed -volume. The main container never mounts the projected Secret and removes the -staged bootstrap before it launches untrusted code. The supervisor receives an -audience-bound Kubernetes token, exchanges it for a sandbox-scoped JWT, and -keeps gateway and provider credentials outside the workload Pod. - -Stopping a sandbox removes both the workload and supervisor Pods. Starting it -creates a new generation with new Secrets and a replacement supervisor Pod -while preserving the workspace PVC. The namespace-wide workload fence remains -in place across sandbox generations. - -If provisioning is interrupted, recovery first confirms that the old workload -Pod is gone. It then deletes the recorded generation's Secrets by name and -clears the rollback state so the next generation can be created. Each -generation Secret is owned by its Pod, so Kubernetes garbage collection removes -any other generation. The Helm chart grants the gateway `create` and `delete` -access to Secrets for this lifecycle. - -## Check Cluster Requirements - -This architecture requires the following cluster behavior: - -- Linux nodes and a container runtime that permits an unprivileged process to - install a nested seccomp user-notification filter under `RuntimeDefault`. -- Landlock enabled and usable by the non-root sandbox process. -- A CNI that enforces `networking.k8s.io/v1` ingress and egress policies, - including node-local and metadata destinations. -- Support for Pod scheduling gates and the safe - `net.ipv4.ip_unprivileged_port_start=0` sysctl. -- Administrative control of sandbox namespaces and OpenShell role labels. - -OpenShell actively probes the Linux primitives and validates the admitted Pod -before starting the agent. Treat a failed probe or changed security posture as -an unsupported runtime, not a degraded mode. diff --git a/docs/kubernetes/setup.mdx b/docs/kubernetes/setup.mdx index dc9a138207..b43ac2b073 100644 --- a/docs/kubernetes/setup.mdx +++ b/docs/kubernetes/setup.mdx @@ -8,10 +8,6 @@ keywords: "Generative AI, Cybersecurity, Kubernetes, Helm, Gateway, Deployment, position: 1 --- - -The OpenShell Helm chart is experimental and under active development. Templates, values, and defaults can change between releases. Do not use it in production. - - Your cluster MUST use a CNI that enforces Kubernetes `NetworkPolicy` for both ingress and egress in every sandbox namespace. OpenShell creates the policies, @@ -20,7 +16,21 @@ sandbox workloads may reach the network directly and bypass supervisor policy. Verify CNI support before installing OpenShell. -Use the Kubernetes deployment when the gateway should run on a shared cluster, in a cloud environment, or as part of team infrastructure. The Helm chart handles PKI bootstrap, RBAC, sandbox namespace setup, and the gateway workload. It uses a StatefulSet by default for the SQLite database, and can render a Deployment when `server.externalDbSecret` points at an external database. +![OpenShell on Kubernetes: the gateway provisions a Sandbox resource, separate supervisor and workload Pods, a boundary Service, NetworkPolicy, and a workspace PVC.](../images/openshell-kubernetes-runtime.svg) + +The gateway's Kubernetes compute driver creates a `Sandbox` resource and a +separate supervisor Pod. The Agent Sandbox controller creates the workload Pod +from that resource. A Service gives the supervisor a stable address for the +workload's authenticated TLS boundary, and a PVC preserves `/sandbox` across +Pod restarts. The gateway can run in the same namespace as these resources or +in a separate namespace. + +The supervisor opens the boundary connection and maintains an outbound session +to the gateway. A `NetworkPolicy` allows only supervisor ingress to the +workload's boundary port and denies new workload-initiated connections. Agent +network requests return on the established channel; the supervisor evaluates +policy and opens approved upstream connections. For the trust boundaries and +request flow, see [Architecture](/about/architecture). ## Prerequisites @@ -163,7 +173,7 @@ helm upgrade --install openshell \ The driver stores every credential in that namespace, in every workspace mode. The gateway receives Secret permissions through a Role in that namespace only. For the full set of options, refer to the -[gateway configuration reference](/reference/gateway-config#credential-drivers). +[gateway configuration reference](/how-it-works/gateways/configuration#credential-drivers). ## Wait for the gateway to be ready @@ -245,12 +255,6 @@ The most commonly changed values are: | `supervisor.sandboxRuntime.boundaryPort` | Non-privileged TLS port used between paired supervisor and sandbox Pods. | | `upstreamProxy` | Operator-owned corporate HTTP forward proxy for policy-approved TLS egress. Refer to [Configure a Corporate Upstream Proxy](#configure-a-corporate-upstream-proxy). | -### Run multiple gateway replicas - -Use a Deployment and shared PostgreSQL to run more than one gateway replica. -Refer to [High Availability](/kubernetes/high-availability) for the database -Secret, Helm values, pod placement, verification, and failover behavior. - Use a values file for repeatable deployments: ```shell @@ -368,9 +372,8 @@ The gateway exposes `/healthz` for process liveness and `/readyz` for dependency ## Next Steps -- Kubernetes sandboxes use separate workload and directly managed supervisor Pods; refer to [Sandbox runtime](/kubernetes/sandbox-runtime). - To run multiple gateway replicas, refer to [High Availability](/kubernetes/high-availability). - To enable automatic certificate rotation with cert-manager, refer to [Managing Certificates](/kubernetes/managing-certificates). - To expose the gateway externally without port-forwarding, refer to [Ingress](/kubernetes/ingress). - To configure OIDC or reverse-proxy authentication, refer to [Access Control](/kubernetes/access-control). -- To create your first sandbox, refer to [Manage Sandboxes](/sandboxes/manage-sandboxes). +- To create your first sandbox, refer to [Manage Sandboxes](/how-it-works/sandboxes/overview). diff --git a/docs/observability/logging.mdx b/docs/observability/logging.mdx index 13ddfeda6d..61882c8b74 100644 --- a/docs/observability/logging.mdx +++ b/docs/observability/logging.mdx @@ -267,4 +267,4 @@ Both files rotate daily and retain the 3 most recent files to bound disk usage. - [Access logs](/observability/accessing-logs) through the CLI, TUI, or sandbox filesystem. - [Enable OCSF JSON export](/observability/ocsf-json-export) for SIEM integration and compliance. -- Learn about [network policies](/sandboxes/policies) that generate these events. +- Learn about [network policies](/how-it-works/policies/overview) that generate these events. diff --git a/docs/reference/sandbox-compute-drivers.mdx b/docs/reference/sandbox-compute-drivers.mdx deleted file mode 100644 index 395a04edf8..0000000000 --- a/docs/reference/sandbox-compute-drivers.mdx +++ /dev/null @@ -1,686 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "Sandbox Runtimes" -sidebar-title: "Runtimes" -description: "Reference for Docker, Podman, MicroVM, Kubernetes, and Windows MXC sandbox runtimes." -keywords: "Generative AI, Cybersecurity, AI Agents, Sandboxing, Docker, Podman, MicroVM, Kubernetes, MXC, Reference" -position: 4 ---- - -The gateway's configured compute driver determines how OpenShell creates each sandbox. The CLI workflow stays the same across drivers: you create, connect to, inspect, stop, start, and delete sandboxes through the gateway API. - -Caller driver config is disabled by default across drivers. Enabling it does -not authorize external attachments: referenced resources must carry matching -operator-controlled approval labels. GPU device attachments are temporarily -exempt. Host bind mounts, supplemental image mounts, and MXC host filesystem -grants lack a trusted label resolver and are unavailable with admission enabled. -See [External Resource Admission](gateway-config#external-resource-admission) -for configuration, migration, and the explicit unsafe opt-out. - -Most compute drivers run the OpenShell supervisor inside the sandbox workload. -The supervisor launches the agent process, applies policy, routes egress through -the proxy, injects configured credentials, and maintains the gateway session. -A driver may instead set `driver_reports_runtime_readiness`. In that mode, -driver-reported readiness does not require a supervisor session. The canonical -create-time policy is part of `DriverSandboxSpec`; a driver that enforces policy -outside the standard supervisor fetches later revisions through the existing -sandbox configuration API. The Windows MXC driver reports its own readiness. - -Stop stops compute but retains the sandbox record and the driver's -persistent workspace boundary. Start reactivates the same driver resource. -Delete remains independent and removes compute plus driver-owned persistent -state. While a sandbox is stopped, gateway access paths and exposed services -remain unavailable. - -Restarting the gateway preserves this intent. During graceful shutdown, the -gateway stops running-intent Docker, Podman, and MicroVM sandboxes through their -drivers without recording an explicit user stop. At startup it sends idempotent start -requests for Docker, Podman, and MicroVM sandboxes that were intended to run; -already-running resources are unchanged, retained stopped compute is restarted, -and explicitly stopped sandboxes remain stopped. Kubernetes workloads continue -running independently of the gateway process. - -Before exiting, the gateway waits up to ten seconds for supervisor-session -ownership cleanup so replacement supervisors can reconnect after restart. -If tracked cleanup exceeds this deadline, the gateway reports a shutdown -error. Persistence errors during ownership release are logged separately. - -The gateway forwards one exact, persisted main-process specification to every -driver. Drivers serialize that specification in -`OPENSHELL_MAIN_PROCESS_SPEC`; they do not install an idle `sleep` workload or -reconstruct argv with shell parsing. Runtime restart policies are disabled so -an exited canonical process remains a terminal sandbox result. Exit code zero -produces `Completed`; a nonzero or signal-normalized exit produces `Error` -with the exact exit code. Driver and supervisor failures remain `Error`. - -## Configure a Compute Driver - -Configure the compute driver on the gateway. Current releases accept one driver per gateway. Set `compute_driver` in the gateway TOML file: - -```toml -[openshell.gateway] -compute_driver = "docker" -``` - -Reserved built-in values are `docker`, `podman`, `kubernetes`, `vm`, and `mxc`. -The `mxc` driver is available only in native Windows gateway builds. -Non-reserved names select an extension driver and require a -`socket_path` in `[openshell.drivers.]`. - -When `compute_driver` is unset, the gateway auto-detects Kubernetes, then Podman, then Docker. Docker must respond on a known API socket. Podman first probes known API sockets and then asks the `podman` CLI for the active native or machine-backed socket. The VM driver is never auto-detected; configure it explicitly with `compute_driver = "vm"` or set `OPENSHELL_COMPUTE_DRIVER=vm` in the launch environment. - -Common gateway options: - -| Gateway TOML option | Description | -|---|---| -| `compute_driver = ""` | Select the compute driver. Built-in values are `docker`, `podman`, `kubernetes`, and `vm`; custom names require `[openshell.drivers.].socket_path`. | - -Set driver-specific values such as sandbox images, gateway endpoints, network names, TLS material, and VM sizing in the gateway TOML file. See the [Gateway Configuration File](./gateway-config) reference for the full `[openshell.drivers.]` schema. - -Extension drivers use the same `compute_driver.proto` gRPC surface as the -managed VM driver. For an out-of-tree driver, choose a driver name and point -the gateway at the Unix socket the operator has already provisioned: - -```toml -[openshell.gateway] -compute_driver = "kyma" - -[openshell.drivers.kyma] -socket_path = "/run/openshell/kyma.sock" -``` - -For a launch-time socket override, pass the selected driver name with the -socket path. The endpoint replaces normal driver construction for that name, -including canonical built-in names: - -```shell -openshell-gateway --drivers kyma --compute-driver-socket /run/openshell/kyma.sock -openshell-gateway --drivers docker --compute-driver-socket /run/openshell/docker.sock -``` - -The gateway connects to the operator-provided endpoint; it does not provision -or supervise the remote driver. The operator must protect the socket so only -the gateway uid can access it. - -Sandbox create supports `--cpu` and `--memory` for per-sandbox compute sizing. -Docker and Podman apply them as runtime limits. Kubernetes applies them as both -container requests and limits. The VM driver accepts the fields but currently -ignores them. - -Sandbox create also accepts experimental driver-owned config through -`--driver-config-json`. The value is a JSON object keyed by driver name. The -gateway forwards only the block for the active driver, so a Kubernetes gateway -receives the `kubernetes` object from a value such as: - -Nested keys inside each driver block use snake_case. The top-level envelope keys -are driver names, such as `kubernetes`, and are not part of the nested schema. - -```shell -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{"kubernetes":{"pod":{"runtime_class_name":"kata-containers","priority_class_name":"batch-low"}}}' \ - -- claude -``` - -Driver config is for fields without a stable public flag. Prefer `--cpu`, -`--memory`, and `--gpu` for supported resource intent. When `--gpu` is present -without a count, OpenShell treats it as a request for one GPU. Pass -`--gpu COUNT` when requesting more than one GPU. - -Kubernetes maps the GPU count to the `nvidia.com/gpu` pod resource limit. -Docker and Podman satisfy count-only GPU requests by selecting the requested -number of NVIDIA CDI devices from the local CDI inventory in round-robin order. -The drivers refresh the CDI inventory before validating or creating the -sandbox, so CDI devices added or removed after gateway start can affect later -creates. On WSL2 all-only runtimes, Docker or Podman can use -`nvidia.com/gpu=all` as a compatibility fallback, where it counts as one -selectable device. - -Exact GPU device selection remains driver-owned and requires `--gpu`. Docker -and Podman accept `cdi_devices` as opaque CDI device names; replace the -top-level `docker` key with `podman` when using the Podman driver, for example -`{"docker":{"cdi_devices":["nvidia.com/gpu=0"]}}`. Explicit CDI device lists -must not contain duplicates, and their length must match the effective GPU -count. A single exact CDI device is compatible with the default `--gpu` -request. The VM driver accepts `gpu_device_ids`, for example -`{"vm":{"gpu_device_ids":["0000:2d:00.0"]}}`; the current VM implementation -accepts at most one entry and allows either `--gpu` or `--gpu 1` when -`gpu_device_ids` is set. - -## Resource Capability Reporting - -API clients can read each configured driver's static resource request support -from the protected `GetGatewayInfo` response. The capability response describes -which request forms a driver implements. It does not report live resource -inventory, availability, or scheduling capacity, so a supported request can -still fail when the selected runtime cannot provide the resource. - -The same response includes the compute driver's negotiated extension snapshot. Protocol version and implementation version are separate: the implementation version identifies the OpenShell driver build, not the Docker daemon, Kubernetes server, or another compute backend. See [Extension Protocol Negotiation](/extensibility/extension-negotiation). - -CPU and memory capabilities report whether the driver enforces a resource -limit. GPU capabilities report whether the driver accepts a default GPU request -and an explicit GPU count. An omitted `resource_capabilities` message, or an -omitted CPU, memory, or GPU capability, means the driver did not report that -capability. A reported `false` value means that request form is unsupported. - -For Kubernetes, `pod.runtime_class_name` maps to PodSpec `runtimeClassName`. -It overrides the gateway's configured default runtime class for that sandbox, -while a typed `SandboxTemplate.runtime_class_name` value from the API still -takes precedence. - -Docker and Podman supervisors use host networking. On Linux they connect to the -gateway's primary loopback listener. Sandbox JWT authentication restricts each -supervisor to the sandbox-callable RPC allowlist; no additional gateway -listener is created. - -The published supervisor container uses a shell-free distroless Debian 13 image. -Inspect its container logs and health status with your runtime tools; it does not -provide a shell or package manager for interactive debugging. This does not -change the tools available inside your workload image. - -## Docker Driver - -[Docker](https://www.docker.com/get-started/)-backed sandboxes run as containers on the gateway host. Use Docker for local development, single-machine gateways, and hosts that already use Docker Desktop or Docker Engine. - -The gateway talks to the Docker daemon to create sandbox containers. Docker is also required for local image builds from directories or Dockerfiles. - -The trusted supervisor companion uses Docker host networking; the agent -workload retains `network=none`. On Linux the supervisor reaches the gateway at -its primary loopback endpoint. Docker Desktop requires host networking to be -enabled and does not support this mode together with Enhanced Container -Isolation. Set `grpc_endpoint` when the gateway is not reachable on the Docker -daemon host. - -For maintainer-level implementation details, refer to the [Docker driver README](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-docker/README.md). - -Select Docker with `compute_driver = "docker"` in `[openshell.gateway]`. Configure Docker driver values such as `socket_path`, `grpc_endpoint`, `sandbox_runtime_image`, `supervisor_image`, `image_pull_policy`, `sandbox_pids_limit`, and `guest_tls_*` in `[openshell.drivers.docker]`. The sandbox runtime image contains `/openshell-sandbox`; the supervisor image contains `/openshell-supervisor`. When `socket_path` is unset, the driver uses the same responsive local socket selected by auto-detection. An explicitly selected Docker driver falls back to `/var/run/docker.sock` when no candidate responds. - -When operating `openshell-driver-docker` as an external driver, set -`OPENSHELL_OTLP_ENDPOINT` to export its spans. The driver continues W3C trace -context from gateway RPCs and reports as `openshell-driver-docker`. - -Stop stops the existing Docker container without removing its writable -layer or attached volumes. Start starts that same container. A durably -stopped container stays stopped across gateway restart, and delete remains -responsible for removing it. Graceful gateway shutdown stops running-intent -Docker containers through the driver RPC without recording an explicit -sandbox stop. On startup, the gateway reconciles that retained intent with an -idempotent start request. Explicitly stopped sandboxes remain stopped. - -For GPU-backed Docker sandboxes, configure Docker CDI before starting the gateway so OpenShell can detect the daemon capability. - -### Docker Driver Config Mounts - -Docker driver config accepts user-supplied `volume` and `tmpfs` mounts. It also -accepts `bind` mounts when `[openshell.drivers.docker]` sets -`enable_bind_mounts = true` and explicitly disables resource admission in -`gateway.toml`. All examples require `allow_driver_config = true`. See Docker's [storage documentation](https://docs.docker.com/engine/storage/) for more information. -Docker local-driver named volumes created with bind options also expose -gateway-host paths, so OpenShell treats them like bind mounts and requires -`enable_bind_mounts = true`. - -Use a `volume` mount for existing Docker named volumes: - -```shell -docker volume create --label openshell.ai/sandbox-attachable=true \ - --label openshell.ai/sandbox-attachable-workspace=default openshell-work - -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{"docker":{"mounts":[{"type":"volume","source":"openshell-work","target":"/sandbox/work","read_only":false}]}}' \ - -- claude -``` - - -Bind mounts share gateway-host filesystem resources with the sandbox. They may -be considered insecure because they can negate OpenShell controls such as -workspace isolation and filesystem policy. Use them only when you understand and -accept that loss of isolation. - - -Raw paths cannot satisfy label admission. The following unsafe opt-out permits -bind mounts and removes label protection for all Docker attachments: - -```toml -[openshell.drivers.docker] -allow_driver_config = true -enable_bind_mounts = true - -[openshell.drivers.docker.resource_admission] -enabled = false -``` - -```shell -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{"docker":{"mounts":[{"type":"bind","source":"/srv/openshell/work","target":"/sandbox/work","read_only":false}]}}' \ - -- claude -``` - -Docker mount schema: - -| Type | Fields | -|---|---| -| `bind` | `source`, `target`, optional `read_only` (`true` by default), optional `selinux_label` (`shared` for `:z` or `private` for `:Z`). `source` must be an absolute host path. Requires `enable_bind_mounts = true`. | -| `volume` | `source`, `target`, optional `read_only` (`true` by default), optional `subpath`. The named volume must already exist. Docker local-driver bind-backed volumes require `enable_bind_mounts = true`. | -| `tmpfs` | `target`, optional `options`, optional `size_bytes`, optional `mode`. | - -OpenShell rejects mount `source`, `target`, and Docker volume `subpath` values -with surrounding whitespace. OpenShell also rejects mount targets that replace -the workspace root or container root, or contain or are contained by the -configured SSH socket or reserved `/opt/openshell`, `/etc/openshell`, -`/etc/openshell-tls`, `/run/openshell`, and network -namespace roots. These checks do not make host bind mounts safe. - -## Podman Driver - -[Podman](https://podman.io/)-backed sandboxes run as rootless containers on the gateway host. Use Podman for Linux workstation workflows that avoid a rootful Docker daemon. - -The gateway talks to the Podman API socket. The Podman driver requires Podman 5.x, cgroups v2, rootless networking, and an active Podman user socket. When `socket_path` is not set, the driver probes known socket paths, then uses the `podman` CLI to resolve the active native or machine-backed connection. It fails to start if neither method finds a socket. - -The agent workload uses `network=none`. Its trusted supervisor companion uses Podman's host network for its gateway session and policy-approved upstream connections. - -For maintainer-level implementation details, refer to the [Podman driver README](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-podman/README.md) and [Podman networking notes](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-podman/NETWORKING.md). - -Select Podman with `compute_driver = "podman"` in `[openshell.gateway]`. Configure Podman driver values such as `socket_path`, `network_name`, `sandbox_runtime_image`, `supervisor_image`, `stop_timeout_secs`, `image_pull_policy`, `grpc_endpoint`, `host_gateway_ip`, `ssh_socket_path`, `sandbox_pids_limit`, and `guest_tls_*` in `[openshell.drivers.podman]`. - -Podman sandboxes default to a 45-second graceful stop window before Podman escalates from `SIGTERM` to `SIGKILL`. Set `stop_timeout_secs` in gateway config, or `OPENSHELL_STOP_TIMEOUT` for the standalone driver, when a local runtime needs a different teardown window. - -Stop stops the existing Podman container while retaining its named workspace -volume and driver-owned secrets. Start starts the same container. Delete is -the operation that removes the container and named volume. Graceful gateway -shutdown stops running-intent Podman containers through the driver RPC without -recording an explicit sandbox stop. On startup, the gateway reconciles that -retained intent with an idempotent start request while leaving explicitly -stopped sandboxes alone. - -For proxy-required networks, the Podman driver also accepts the corporate egress proxy keys `https_proxy`, `no_proxy`, `proxy_auth_file`, `proxy_auth_allow_insecure`, and `proxy_connect_by_hostname`. The supervisor chains policy-approved TLS tunnels through the proxy with HTTP CONNECT instead of dialing destinations directly. See the [Gateway Configuration File](./gateway-config) reference for the full contract, including the cleartext-credential acknowledgement and the validated-IP CONNECT behavior. - -On Linux, the host-networked supervisor uses the gateway's primary loopback -endpoint. On macOS with `podman machine`, the driver uses gvproxy's -host-loopback IP, `192.168.127.254`, by default. Set `host_gateway_ip` only when -your Podman machine uses a non-standard host-loopback address, or set -`grpc_endpoint` explicitly when the gateway is remote. - -### Podman Driver Config Mounts - -Podman driver config accepts user-supplied `volume` and `tmpfs` mounts. -All examples require `allow_driver_config = true`. Supplemental `image` mounts -require disabling resource admission. It also accepts `bind` mounts when -`[openshell.drivers.podman]` sets `enable_bind_mounts = true` and explicitly -disables resource admission in `gateway.toml`. Podman local-driver named -volumes created with bind options also expose gateway-host paths, so -OpenShell treats them like bind mounts and requires `enable_bind_mounts = true`. -Host bind mounts expose gateway host paths to sandbox requests, so they are -disabled by default. - -Use a `volume` mount for existing Podman named volumes: - -```shell -podman volume create --label openshell.ai/sandbox-attachable=true \ - --label openshell.ai/sandbox-attachable-workspace=default openshell-work - -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{"podman":{"mounts":[{"type":"volume","source":"openshell-work","target":"/sandbox/work","read_only":false}]}}' \ - -- claude -``` - - -Bind mounts share gateway-host filesystem resources with the sandbox. They may -be considered insecure because they can negate OpenShell controls such as -workspace isolation and filesystem policy. Use them only when you understand and -accept that loss of isolation. - - -Raw paths cannot satisfy label admission. The following unsafe opt-out permits -bind mounts and removes label protection for all Podman attachments: - -```toml -[openshell.drivers.podman] -allow_driver_config = true -enable_bind_mounts = true - -[openshell.drivers.podman.resource_admission] -enabled = false -``` - -```shell -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{"podman":{"mounts":[{"type":"bind","source":"/srv/openshell/work","target":"/sandbox/work","read_only":false}]}}' \ - -- claude -``` - -Podman mount schema: - -| Type | Fields | -|---|---| -| `bind` | `source`, `target`, optional `read_only` (`true` by default), optional `selinux_label` (`shared` for `:z` or `private` for `:Z`). `source` must be an absolute host path. Requires `enable_bind_mounts = true`. | -| `volume` | `source`, `target`, optional `read_only` (`true` by default). The named volume must already exist. Podman local-driver bind-backed volumes require `enable_bind_mounts = true`. | -| `tmpfs` | `target`, optional `options`, optional `size_bytes`, optional `mode`. | -| `image` | `source`, `target`, optional `read_only` (`true` by default). | - -Podman `volume` and `image` mounts do not support `subpath` in OpenShell driver -config, and OpenShell rejects `subpath` for those mount types. OpenShell rejects -mount `source` and `target` values with surrounding whitespace. OpenShell also -rejects mount targets that replace the workspace root, container root, supervisor -files, `/etc/openshell`, `/etc/openshell-tls`, authentication material, or -network namespace paths. These checks do not make host bind mounts safe. - -## MicroVM Driver - -MicroVM-backed sandboxes run inside VM-backed isolation instead of a container boundary. Use MicroVM when workloads need a VM boundary instead of a local container boundary. - -The gateway uses the VM compute driver to create VM-backed sandboxes. MicroVM requires host virtualization support. It uses [libkrun](https://github.com/containers/libkrun) with Apple's [Hypervisor framework](https://developer.apple.com/documentation/hypervisor) on macOS, KVM on Linux, and [QEMU](https://www.qemu.org/) for GPU-backed sandboxes on Linux. - -The VM driver boots a cached immutable bootstrap ext4 root disk. Set `bootstrap_image` explicitly or let it fall back to the operator-configured `default_image`. The gateway rejects the VM configuration when both are empty, and the standalone driver also refuses to start; neither path uses a sandbox-requested image as the VM bootstrap image. When the requested sandbox image differs from the bootstrap image, the driver stages the registry image as an OCI layout, unpacks it inside a bootstrap VM with `umoci`, and caches the prepared image disk by image identity. Each sandbox receives that prepared disk read-only plus its own writable `overlay.ext4` disk for `/`, including `/sandbox` writes and runtime TLS material. The overlay persists for the sandbox lifetime and is deleted with the sandbox state directory. - -VM sandbox creation follows the same progress model as Kubernetes-backed sandboxes. The gateway accepts the sandbox, then the VM driver publishes watch events while it resolves the image, prepares or reuses the bootstrap and prepared image caches, creates the writable overlay, and starts the VM launcher. - -On graceful gateway shutdown, the gateway stops running-intent VMs through the driver RPC while retaining their launch records and writable overlays. On restart, the gateway starts a fresh VM driver process and reconciles the retained intent through the same idempotent start request used by the local container drivers. Running-intent VMs restart with their existing `overlay.ext4`, while explicitly stopped VMs remain stopped. - -Stopped VM state directories contain a marker that prevents startup from -launching the VM. The driver retains `sandbox.pb`, `overlay.ext4`, and extension -state, then removes the marker and restores the same overlay on start. - -CPU-only VMs do not inherit GPU filesystem allowances from the host. A policy can keep `/proc` read-only on a GPU-equipped host. For GPU-assigned VMs, the sandbox discovers GPU paths inside the guest. - -For maintainer-level implementation details, refer to the [VM driver README](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-vm/README.md). - -### Enable the VM Driver - -The VM driver is opt-in. Release packages can install `openshell-driver-vm`, but the gateway does not select it unless you configure the driver explicitly. - -Enable VM by setting `compute_driver = "vm"` in the gateway TOML file: - -```toml -[openshell.gateway] -compute_driver = "vm" -``` - -For a launch-time override, set `OPENSHELL_COMPUTE_DRIVER=vm` in the gateway environment and restart the service. - -Configure VM driver values such as `grpc_endpoint`, `driver_dir`, `state_dir`, `default_image`, `bootstrap_image`, `vcpus`, `mem_mib`, `overlay_disk_mib`, `krun_log_level`, and `guest_tls_*` in `[openshell.drivers.vm]`. The default workload and bootstrap image is `nvcr.io/nvidia/base/ubuntu:24.04`; configure a user-owned image with the agents and tools required by the workload. The VM `state_dir` stores overlay disks, console logs, runtime state, image-rootfs cache, and the private `run/compute-driver.sock` socket. The VM socket path is managed by the gateway and is not configurable through remote endpoint settings. - -The gateway starts `openshell-driver-vm` over a private Unix socket and passes its process ID so the driver can reject unexpected local clients. The driver's standalone TCP listener is disabled unless `--allow-unauthenticated-tcp` is set for local development. - -### Local image resolution - -The VM driver resolves sandbox images from a local container engine before falling back to registry pulls. It tries Docker first, then uses the same Podman socket discovery as the Podman driver. On Linux with Podman, enable the API socket so the driver can find local images: - -```shell -systemctl --user start podman.socket -``` - -### Network isolation - -VM sandboxes boot without a virtual NIC. `openshell-sandbox` intercepts workload -network syscalls inside the guest and carries mediated streams over virtio-vsock -to the host `openshell-supervisor`, which owns DNS, policy evaluation, and -external connections. The driver does not create TAP interfaces or host -nftables rules. - -### Corporate Proxy Egress - -For proxy-required networks, the VM driver accepts the same corporate egress proxy keys as the Podman driver: `https_proxy`, `no_proxy`, `proxy_auth_file`, `proxy_auth_allow_insecure`, `proxy_connect_by_hostname`, and `proxy_ca_bundle`. The host supervisor chains policy-approved TLS tunnels through the proxy with HTTP CONNECT instead of dialing destinations directly. - -The settings reach the host supervisor through driver-owned arguments, so a sandbox cannot select, alter, or disable the proxy from inside the guest. - -A proxy on the corporate network needs no special address and works on every VM sandbox. The guest's callback to the gateway never traverses the proxy. - -A proxy on the gateway host works for both libkrun and QEMU sandboxes. Configure -`https_proxy = "http://host.openshell.internal:"`; the host supervisor -normalizes that name to host loopback. - -The credential and private CA material stay with the host supervisor rather -than being staged into the guest. See the [Gateway Configuration File](./gateway-config) reference for the full contract, including the cleartext-credential acknowledgement and the validated-IP CONNECT behavior. - -## Kubernetes Driver - -Kubernetes-backed sandboxes run as pods in the configured sandbox namespace. Use Kubernetes for shared clusters, remote compute, GPU scheduling, and operator-managed environments. - - -The cluster CNI MUST enforce ingress and egress `NetworkPolicy` in every sandbox -namespace. OpenShell creates the workload policy, but the Kubernetes API cannot -confirm enforcement. Without it, workload pods may connect directly and bypass -supervisor network policy. - -Kubernetes workspace namespaces are an administrative trust boundary. In -shared and managed modes, only the OpenShell gateway and its trusted Agent -Sandbox controller may administer Sandbox CRs, sandbox pods, or the configured -sandbox ServiceAccount in those namespaces. In operator mode, allowlist only -namespaces where the platform operator preserves that exclusive control. -Untrusted principals must not be able to create sandbox pods with fabricated -owner references or use the sandbox ServiceAccount. The operator namespace -allowlist is a trust grant, not a tenant isolation mechanism. - - -Helm deployments set Kubernetes driver values through the chart. - -For maintainer-level implementation details, refer to the [Kubernetes driver README](https://github.com/NVIDIA/OpenShell/blob/main/crates/openshell-driver-kubernetes/README.md). - -| Gateway configuration | Helm value | Description | -|---|---|---| -| `compute_driver = "kubernetes"` | Not applicable | Select the Kubernetes compute driver. | -| `[openshell.drivers.kubernetes].namespace` | `server.sandboxNamespace` | Set the namespace for sandbox resources. The Helm chart defaults to the release namespace when left empty. | -| `service_account_name` | `sandboxServiceAccount.name` | Set the Kubernetes service account assigned to sandbox pods and accepted by the Kubernetes driver's TokenReview bootstrap path. The Helm chart creates a dedicated sandbox service account by default. | -| `default_image` | `sandbox.image.repository` / `sandbox.image.tag` / `sandbox.image.digest` | Set the default sandbox image. | -| `image_pull_policy` | `sandbox.image.pullPolicy` | Set the canonical sandbox pull policy: `always`, `if_not_present`, or `never`. `newer` is Podman-only. | -| `image_pull_secrets` | `server.sandboxImagePullSecrets` | Attach Kubernetes image-pull Secrets to sandbox pods. Managed mode creates an immutable copy of each Secret from the configured source namespace for every sandbox runtime generation. In shared and operator modes, the Secrets must already exist in the sandbox namespace. | -| `[managed_ssh_ingress]` | `networkPolicy.enabled` | In managed mode, create an SSH ingress policy in every workspace namespace. Helm configures the gateway namespace and pod selector automatically. Operator mode leaves namespace policy management to the platform operator. | -| `grpc_endpoint` | `server.grpcEndpoint` | Set the gateway endpoint reachable from sandbox pods. | -| `client_tls_secret_name` | `server.tls.clientTlsSecretName` | Name the Kubernetes Secret holding sandbox client TLS materials. Shared mode mounts it directly; managed and operator modes stage its contents into each supervisor bootstrap Secret. | -| `sandbox_runtime_image` | `sandboxRuntime.image.registry` / `sandboxRuntime.image.repository` / `sandboxRuntime.image.tag` / `sandboxRuntime.image.digest` | Override the trusted workload-side image that provides `openshell-sandbox`. Individual image values take precedence over `global.image`; a digest takes precedence over the tag. | -| `sandbox_runtime_image_pull_policy` | `sandboxRuntime.image.pullPolicy` | Set the Kubernetes image pull policy for the sandbox runtime image. | -| `supervisor_image` | `supervisor.image.registry` / `supervisor.image.repository` / `supervisor.image.tag` / `supervisor.image.digest` | Override the image that provides `openshell-supervisor`. Individual image values take precedence over `global.image`; a digest takes precedence over the tag. | -| `supervisor_image_pull_policy` | `supervisor.image.pullPolicy` | Set the canonical supervisor pull policy: `always`, `if_not_present`, or `never`. `newer` is Podman-only. | -| `sandbox_runtime.boundary_port` | `supervisor.sandboxRuntime.boundaryPort` | Set the non-privileged TLS port used between the paired supervisor and sandbox Pods. | -| `https_proxy` | `upstreamProxy.url` | Set the operator-owned `http://host:port` or `https://host:port` corporate forward proxy used for policy-approved TLS CONNECT egress. | -| `no_proxy` | `upstreamProxy.noProxy` | Set destinations that bypass only the corporate proxy. OpenShell policy evaluation still applies. | -| `proxy_auth_secret_name` | `upstreamProxy.authSecret.name` | Set the existing Secret name in the sandbox namespace that contains the proxy credential. The Secret mounts only in the supervisor Pod. | -| `proxy_auth_secret_key` | `upstreamProxy.authSecret.key` | Set the Secret key containing the `user:pass` credential. | -| `proxy_auth_allow_insecure` | `upstreamProxy.authAllowInsecure` | Set `true` to acknowledge that Basic authentication to an HTTP proxy is cleartext. Required with a proxy credential Secret and an `http://` proxy; an `https://` proxy carries the credential inside the verified TLS session and needs no acknowledgement. | -| `proxy_connect_by_hostname` | `upstreamProxy.connectByHostname` | Send hostnames rather than validated IPs in CONNECT requests. Use only when proxy ACLs require hostname targets. | -| `proxy_ca_bundle` | `upstreamProxy.caBundle.configMapName` / `upstreamProxy.caBundle.key` | Trust a PEM CA bundle for the corporate proxy. Required for an `https://` proxy with a private CA, and for a TLS-intercepting proxy that re-signs upstream certificates. Helm mounts the ConfigMap into the gateway Pod; the gateway stages the bundle into each sandbox's immutable supervisor bootstrap Secret. | -| `workspace_default_storage_size` | `server.workspaceDefaultStorageSize` | Set the default workspace PVC size for new sandboxes. | -| `workspace_storage_class` | `server.workspaceStorageClass` | Set the `StorageClass` for the workspace PVC. Empty (default) omits `storageClassName` and uses the cluster's default `StorageClass`. Set this on clusters with no default `StorageClass`, otherwise the workspace PVC stays `Pending` and the sandbox never starts. | -| `sa_token_ttl_secs` | `server.sandboxJwt.k8sSaTokenTtlSecs` | Set the projected ServiceAccount token TTL used for the bootstrap token exchange. | - -`proxy_ca_bundle` needs only the CA that signs the proxy's certificate, or that -a TLS-intercepting proxy re-signs upstream certificates with. Public roots -already come from the supervisor image and its TLS stack, so supplying a full -merged trust bundle adds hundreds of kilobytes of duplicated roots for no -benefit. - -On OpenShift, copy the cluster proxy's trusted-CA ConfigMap into the gateway's -release namespace rather than pointing at an injected trusted-CA bundle. A copy -is required in any case, because ConfigMaps cannot be referenced across -namespaces: - -```shell -CORP_CA=$(oc get proxy/cluster -o jsonpath='{.spec.trustedCA.name}') -oc -n openshift-config get cm "$CORP_CA" -o jsonpath='{.data.ca-bundle\.crt}' > corp-ca.pem -oc -n openshell create configmap corporate-proxy-ca --from-file=ca.crt=corp-ca.pem -``` - -Then set `upstreamProxy.caBundle.configMapName` to `corporate-proxy-ca` and -leave `upstreamProxy.caBundle.key` at its `ca.crt` default. - -Managed-mode sandbox runtime generations require the gateway ServiceAccount to -create and delete Secrets in workspace namespaces. Kubernetes RBAC cannot -restrict Secret `create` by resource name, so the Helm chart grants cluster-wide -Secret `create` and `delete`. Secret `get` is limited to the configured TLS and -image-pull source Secrets in the sandbox namespace. Do not reuse the gateway -ServiceAccount for unrelated workloads. - -The Kubernetes driver always places the sandbox runtime in the workload Pod and -the supervisor in a separate, directly managed Pod. The -workload Pod runs `openshell-sandbox` as the same non-root UID/GID as the agent -and requests no added Linux capabilities. The supervisor Pod runs -`openshell-supervisor`, authenticates to the gateway with a sandbox JWT, and -owns upstream connections. Both containers disable privilege escalation, drop -all capabilities, and use `RuntimeDefault` seccomp. The sandbox adds a nested -seccomp user-notification filter and Landlock restrictions before it launches -the agent. One namespace-wide, empty-egress `NetworkPolicy` is the mandatory -outer fence for all OpenShell workload Pods. It permits supervisor Pods to -reach sandbox listeners; TLS and JWT identity enforce the exact pairing. - -The Kubernetes driver creates namespaced `agents.x-k8s.io` `Sandbox` resources from the Kubernetes SIG Apps [agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox) project. It detects the served Sandbox API at runtime, caches the selected API version for the gateway process, and uses `v1beta1` when available before falling back to `v1alpha1`, so supported Agent Sandbox installations work without version-specific operator configuration. The Agent Sandbox controller turns those resources into sandbox pods and related storage. - -Stop patches the existing resource rather than deleting it. For `v1beta1`, -the driver sets `spec.operatingMode` to `Suspended` or `Running`. For -`v1alpha1`, it sets `spec.replicas` to `0` or `1`. The Sandbox resource and its -workspace PVC keep their identity across both operations. Stop returns only -after the controller reports suspension and deletes the old pod, so an -immediate start cannot race the prior pod's termination. - -If Agent Sandbox is upgraded in place, restart the OpenShell gateway after the controller and CRD rollout completes so the gateway can detect the served API versions again. - - -`Sandbox.spec.volumeClaimTemplates` is immutable after creation. To change storage configuration, delete the sandbox and create a new one with the updated spec. - - -### Kubernetes Driver Config PVC Mounts - -Kubernetes driver config can mount existing PersistentVolumeClaims into the -agent container. Use this when storage is provisioned outside OpenShell and a -sandbox should mount selected PVC subpaths instead of using the default -OpenShell-created `/sandbox` workspace PVC. - -```shell -openshell sandbox create \ - --from registry.example.com/team/claude-code:1.0 \ - --driver-config-json '{ - "kubernetes": { - "volumes": [{ - "name": "user-data", - "persistent_volume_claim": { - "claim_name": "pvc-user-data-123", - "read_only": false - } - }], - "containers": { - "agent": { - "volume_mounts": [ - { - "name": "user-data", - "mount_path": "/sandbox/.openshell/workspace", - "sub_path": "workspace", - "read_only": false - }, - { - "name": "user-data", - "mount_path": "/sandbox/.openshell/memory", - "sub_path": "memory", - "read_only": false - } - ] - } - } - } - }' \ - -- claude -``` - -Kubernetes PVC mount schema: - -| Field | Description | -|---|---| -| `volumes[].name` | Pod volume name. It must be a DNS-1123 label, unique, and not use OpenShell-managed volume names. | -| `volumes[].persistent_volume_claim.claim_name` | Existing PVC name in the sandbox namespace. It must be a DNS-1123 subdomain name. | -| `volumes[].persistent_volume_claim.read_only` | Optional. Defaults to `true`. Set `false` to allow read-write mounts. | -| `containers.agent.volume_mounts[].name` | References a volume declared in `volumes`. | -| `containers.agent.volume_mounts[].mount_path` | Absolute, normalized container path for the agent mount. | -| `containers.agent.volume_mounts[].sub_path` | Optional relative PVC subpath. Absolute paths and `..` are rejected. | -| `containers.agent.volume_mounts[].read_only` | Optional. Defaults to `true`. It cannot be `false` when the PVC volume is read-only. | - -OpenShell rejects duplicate volume names, mounts that reference unknown volumes, -protected mount targets, and mounts that replace OpenShell TLS, supervisor, -ServiceAccount token, or SPIFFE paths. Read-write PVC access requires -`read_only: false` on both the PVC volume and each writable mount. - -Any driver-config mount under `/sandbox` disables the default `/sandbox` -workspace PVC injection for that sandbox. Only the explicit mount paths persist -through the external PVC; other `/sandbox` paths come from the current sandbox -image. - -## Sandbox User Identity - -The policy can set `process.run_as_user` and `process.run_as_group` -independently. Each explicit field wins. The active compute driver supplies the -identity for omitted fields. - -Explicit numeric values may use any non-root Linux UID/GID from `1` through -`4294967294`. OpenShell rejects `0` as root and `4294967295` as the invalid -identity sentinel. Low numeric identities can inherit permissions from matching -accounts, files, volumes, or devices, so choose them with the same care as any -other runtime identity. - -### Docker / Podman - -Docker and Podman inspect the final image and use its OCI `USER` declaration as -a per-field fallback. Supported forms include `app`, `app:staff`, a numeric UID -whose passwd entry supplies its primary GID, and an accountless numeric pair -such as `1234:1235`. - -The driver pins container creation to the immutable image ID it inspected. The -supervisor validates any required names inside that image and preserves the -declared name or numeric components for both direct and SSH children. When -`USER` omits the group, the supervisor uses the user's numeric primary GID. It -does not modify `/etc/passwd` or `/etc/group`. - -Docker also inspects OCI `WorkingDir`. An absolute value becomes the -agent workspace; an empty, root (`/`), or explicit `/sandbox` value uses the -managed `/sandbox` compatibility workspace. -OpenShell creates and owns that compatibility workspace. Any other workdir must -already exist in the immutable image without symlink components. The completed -UID/GID and supplementary groups must already be able to traverse every parent -and write and enter the workdir. OpenShell does not change that directory's -ownership or mode. A one-shot validator drops to that identity and uses kernel -effective-access checks, including POSIX ACL grants and LSM denials. It rejects -workdirs that overlap the OCI runtime namespaces under `/proc`, `/sys`, or -`/dev`, and rejects overlap with actual OpenShell control paths. Docker checks -the original image filesystem in the final supervisor and rejects image -`VOLUME` declarations that would mask the workdir or one of its parents before -validation. The resolved workspace is the cwd and `HOME` for direct and SSH -children. The supervisor itself starts from `/`, so a missing or invalid -workspace is handled during readiness instead of preventing the container -runtime from starting it. - -Sandbox creation fails before readiness if a required `USER` component is -missing, malformed, unknown, ambiguous, or resolves to UID/GID 0. An image -without `USER` therefore works only when policy explicitly provides both -identity fields. - -### Kubernetes / OpenShift - -The Kubernetes driver auto-detects the sandbox UID from OpenShift SCC namespace annotations: - -- `openshift.io/sa.scc.uid-range` (format: `/`, e.g. `1000000000/10000`) provides the UID. -- `openshift.io/sa.scc.supplemental-groups` provides the GID when present; otherwise the resolved UID is used as the GID. -- On non-OpenShift clusters, or when annotations are absent, the driver falls back to `1000`. - -You can override autodetection with explicit `sandbox_uid` / `sandbox_gid` config in `[openshell.drivers.kubernetes]`. When set, the driver skips namespace annotation lookup entirely. - -The resolved UID/GID appear in: - -- Supervisor container environment variables (`OPENSHELL_SANDBOX_UID`, `OPENSHELL_SANDBOX_GID`) for direct kernel-level privilege dropping without `/etc/passwd` lookups. -- PVC init container `securityContext.runAsUser/runAsGroup/fsGroup` for workspace ownership operations. - -### VM Driver - -The VM driver injects the sandbox UID into the rootfs guest's `/etc/passwd`, `/etc/group`, and `/etc/gshadow` during rootfs preparation. Default UID is `10001`; configure `sandbox_uid` in `[openshell.drivers.vm]` to use a different value. - -### Custom Images - -Docker and Podman custom images do not need a baked-in `"sandbox"` user. Declare -a non-root OCI `USER`, or set both process identity fields explicitly in policy. -Named image users require matching account entries; a numeric `UID:GID` pair -does not. For Docker, declare an absolute OCI `WORKDIR` to select the workspace. -Images with no working directory, `WORKDIR /`, or `WORKDIR /sandbox` use -OpenShell's managed `/sandbox` compatibility workspace. For any other Docker -path, create the directory in the image and grant the final process identity -write and execute permission in the Dockerfile. Podman, Kubernetes/OpenShift, -and VM sandboxes continue to use `/sandbox`. diff --git a/docs/reference/api-errors.mdx b/docs/sdk/api-errors.mdx similarity index 100% rename from docs/reference/api-errors.mdx rename to docs/sdk/api-errors.mdx diff --git a/docs/sdk/go.mdx b/docs/sdk/go.mdx index 478280934d..86a011e00d 100644 --- a/docs/sdk/go.mdx +++ b/docs/sdk/go.mdx @@ -121,6 +121,6 @@ return lazy pagers so callers choose when to fetch the next page. ## Next Steps -- Review [Gateway Authentication](/reference/gateway-auth) before connecting a service to a production gateway. -- Review [API Errors](/reference/api-errors) for the gateway error model. +- Review [Gateway Authentication](/how-it-works/gateways/authentication) before connecting a service to a production gateway. +- Review [API Errors](/sdk/api-errors) for the gateway error model. - Browse the [Go package reference](https://pkg.go.dev/github.com/NVIDIA/OpenShell/sdk/go/openshell/v1) for all exported types and methods. diff --git a/docs/reference/protobuf-time-types.mdx b/docs/sdk/protobuf-time-types.mdx similarity index 100% rename from docs/reference/protobuf-time-types.mdx rename to docs/sdk/protobuf-time-types.mdx diff --git a/docs/sdk/python.mdx b/docs/sdk/python.mdx index c03478cdd5..afd1a9d399 100644 --- a/docs/sdk/python.mdx +++ b/docs/sdk/python.mdx @@ -109,6 +109,6 @@ complete collection. ## Next Steps -- Review [Manage Sandboxes](/sandboxes/manage-sandboxes) for labels, templates, services, and Python SDK examples. -- Review [Gateway Authentication](/reference/gateway-auth) for OIDC and client credentials. -- Review [API Errors](/reference/api-errors) for structured error handling. +- Review [Manage Sandboxes](/how-it-works/sandboxes/overview) for labels, templates, services, and Python SDK examples. +- Review [Gateway Authentication](/how-it-works/gateways/authentication) for OIDC and client credentials. +- Review [API Errors](/sdk/api-errors) for structured error handling. diff --git a/docs/sdk/rust.mdx b/docs/sdk/rust.mdx index 20e938a84c..f16650ffd0 100644 --- a/docs/sdk/rust.mdx +++ b/docs/sdk/rust.mdx @@ -124,6 +124,6 @@ requests. ## Next Steps -- Review [Gateway Authentication](/reference/gateway-auth) for transport and identity choices. -- Review [API Errors](/reference/api-errors) for the gateway error model. +- Review [Gateway Authentication](/how-it-works/gateways/authentication) for transport and identity choices. +- Review [API Errors](/sdk/api-errors) for the gateway error model. - See the [Rust SDK source documentation](https://github.com/NVIDIA/OpenShell/tree/main/crates/openshell-sdk) for modules and advanced transport behavior. diff --git a/docs/sdk/typescript.mdx b/docs/sdk/typescript.mdx index f9ac855480..96a093fb3f 100644 --- a/docs/sdk/typescript.mdx +++ b/docs/sdk/typescript.mdx @@ -105,6 +105,6 @@ return protobuf wire shapes, while curated calls return SDK-specific types. ## Next Steps -- Review [Gateway Authentication](/reference/gateway-auth) for OIDC and service authentication. -- Review [API Errors](/reference/api-errors) for structured error handling. +- Review [Gateway Authentication](/how-it-works/gateways/authentication) for OIDC and service authentication. +- Review [API Errors](/sdk/api-errors) for structured error handling. - See the [TypeScript SDK source documentation](https://github.com/NVIDIA/OpenShell/tree/main/sdk/typescript) for streaming, forwarding, and raw client examples. diff --git a/docs/security/best-practices.mdx b/docs/security/best-practices.mdx index 40a1e18639..20335c7c8b 100644 --- a/docs/security/best-practices.mdx +++ b/docs/security/best-practices.mdx @@ -12,8 +12,8 @@ position: 1 OpenShell enforces sandbox security across four layers: network, filesystem, process, and provider credentials. This page documents every configurable control, its default, what it protects, and the risk of relaxing it. -For the full policy YAML schema, refer to the [Policy Schema](/reference/policy-schema). -For the architecture of each enforcement layer, refer to [Architecture](/about/how-it-works). +For the full policy YAML schema, refer to the [Policy Schema](/how-it-works/policies/schema). +For the architecture of each enforcement layer, refer to [Architecture](/about/architecture). If you use [NemoClaw](https://github.com/NVIDIA/NemoClaw), its [Security Best Practices](https://docs.nvidia.com/nemoclaw/latest/security/best-practices.html) guide covers additional entrypoint-level controls, policy presets, provider trust tiers, and posture profiles specific to the NemoClaw blueprint. @@ -296,9 +296,9 @@ The following patterns weaken security without providing meaningful benefit. ## Related Topics -- [Policies](/sandboxes/policies) for applying and iterating on sandbox policies. -- [Policy Schema](/reference/policy-schema) for the full field-by-field YAML reference. -- [Default Policy](/reference/default-policy) for the built-in default policy breakdown. -- [Gateway Auth](/reference/gateway-auth) for gateway authentication details. -- [Architecture](/about/how-it-works) for the system architecture. +- [Policies](/how-it-works/policies/overview) for applying and iterating on sandbox policies. +- [Policy Schema](/how-it-works/policies/schema) for the full field-by-field YAML reference. +- [Default Policy](/how-it-works/policies/default-policy) for the built-in default policy breakdown. +- [Gateway Auth](/how-it-works/gateways/authentication) for gateway authentication details. +- [Architecture](/about/architecture) for the system architecture. - NemoClaw [Security Best Practices](https://docs.nvidia.com/nemoclaw/latest/security/best-practices.html) for entrypoint-level controls (capability drops, PATH hardening, build toolchain removal), policy presets, provider trust tiers, and posture profiles. diff --git a/docs/get-started/tutorials/first-network-policy.mdx b/docs/tutorials/first-network-policy.mdx similarity index 97% rename from docs/get-started/tutorials/first-network-policy.mdx rename to docs/tutorials/first-network-policy.mdx index 1a5cf67786..bed3335666 100644 --- a/docs/get-started/tutorials/first-network-policy.mdx +++ b/docs/tutorials/first-network-policy.mdx @@ -3,7 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 title: "Write Your First Sandbox Network Policy" sidebar-title: "First Network Policy" -slug: "get-started/tutorials/first-network-policy" description: "Learn how OpenShell network policies work by creating a sandbox, observing default-deny in action, and applying a fine-grained L7 read-only rule." keywords: "Generative AI, Cybersecurity, Tutorial, Policy, Network Policy, Sandbox, Security" --- @@ -133,8 +132,8 @@ openshell policy set demo --policy github_readonly.yaml --wait This tutorial uses `curl` and `read-only` access to keep things simple. When building policies for real workloads: - To scope the policy to an agent, replace the `binaries` section with your agent's binary, such as `/usr/local/bin/claude`, instead of `curl`. -- To grant write access, change `access: read-only` to `read-write` or add explicit `rules` for specific paths. Refer to the [Policy Schema](/reference/policy-schema). -- To allow additional endpoints, stack multiple policies in the same file for PyPI, npm, or your internal APIs. Refer to [Policies](/sandboxes/policies) for examples. +- To grant write access, change `access: read-only` to `read-write` or add explicit `rules` for specific paths. Refer to the [Policy Schema](/how-it-works/policies/schema). +- To allow additional endpoints, stack multiple policies in the same file for PyPI, npm, or your internal APIs. Refer to [Policies](/how-it-works/policies/overview) for examples. @@ -208,4 +207,4 @@ bash examples/sandbox-policy-quickstart/demo.sh ## Next Steps -- To walk through a full policy iteration with Claude Code, including diagnosing denials and applying fixes from outside the sandbox, refer to [GitHub Sandbox](/get-started/tutorials/github-sandbox). +- To walk through a full policy iteration with Claude Code, including diagnosing denials and applying fixes from outside the sandbox, refer to [GitHub Sandbox](/tutorials/github-push-access). diff --git a/docs/get-started/tutorials/github-sandbox.mdx b/docs/tutorials/github-sandbox.mdx similarity index 85% rename from docs/get-started/tutorials/github-sandbox.mdx rename to docs/tutorials/github-sandbox.mdx index 2e52826e77..afacbfb3de 100644 --- a/docs/get-started/tutorials/github-sandbox.mdx +++ b/docs/tutorials/github-sandbox.mdx @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 title: "Grant GitHub Push Access to a Sandboxed Agent" sidebar-title: "GitHub Push Access" -slug: "get-started/tutorials/github-sandbox" +slug: "tutorials/github-push-access" description: "Launch an agent with a GitHub provider, diagnose a denied push, and grant repository-scoped write access." keywords: "Generative AI, Cybersecurity, Tutorial, GitHub, Sandbox, Policy, Claude Code" --- @@ -12,7 +12,7 @@ This tutorial shows how provider access and sandbox policy work together. You attach a GitHub provider that contributes read-only GitHub access, observe a denied push, and add a user policy that permits writes to one repository. -The built-in [default policy](/reference/default-policy) does not grant network +The built-in [default policy](/how-it-works/policies/default-policy) does not grant network access. Imported provider profiles contribute the endpoints and executable paths needed by their providers. @@ -34,14 +34,15 @@ and updates policy. ## Import the Provider Profiles -Download and review the Claude Code and GitHub profiles. Confirm that their -`binaries` paths match the executables in your image, then import them: +Review the [Claude Code profile](https://github.com/NVIDIA/OpenShell/blob/main/providers/claude-code.yaml) +and [GitHub profile](https://github.com/NVIDIA/OpenShell/blob/main/providers/github.yaml). +Confirm that their `binaries` paths match the executables in your image, then +import them directly. If a path or endpoint grant needs to change, edit a local +copy and import it with `-f` instead. ```shell -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml -curl -LsSfO https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/github.yaml -openshell profile import -f claude-code.yaml --global -openshell profile import -f github.yaml --global +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/claude-code.yaml --global +openshell profile import --url https://raw.githubusercontent.com/NVIDIA/OpenShell/main/providers/github.yaml --global ``` The gateway contains no built-in profiles. Import each profile once per gateway @@ -218,6 +219,6 @@ openshell sandbox delete github-demo ## Next Steps -- Review [Profiles](/providers/profiles) for endpoint-scoped credential placement. -- Review [Policies](/sandboxes/policies) for incremental policy updates and policy history. -- Review the [Policy Schema](/reference/policy-schema) for REST, GraphQL, and other protocol rules. +- Review [Profiles](/how-it-works/providers/profiles) for endpoint-scoped credential placement. +- Review [Policies](/how-it-works/policies/overview) for incremental policy updates and policy history. +- Review the [Policy Schema](/how-it-works/policies/schema) for REST, GraphQL, and other protocol rules. diff --git a/docs/get-started/tutorials/index.mdx b/docs/tutorials/index.mdx similarity index 70% rename from docs/get-started/tutorials/index.mdx rename to docs/tutorials/index.mdx index 8d13198d99..1beee6d434 100644 --- a/docs/get-started/tutorials/index.mdx +++ b/docs/tutorials/index.mdx @@ -2,7 +2,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 title: "Tutorials" -slug: "get-started/tutorials" description: "Step-by-step walkthroughs for OpenShell, from first sandbox to production-ready policies." keywords: "Generative AI, Cybersecurity, Tutorial, Sandbox, Policy" position: 1 @@ -12,17 +11,22 @@ Hands-on walkthroughs that teach OpenShell concepts by building real configurati - + + +Build a Pi coding-agent image, configure Anthropic access, and run it inside an OpenShell sandbox. + + + Create a sandbox, observe default-deny networking, apply a read-only L7 policy, and inspect audit logs. No AI agent required. - + Launch Claude Code in a sandbox, diagnose a policy denial, and iterate on a custom GitHub policy from outside the sandbox. - + Configure a Microsoft Graph provider profile with gateway-managed OAuth2 refresh-token rotation. diff --git a/docs/get-started/tutorials/microsoft-graph-provider-refresh.mdx b/docs/tutorials/microsoft-graph-provider-refresh.mdx similarity index 99% rename from docs/get-started/tutorials/microsoft-graph-provider-refresh.mdx rename to docs/tutorials/microsoft-graph-provider-refresh.mdx index 301678d91f..4c74ac3276 100644 --- a/docs/get-started/tutorials/microsoft-graph-provider-refresh.mdx +++ b/docs/tutorials/microsoft-graph-provider-refresh.mdx @@ -3,7 +3,6 @@ # SPDX-License-Identifier: Apache-2.0 title: "Refresh Microsoft Graph Credentials with a Provider Profile" sidebar-title: "Microsoft Graph Provider Refresh" -slug: "get-started/tutorials/microsoft-graph-provider-refresh" description: "Configure a Microsoft Graph provider profile with gateway-managed OAuth2 refresh-token rotation." keywords: "Generative AI, Cybersecurity, Tutorial, Providers, Microsoft Graph, OAuth2, Credential Refresh, Sandbox" --- diff --git a/docs/tutorials/run-pi.mdx b/docs/tutorials/run-pi.mdx new file mode 100644 index 0000000000..141db5571f --- /dev/null +++ b/docs/tutorials/run-pi.mdx @@ -0,0 +1,168 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Run Pi in OpenShell" +sidebar-title: "Run Pi" +description: "Build a Pi coding-agent image, configure Anthropic access, and run Pi inside an OpenShell sandbox." +keywords: "Generative AI, Cybersecurity, Tutorial, Pi Coding Agent, Anthropic, Sandbox, Provider Profile" +--- + + +This tutorial runs [Pi](https://pi.dev), a terminal coding agent, with the +Anthropic API. You will build Pi into an OCI image, configure narrowly scoped +model access, and run it inside OpenShell. + +## Build the Pi Image + +Pi does not publish an official OCI image. Its +[container guide](https://pi.dev/docs/latest/containerization) installs the +maintained `@earendil-works/pi-coding-agent` npm package into a Node.js image. +Create `Dockerfile.pi` with the same approach: + +```dockerfile +FROM node:24-bookworm-slim + +ARG PI_VERSION=latest + +RUN apt-get update \ + && apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \ + && rm -rf /var/lib/apt/lists/* + +RUN npm install -g --ignore-scripts "@earendil-works/pi-coding-agent@${PI_VERSION}" + +RUN mkdir -p /workspace && chown node:node /workspace +USER node +WORKDIR /workspace + +ENV PI_CODING_AGENT_DIR=/tmp/pi-agent +``` + +Build the image with the container engine used by your local gateway: + +```shell +docker build -t pi-agent:local -f Dockerfile.pi . +``` + +For Podman, use `podman build -t localhost/pi-agent:local -f Dockerfile.pi .` +and substitute `localhost/pi-agent:local` in the commands below. For a remote +gateway, push the image to a registry the gateway can pull from. Pin +`PI_VERSION` to a reviewed release when you publish a reproducible image. + +## Configure Anthropic Access + +Create `pi-anthropic.yaml`. The profile permits only the Pi executable from +this image to reach the Anthropic API. OpenShell supplies a credential +placeholder to Pi and replaces it only on requests to the declared endpoint. + +```yaml +id: pi-anthropic +display_name: Pi with Anthropic +description: Anthropic model access for the Pi coding agent +category: agent +inference_capable: true +credentials: + - name: api_key + description: Anthropic API key used by Pi + env_vars: [ANTHROPIC_API_KEY] + required: true + auth_style: header + header_name: x-api-key +discovery: + credentials: [api_key] +endpoints: + - host: api.anthropic.com + port: 443 + protocol: rest + access: read-write + enforcement: enforce +binaries: + - /usr/local/bin/pi + - /usr/local/lib/node_modules/@earendil-works/pi-coding-agent/** +``` + +Lint and import the profile into your current workspace, then store an +Anthropic API key in a provider: + +```shell +openshell provider profile lint -f pi-anthropic.yaml +openshell provider profile import -f pi-anthropic.yaml + +ANTHROPIC_API_KEY=your-key \ + openshell provider create \ + --name pi-anthropic \ + --type pi-anthropic \ + --from-existing +``` + +## Create the Pi Sandbox + +Create the sandbox, attach the provider, and run Pi interactively: + +```shell +openshell sandbox create \ + --name pi \ + --from pi-agent:local \ + --provider pi-anthropic \ + -- pi +``` + +The command after `--` is the sandbox's main process. Pi and every command it +starts run inside the sandbox boundary. Try asking Pi: + +```text +Explain what files are available in this workspace. +``` + +To give Pi a local project, upload it before the main process starts: + +```shell +openshell sandbox create \ + --name pi-project \ + --from pi-agent:local \ + --provider pi-anthropic \ + --upload .:/workspace \ + -- pi +``` + +The provider grants Pi access to `api.anthropic.com`. The built-in fallback +policy grants access to the working directory and standard runtime paths while +denying all other network egress. Add a reviewed custom policy when Pi needs +package registries, source hosts, tool servers, or other destinations. + +## Adapt the Pi Workflow + +Pi supports multiple model providers. Create or adapt a provider profile for +the service you use, and make its `binaries` paths match the Pi installation in +your image. The OpenShell repository contains reviewable profile examples in +[`providers/`](https://github.com/NVIDIA/OpenShell/tree/main/providers). + +Install any additional compilers, package managers, and agent tools in the +image. Grant their filesystem and network requirements through +[sandbox policy](/how-it-works/policies/overview) instead of giving the workload broad +access. Refer to [Profiles](/how-it-works/providers/profiles) for credential and endpoint +configuration. + +## Verify and Troubleshoot + +Inspect the sandbox, effective policy, provider attachments, and logs: + +```shell +openshell sandbox list +openshell policy get pi --full +openshell sandbox provider list pi +openshell logs pi --tail +``` + +If `pi` is missing, confirm that the image was built with the selected local +container engine or pushed to a registry visible to the gateway. If a model +request is denied, confirm that the profile's `binaries` paths match +`command -v pi` and `npm root -g` inside the image. Review any other denied +network or filesystem operation before updating the sandbox policy. + +## Next Steps + +- To give Pi access to source control, package registries, or tool servers, add + the corresponding provider profiles or a reviewed [sandbox policy](/how-it-works/policies/overview). +- To understand image, resource, upload, and lifecycle options, refer to + [Sandboxes](/how-it-works/sandboxes/overview). +- To configure another model service, refer to [Profiles](/how-it-works/providers/profiles). diff --git a/docs/upgrade/0-1-0.mdx b/docs/upgrade/0-1-0.mdx index f91322e3cd..7801b48179 100644 --- a/docs/upgrade/0-1-0.mdx +++ b/docs/upgrade/0-1-0.mdx @@ -7,9 +7,16 @@ description: "Prepare OpenShell operators and users for the breaking changes in keywords: "Generative AI, Cybersecurity, AI Agents, Sandboxing, Upgrade, Migration" --- -Upgrading from OpenShell 0.0.x to 0.1.0? Start with the section that matches how you use the platform. + +Local OpenShell 0.0.x installations cannot be upgraded in place. Clean up the +old runtime and [uninstall the existing package](/about/installation#uninstall-openshell) +before installing OpenShell 0.1.0. + -Each item links to the pull request that defines the change. +OpenShell 0.1.0 introduces breaking changes for deployments, sandboxes, policies, APIs, and SDKs. Review the changes that apply to your role before upgrading: + +- [Operators](#operators): Plan the rollout, migrate configuration and credentials, and update custom extensions. +- [End users](#end-users): Update sandbox workflows, policies, API clients, and SDK integrations. ## Operators @@ -26,7 +33,7 @@ If you run OpenShell for a team, start here. openshell profile import --from ./profiles --global ``` -- **Migrate `gateway.toml` to schema version 2.** Add the version, replace the plural compute-driver selector, move driver settings under `[openshell.drivers.]`, and apply the renamed Docker, Podman, and VM fields. Validate the file before restarting. See [Gateway Configuration](/reference/gateway-config#migrate-to-schema-version-2) for the complete field mapping and [PR #2814](https://github.com/NVIDIA/OpenShell/pull/2814) for the implementation. +- **Migrate `gateway.toml` to schema version 2.** Add the version, replace the plural compute-driver selector, move driver settings under `[openshell.drivers.]`, and apply the renamed Docker, Podman, and VM fields. Validate the file before restarting. See [Gateway Configuration](/how-it-works/gateways/configuration#migrate-to-schema-version-2) for the complete field mapping and [PR #2814](https://github.com/NVIDIA/OpenShell/pull/2814) for the implementation. ```toml [openshell] @@ -61,7 +68,7 @@ If you run OpenShell for a team, start here. - **Install the workspace chart in operator-managed namespaces.** In operator workspace mode, the gateway receives Secret permissions only from the `openshell-workspace` chart. Install the matching chart release in every operator-managed namespace; without it, sandbox bootstrap fails ([PR #3616](https://github.com/NVIDIA/OpenShell/pull/3616)). -- **Implement extension protocol negotiation.** Custom compute drivers, credential drivers, gateway interceptors, and middleware must exchange `PeerMetadata`, use protocol `1.0`, and advertise their family base capability. Upgrade both peers together. See [Extension Protocol Negotiation](/extensibility/extension-negotiation) and [PR #3352](https://github.com/NVIDIA/OpenShell/pull/3352). +- **Implement extension protocol negotiation.** Custom compute drivers, credential drivers, gateway interceptors, and middleware must exchange `PeerMetadata`, use protocol `1.0`, and advertise their family base capability. Upgrade both peers together. See [Extension Protocol Negotiation](/extensibility/overview#protocol-negotiation) and [PR #3352](https://github.com/NVIDIA/OpenShell/pull/3352). - **Remove compute-driver callback-listener negotiation.** Regenerate custom compute-driver bindings and connect supervisors to the operator-configured primary gateway endpoint ([PR #3365](https://github.com/NVIDIA/OpenShell/pull/3365)). @@ -85,7 +92,7 @@ If you use OpenShell through the CLI, policies, APIs, or SDKs, review these chan - **Name providers explicitly.** A trailing sandbox command no longer infers or attaches a provider. Pass `--provider `, and ask the operator to import the referenced profile when it is missing ([PR #3383](https://github.com/NVIDIA/OpenShell/pull/3383)). -- **Replace managed inference routes.** The `openshell inference` commands, route APIs, and `inference.local` endpoint are removed. Attach a provider to each sandbox and call its native endpoint with its native model and request format. See [Migrate from Managed Inference Routes](/sandboxes/inference-routing#migrate-from-managed-inference-routes) and [PR #3195](https://github.com/NVIDIA/OpenShell/pull/3195). +- **Replace managed inference routes.** The `openshell inference` commands, route APIs, and `inference.local` endpoint are removed. Attach a provider to each sandbox and call its native endpoint with its native model and request format. See [Migrate from Managed Inference Routes](/how-it-works/inference#migrate-from-managed-inference-routes) and [PR #3195](https://github.com/NVIDIA/OpenShell/pull/3195). - **Remove `NetworkBinary.harness`.** In authored policies, keep each binary as an object containing only `path`, such as `- path: /usr/bin/curl`. In provider profiles, write binaries as scalar paths such as `- /usr/bin/curl` ([PR #3222](https://github.com/NVIDIA/OpenShell/pull/3222)). @@ -97,15 +104,15 @@ If you use OpenShell through the CLI, policies, APIs, or SDKs, review these chan - **Send the negotiated MCP version.** MCP clients must include one `MCP-Protocol-Version` header on each post-initialization request, and the endpoint policy must allow that revision ([PR #3241](https://github.com/NVIDIA/OpenShell/pull/3241)). -- **Select workspaces explicitly.** Regenerate clients for `WorkspaceSelector`, and select the literal `default` workspace when appropriate. Omission no longer selects it. See [Manage Workspaces](/sandboxes/manage-workspaces) and [PR #3245](https://github.com/NVIDIA/OpenShell/pull/3245). +- **Select workspaces explicitly.** Regenerate clients for `WorkspaceSelector`, and select the literal `default` workspace when appropriate. Omission no longer selects it. See [Manage Workspaces](/how-it-works/workspaces) and [PR #3245](https://github.com/NVIDIA/OpenShell/pull/3245). - **Use canonical resource names.** Public sandbox RPCs accept a sandbox name plus its workspace instead of an internal sandbox ID. Update renamed request and JSON fields such as `sandbox`, `provider`, and `name` ([PR #3272](https://github.com/NVIDIA/OpenShell/pull/3272)). -- **Use protobuf time types.** Replace scalar millisecond, second, and string fields with `google.protobuf.Timestamp` and `google.protobuf.Duration`. Preserve the distinction between an absent field and a zero value. See [Protobuf Time Types](/reference/protobuf-time-types) and [PR #3113](https://github.com/NVIDIA/OpenShell/pull/3113). +- **Use protobuf time types.** Replace scalar millisecond, second, and string fields with `google.protobuf.Timestamp` and `google.protobuf.Duration`. Preserve the distinction between an absent field and a zero value. See [Protobuf Time Types](/sdk/protobuf-time-types) and [PR #3113](https://github.com/NVIDIA/OpenShell/pull/3113). - **Replace offset pagination.** Send `page_size` and the opaque `page_token`, then continue while `next_page_token` is non-empty. Curated SDK list methods may return lazy, single-pass pagers; use `list_all` or `ListAll` only when the full collection is required ([PR #3249](https://github.com/NVIDIA/OpenShell/pull/3249), [PR #3256](https://github.com/NVIDIA/OpenShell/pull/3256), [PR #3279](https://github.com/NVIDIA/OpenShell/pull/3279)). -- **Handle typed deletion outcomes.** Replace `deleted`, `removed`, and `revoked` booleans with `DeletionOutcome`. Treat `ACCEPTED` as asynchronous, use the returned sandbox ID when waiting, and set `allow_missing` only when absence is acceptable. See [SDK Migration for Deletion](/reference/api-errors#sdk-migration-for-deletion) and [PR #3317](https://github.com/NVIDIA/OpenShell/pull/3317). +- **Handle typed deletion outcomes.** Replace `deleted`, `removed`, and `revoked` booleans with `DeletionOutcome`. Treat `ACCEPTED` as asynchronous, use the returned sandbox ID when waiting, and set `allow_missing` only when absence is acceptable. See [SDK Migration for Deletion](/sdk/api-errors#sdk-migration-for-deletion) and [PR #3317](https://github.com/NVIDIA/OpenShell/pull/3317). - **Update SDK error handling.** Python clients raise `GatewayError`, which is a `grpc.RpcError` but not a `grpc.Call`. Rust error variants contain additional status fields. SDKs expose retry details but do not automatically retry mutations ([PR #3313](https://github.com/NVIDIA/OpenShell/pull/3313)). diff --git a/fern/docs.yml b/fern/docs.yml index 1be5371527..7fd2f6aa84 100644 --- a/fern/docs.yml +++ b/fern/docs.yml @@ -61,13 +61,25 @@ versions: slug: dev availability: beta announcement: - message: 'New in OpenShell 0.1.0: a stable release cadence, an improved security model, an expanded extension surface, and new APIs. Read the 0.1.0 upgrade guide.' + message: 'New in OpenShell 0.1.0: a stable release cadence, new isolation primitives, an expanded extension surface, and new APIs. Read the 0.1.0 upgrade guide.' redirects: + - source: "/openshell/latest/kubernetes/sandbox-runtime" + destination: "/openshell/latest/kubernetes/setup" + - source: "/openshell/dev/kubernetes/sandbox-runtime" + destination: "/openshell/dev/kubernetes/setup" + - source: "/openshell/latest/about/how-it-works" + destination: "/openshell/latest/about/architecture" + - source: "/openshell/dev/about/how-it-works" + destination: "/openshell/dev/about/architecture" + - source: "/openshell/latest/extensibility/extension-negotiation" + destination: "/openshell/latest/extensibility/overview#protocol-negotiation" + - source: "/openshell/dev/extensibility/extension-negotiation" + destination: "/openshell/dev/extensibility/overview#protocol-negotiation" - source: "/openshell/latest/providers/google-vertex-ai" - destination: "/openshell/latest/providers/google-cloud#vertex-ai" + destination: "/openshell/latest/how-it-works/providers/google#vertex-ai" - source: "/openshell/dev/providers/google-vertex-ai" - destination: "/openshell/dev/providers/google-cloud#vertex-ai" + destination: "/openshell/dev/how-it-works/providers/google#vertex-ai" - source: "/openshell/latest/about/supported-agents" destination: "/openshell/latest/about/run-an-agent" - source: "/openshell/dev/about/supported-agents" @@ -77,7 +89,7 @@ redirects: - source: "/openshell/dev/get-started/quickstart" destination: "/openshell/dev/about/run-an-agent" - source: "/openshell/latest/sandboxes/providers-v2" - destination: "/openshell/latest/providers/profiles" + destination: "/openshell/latest/how-it-works/providers/profiles" # Paths are relative to the site root; subpath prefix matches instances + custom-domain. # Legacy HTML URLs used .../path/to/page/index.html; Fern canonical URLs omit index.html. # List explicit /index.html routes before :path*/index.html so empty path segments do not @@ -97,12 +109,7 @@ redirects: destination: "/openshell/:path*" - source: "/openshell/:path*.html" destination: "/openshell/:path*" - # tutorials moved under get-started - source: "/openshell/tutorials" - destination: "/openshell/latest/get-started/tutorials" + destination: "/openshell/latest/tutorials" - source: "/openshell/tutorials/:path*" - destination: "/openshell/latest/get-started/tutorials/:path*" - - source: "/openshell/latest/tutorials" - destination: "/openshell/latest/get-started/tutorials" - - source: "/openshell/latest/tutorials/:path*" - destination: "/openshell/latest/get-started/tutorials/:path*" + destination: "/openshell/latest/tutorials/:path*" diff --git a/providers/README.md b/providers/README.md index c7a5762643..9a721af9a8 100644 --- a/providers/README.md +++ b/providers/README.md @@ -50,5 +50,5 @@ workload, and import your copy. credential is only sent to the endpoints its profile declares. - Run `openshell provider profile lint` before importing. -See [Provider profiles](https://docs.nvidia.com/openshell/latest/providers/profiles.html) for the +See [Provider profiles](https://docs.nvidia.com/openshell/latest/how-it-works/providers/profiles) for the full schema. diff --git a/skills/debug-inference/SKILL.md b/skills/debug-inference/SKILL.md index dfeb0ca8c5..50937104a1 100644 --- a/skills/debug-inference/SKILL.md +++ b/skills/debug-inference/SKILL.md @@ -11,8 +11,8 @@ model. The application calls the provider's native endpoint and owns its base URL, model, request format, and timeout. Use installed `openshell --help` output as the authority for command syntax. -Refer to the published [provider management guide](https://docs.nvidia.com/openshell/latest/sandboxes/manage-providers.md) -and [provider profile guide](https://docs.nvidia.com/openshell/latest/providers/profiles.md) +Refer to the published [provider management guide](https://docs.nvidia.com/openshell/latest/how-it-works/providers/overview) +and [provider profile guide](https://docs.nvidia.com/openshell/latest/how-it-works/providers/profiles) for current behavior. ## Diagnostic Workflow diff --git a/skills/debug-openshell-cluster/SKILL.md b/skills/debug-openshell-cluster/SKILL.md index 22e35fbb27..8e865f13ec 100644 --- a/skills/debug-openshell-cluster/SKILL.md +++ b/skills/debug-openshell-cluster/SKILL.md @@ -34,7 +34,7 @@ On Windows, custom binaries can include MXC independently. Registrations for Docker, Podman, Kubernetes, and VM are rejection stubs when included; they do not enable those runtimes on Windows. -See the [compute driver reference](https://docs.nvidia.com/openshell/latest/reference/sandbox-compute-drivers.md) +See the [compute driver reference](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/runtimes) for selective-build options and external-driver configuration. For local evaluation only, TLS may be disabled and the gateway can be reached through `http://127.0.0.1:`. @@ -47,7 +47,7 @@ For local evaluation only, TLS may be disabled and the gateway can be reached th - For Kubernetes: `kubectl` must target the cluster that hosts OpenShell and Helm version 3 or later must be available. - For Docker or Podman: the runtime socket must be reachable from the gateway host. -Use `openshell --help` and nested `--help` output as the authority for the installed CLI version. Use the published [installation guide](https://docs.nvidia.com/openshell/latest/about/installation.md), [compute-driver reference](https://docs.nvidia.com/openshell/latest/reference/sandbox-compute-drivers.md), [gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config.md), and [Kubernetes setup guide](https://docs.nvidia.com/openshell/latest/kubernetes/setup.md) as the authority for deployment and configuration behavior. +Use `openshell --help` and nested `--help` output as the authority for the installed CLI version. Use the published [installation guide](https://docs.nvidia.com/openshell/latest/about/installation.md), [compute-driver reference](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/runtimes), [gateway configuration reference](https://docs.nvidia.com/openshell/latest/how-it-works/gateways/configuration), and [Kubernetes setup guide](https://docs.nvidia.com/openshell/latest/kubernetes/setup.md) as the authority for deployment and configuration behavior. ## Workflow @@ -225,7 +225,7 @@ If the 300-second provisioning repair window expires, the gateway records complete. Repairing configuration after expiry does not restart compute: wait for cleanup, then explicitly use `sandbox start`. Repeated rejected reports do not refresh the deadline, and the CLI wait timeout does not control it. -See [policy validation and repair](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md). +See [policy validation and repair](https://docs.nvidia.com/openshell/latest/how-it-works/policies/overview). The isolated supervisor requests image-policy discovery through the authenticated sandbox boundary before admission. The workload boundary can remain alive without launching the workload while configuration is repaired. An unavailable boundary diff --git a/skills/debug-openshell-cluster/references/supervisor-middleware.md b/skills/debug-openshell-cluster/references/supervisor-middleware.md index 6a71f95914..7f999fcf4e 100644 --- a/skills/debug-openshell-cluster/references/supervisor-middleware.md +++ b/skills/debug-openshell-cluster/references/supervisor-middleware.md @@ -4,7 +4,7 @@ Use this reference when the deployment registers supervisor middleware or a sandbox policy attaches it through `network_middlewares`. Start with gateway reachability and compute-platform checks in the [main skill](../SKILL.md). Use installed CLI help for command syntax and the published -[gateway configuration reference](https://docs.nvidia.com/openshell/latest/reference/gateway-config.md) +[gateway configuration reference](https://docs.nvidia.com/openshell/latest/how-it-works/gateways/configuration) for registration settings. ## Collect diagnostics diff --git a/skills/generate-sandbox-policy/SKILL.md b/skills/generate-sandbox-policy/SKILL.md index 98a21f162e..01042af1cc 100644 --- a/skills/generate-sandbox-policy/SKILL.md +++ b/skills/generate-sandbox-policy/SKILL.md @@ -157,7 +157,7 @@ You may need to go back and forth a few times. Keep the loop tight: ## Step 3: Read the Policy Schema -Read the published [policy schema reference](https://docs.nvidia.com/openshell/latest/reference/policy-schema.md) before generating or changing a policy. Published documentation is the authority for the current schema; do not infer fields from examples in this skill. +Read the published [policy schema reference](https://docs.nvidia.com/openshell/latest/how-it-works/policies/schema) before generating or changing a policy. Published documentation is the authority for the current schema; do not infer fields from examples in this skill. Key sections to reference: - **Policy Schema Reference** — top-level structure @@ -171,7 +171,7 @@ Key sections to reference: When middleware is requested, also read the published [supervisor middleware guide](https://docs.nvidia.com/openshell/latest/extensibility/supervisor-middleware.md). -For enforcement concepts and the shipped baseline, read [sandbox policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) and the [default policy reference](https://docs.nvidia.com/openshell/latest/reference/default-policy.md). The default policy is built into the OpenShell runtime and applies when no explicit policy is supplied. +For enforcement concepts and the shipped baseline, read [sandbox policies](https://docs.nvidia.com/openshell/latest/how-it-works/policies/overview) and the [default policy reference](https://docs.nvidia.com/openshell/latest/how-it-works/policies/default-policy). The default policy is built into the OpenShell runtime and applies when no explicit policy is supplied. Validate the intended provider combination as well as the authored policy. An image endpoint can become credentialed after provider composition and block @@ -631,9 +631,9 @@ private_services: ## Additional Resources -- [Policy schema](https://docs.nvidia.com/openshell/latest/reference/policy-schema.md) -- [Sandbox policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) -- [Default policy](https://docs.nvidia.com/openshell/latest/reference/default-policy.md) +- [Policy schema](https://docs.nvidia.com/openshell/latest/how-it-works/policies/schema) +- [Sandbox policies](https://docs.nvidia.com/openshell/latest/how-it-works/policies/overview) +- [Default policy](https://docs.nvidia.com/openshell/latest/how-it-works/policies/default-policy) - [Supervisor middleware](https://docs.nvidia.com/openshell/latest/extensibility/supervisor-middleware.md) - Default policy: built into the OpenShell runtime - For translation examples from real API docs, see [examples.md](examples.md) diff --git a/skills/openshell-cli/SKILL.md b/skills/openshell-cli/SKILL.md index c6e166f230..4118628278 100644 --- a/skills/openshell-cli/SKILL.md +++ b/skills/openshell-cli/SKILL.md @@ -34,12 +34,12 @@ This is your primary fallback. Use it freely -- the CLI's help output is authori Use `openshell --help` and nested `--help` output as the authority for the installed CLI version. Use the published documentation for product concepts and supported workflows: -- [Manage gateways](https://docs.nvidia.com/openshell/latest/sandboxes/manage-gateways.md) -- [Manage sandboxes](https://docs.nvidia.com/openshell/latest/sandboxes/manage-sandboxes.md) -- [Manage providers](https://docs.nvidia.com/openshell/latest/sandboxes/manage-providers.md) -- [Profiles](https://docs.nvidia.com/openshell/latest/providers/profiles.md) -- [Sandbox policies](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) -- [Inference routing](https://docs.nvidia.com/openshell/latest/sandboxes/inference-routing.md) +- [Manage gateways](https://docs.nvidia.com/openshell/latest/how-it-works/gateways/overview) +- [Manage sandboxes](https://docs.nvidia.com/openshell/latest/how-it-works/sandboxes/overview) +- [Manage providers](https://docs.nvidia.com/openshell/latest/how-it-works/providers/overview) +- [Profiles](https://docs.nvidia.com/openshell/latest/how-it-works/providers/profiles) +- [Sandbox policies](https://docs.nvidia.com/openshell/latest/how-it-works/policies/overview) +- [Inference routing](https://docs.nvidia.com/openshell/latest/how-it-works/inference) --- @@ -498,7 +498,7 @@ first failed load reset that window; repeated failures do not. After `ProvisioningTimedOut`, inspect the retained record and cleanup status, repair configuration, and explicitly run `sandbox start` once cleanup completes. A CLI wait timeout is separate from this gateway deadline. Follow the -published [policy repair guidance](https://docs.nvidia.com/openshell/latest/sandboxes/policies.md) +published [policy repair guidance](https://docs.nvidia.com/openshell/latest/how-it-works/policies/overview) and confirm current replacement/detach syntax with installed CLI help. An endpoint with omitted `protocol` retains explicit-proxy behavior. Explicit