diff --git a/docs/about/architecture.md b/docs/about/architecture.md index 8c0647b510..2b8467f314 100644 --- a/docs/about/architecture.md +++ b/docs/about/architecture.md @@ -1,9 +1,9 @@ --- title: - page: "Architecture Overview" - nav: "Architecture" -description: "High-level overview of the OpenShell architecture: gateway, sandboxes, policy engine, and privacy router." -keywords: ["openshell architecture", "sandbox architecture", "agent isolation", "k3s", "policy engine"] + page: "How OpenShell Works" + nav: "How It Works" +description: "OpenShell architecture: gateway, sandbox, policy engine, and privacy router." +keywords: ["nemoclaw architecture", "sandbox architecture", "agent isolation", "k3s", "policy engine"] topics: ["generative_ai", "cybersecurity"] tags: ["ai_agents", "sandboxing", "security", "architecture"] content: @@ -19,63 +19,48 @@ content: # How OpenShell Works -OpenShell runs as a [k3s](https://k3s.io/) Kubernetes cluster inside a Docker container. -Each sandbox is an isolated Kubernetes pod managed by the OpenShell control plane. -Four components work together to keep agents secure. +OpenShell runs as a [k3s](https://k3s.io/) Kubernetes cluster inside a Docker container. Each sandbox is an isolated Kubernetes pod managed through the gateway. Four components work together to keep agents secure. -```{mermaid} -flowchart LR - CLI["CLI"] -->|gRPC| GW["Gateway"] - GW --> SBX["Sandbox"] - - subgraph SBX["Sandbox"] - direction TB - AGENT["Agent Process"] -->|All traffic| PROXY["Network Proxy"] - PROXY -->|Evaluate| OPA["Policy Engine"] - end - - PROXY -->|Allowed traffic| EXT["External Services"] - - style CLI fill:#ffffff,stroke:#000000,color:#000000 - style GW fill:#76b900,stroke:#000000,color:#000000 - style SBX fill:#f5f5f5,stroke:#000000,color:#000000 - style AGENT fill:#ffffff,stroke:#000000,color:#000000 - style PROXY fill:#76b900,stroke:#000000,color:#000000 - style OPA fill:#76b900,stroke:#000000,color:#000000 - style EXT fill:#ffffff,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px +```{image} architecture.svg +:alt: OpenShell architecture diagram showing the NemoClaw component layout +:align: center ``` ## Components -OpenShell consists of the following components. - -Gateway -: The control-plane API that manages sandbox lifecycle, stores encrypted credentials, distributes policies, and terminates SSH tunnels. The CLI communicates exclusively with the gateway—it never talks to sandbox pods directly. +| Component | Role | +|---|---| +| **Gateway** | Control-plane API that coordinates sandbox lifecycle and state, acts as the auth boundary, and brokers requests across the platform. | +| **Sandbox** | Isolated runtime that includes container supervision and policy-enforced egress routing. | +| **Policy Engine** | Policy definition and enforcement layer for filesystem, network, and process constraints. Defense in depth enforces policies from the application layer down to infrastructure and kernel layers. | +| **Privacy Router** | Privacy-aware LLM routing layer that keeps sensitive context on sandbox compute and routes based on cost and privacy policy. | -Sandbox -: An isolated pod that runs your agent. Each sandbox contains a **supervisor** (sets up isolation and starts the agent), an **L7 proxy** (intercepts and evaluates every outbound connection), and the agent process itself. - -Policy Engine -: Evaluates declarative YAML policies that define filesystem, network, and process constraints. The proxy queries the engine on every outbound connection. Policies can be hot-reloaded without restarting the agent. +## How a Request Flows -Privacy Router -: Intercepts LLM API calls and routes them to local or self-hosted backends based on your routing policy. Sensitive prompts and completions stay on infrastructure you control. +Every outbound connection from agent code passes through the same decision path: -## How a Request Flows +1. The agent process opens an outbound connection (API call, package install, git clone, etc.). +2. The proxy inside the sandbox intercepts the connection and identifies which binary opened it. +3. The proxy queries the policy engine with the destination, port, and calling binary. +4. The policy engine returns one of three decisions: + - **Allow** — the destination and binary match a policy block. Traffic flows directly to the external service. + - **Route for inference** — no policy block matched, but inference routing is configured. The privacy router intercepts the request, strips the original credentials, injects the configured backend credentials, and forwards to the managed model endpoint. + - **Deny** — no match and no inference route. The connection is blocked and logged. -OpenShell works in the following way: +For REST endpoints with TLS termination enabled, the proxy also decrypts TLS and checks each HTTP request against per-method, per-path rules before allowing it through. -1. The agent makes an outbound connection (for example, an API call). -2. The L7 proxy intercepts the connection and identifies the calling process. -3. The proxy queries the policy engine with the destination and process identity. -4. Based on the policy decision, the proxy either allows the connection, routes it through the privacy router for inference, or denies it. +## Deployment Modes -## Remote Deployment +OpenShell can run locally or on a remote host. The architecture is identical in both cases — only the Docker container location changes. -OpenShell can also run on a remote host. Deploy with `openshell gateway start --remote user@host`, then set up a tunnel with `openshell gateway tunnel`. The architecture is identical—only the Docker container location changes. +- **Local**: the k3s cluster runs inside Docker on your workstation. The CLI provisions it automatically on first use. +- **Remote**: the cluster runs on a remote host. Deploy with `nemoclaw gateway start --remote user@host`. For example, connect to your DGX Spark + ```console + $ nemoclaw gateway start --remote @.local + $ nemoclaw status + ``` ---- +## Next Steps -For detailed component internals, refer to the [Architecture Reference](../reference/architecture.md). +- [Quickstart](get-started.md): Create your first sandbox. +- [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/about/architecture.svg b/docs/about/architecture.svg new file mode 100644 index 0000000000..b0bcd4d5df --- /dev/null +++ b/docs/about/architecture.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/about/get-started.md b/docs/about/get-started.md new file mode 100644 index 0000000000..01ac2bb775 --- /dev/null +++ b/docs/about/get-started.md @@ -0,0 +1,132 @@ +--- +title: + page: "Quickstart" + nav: "Quickstart" +description: "Install the OpenShell CLI and create your first sandboxed AI agent in two commands." +keywords: ["nemoclaw install", "quickstart", "sandbox create", "getting started"] +topics: ["generative_ai", "cybersecurity"] +tags: ["ai_agents", "sandboxing", "installation", "quickstart"] +content: + type: get_started + difficulty: technical_beginner + audience: [engineer, data_scientist] +--- + + + +# Quickstart + +This page gets you from zero to a running, policy-enforced sandbox in two commands. + +## Prerequisites + +Before you begin, make sure you have: + +- Python 3.12 or later +- [uv](https://docs.astral.sh/uv/) installed +- Docker Desktop running on your machine + +## Install the OpenShell CLI + +Activate your virtual environment: + +```bash +uv venv && source .venv/bin/activate +``` + +Install the CLI: + +```bash +uv pip install nemoclaw +``` + +## Connect to a Remote Gateway (Optional) + +If you're running locally, skip this step — the CLI creates a gateway automatically when you create your first sandbox. + +:::::{tab-set} + +::::{tab-item} Brev + +:::{note} +Deploy an OpenShell gateway on Brev by hitting **Deploy** on the [OpenShell Launchable](https://brev.nvidia.com/launchable/deploy/now?launchableID=env-3AaK9NmCzWp3pVyUDNNFBt805FT). +::: + +Once the instance is running, find the gateway URL in the Brev console under **Using Secure Links**. Copy the shareable URL for **port 8080** — this is the gateway endpoint. + +```console +$ nemoclaw gateway add https://.brevlab.com +$ nemoclaw status +``` + +:::: + +::::{tab-item} DGX Spark + +:::{note} +Set up your Spark with NVIDIA Sync first, or make sure SSH access is configured (e.g., SSH keys added to the host). +::: + +Deploy to a DGX Spark machine over SSH: + +```console +$ nemoclaw gateway start --remote @.local +$ nemoclaw status +``` + +Once `nemoclaw status` shows the gateway as healthy, all subsequent commands route through the SSH tunnel. + +:::: + +::::: + +## Create Your First OpenShell Sandbox + +Choose the tab that matches your agent: + +::::{tab-set} + +:::{tab-item} Claude Code +```console +$ nemoclaw sandbox create -- claude +``` + +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `ANTHROPIC_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. +::: + +:::{tab-item} OpenCode +```console +$ nemoclaw sandbox create -- opencode +``` + +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `OPENAI_API_KEY` or `OPENROUTER_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. +::: + +:::{tab-item} Codex +```console +$ nemoclaw sandbox create -- codex +``` + +The CLI prompts you to create a provider from local credentials — type `yes` to continue. If `OPENAI_API_KEY` is set in your environment, it is picked up automatically. If not, you can configure it from inside the sandbox after it launches. +::: + +:::{tab-item} Community Sandbox +```console +$ nemoclaw sandbox create --from openclaw +``` + +The `--from` flag pulls a pre-built sandbox definition from the [NemoClaw Community](https://github.com/NVIDIA/NemoClaw-Community) catalog. Each definition bundles a container image, a tailored policy, and optional skills into a single package. +::: + +:::: + +## Next Steps + +You now have a working sandbox! From here, you can: + +- **Follow a guided tutorial** — set up scoped GitHub repo access in {doc}`/tutorials/github-sandbox`. +- **Learn how sandboxes work** — see {doc}`/sandboxes/create-and-manage` for the full lifecycle. +- **Write your own policies** — see {doc}`/sandboxes/policies` for custom access rules. diff --git a/docs/about/overview.md b/docs/about/overview.md index 8cb6552485..e28350953e 100644 --- a/docs/about/overview.md +++ b/docs/about/overview.md @@ -2,8 +2,8 @@ title: page: "Overview of NVIDIA OpenShell" nav: "Overview" -description: "OpenShell is the safe, private runtime for autonomous AI agents. Run agents in sandboxed environments that protect your data, credentials, and infrastructure." -keywords: ["openshell", "ai agent sandbox", "agent security", "agent isolation", "inference routing"] +description: "NemoClaw is the safe, private runtime for autonomous AI agents. Run agents in sandboxed environments that protect your data, credentials, and infrastructure." +keywords: ["nemoclaw", "ai agent sandbox", "agent security", "agent isolation", "inference routing"] topics: ["generative_ai", "cybersecurity"] tags: ["ai_agents", "sandboxing", "security", "privacy", "inference_routing"] content: @@ -19,62 +19,47 @@ content: # Overview of NVIDIA OpenShell -NVIDIA OpenShell is an open-source runtime that executes autonomous AI agents inside sandboxed environments with kernel-level isolation. It prevents agents from accessing unauthorized files, exfiltrating data, leaking credentials, or making uncontrolled network requests. A single declarative YAML policy governs filesystem, network, process, and inference protections across all sandboxes and is hot-reloadable without restarting running agents. +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. -## Common Challenges with AI Agents +## Why OpenShell Exists -AI agents are most useful when they have broad access to reading files, installing packages, calling APIs, and using credentials. However, this same access makes them dangerous. An unrestricted agent can leak your API keys, send proprietary code to unauthorized endpoints, or reach infrastructure it was never meant to touch. +AI agents are most useful when they can read files, install packages, call APIs, and use credentials. That same access can create material risk. OpenShell is designed for this tradeoff: preserve agent capability while enforcing explicit controls over what the agent can access. -Conventional containers do not solve this. They isolate processes from the host, but they do not control what an agent does *inside* the container — which files it reads, which hosts it contacts, or where it sends your prompts. +## Common Risks and Controls -## Benefits of Using OpenShell +The table below summarizes common failure modes and how OpenShell mitigates them. -OpenShell addresses these risks through defense-in-depth enforcement across four policy domains: filesystem, network, process, and inference. +| Threat | Without controls | With OpenShell | +|---|---|---| +| Data exfiltration | Agent uploads source code or internal files to unauthorized endpoints. | Network policies allow only approved destinations; other outbound traffic is denied. | +| Credential theft | Agent reads local secrets such as SSH keys or cloud credentials. | Filesystem restrictions (Landlock) confine access to declared paths only. | +| Unauthorized API usage | Agent sends prompts or data to unapproved model providers. | Privacy routing and network policies control where inference traffic can go. | +| Privilege escalation | Agent attempts `sudo`, setuid paths, or dangerous syscall behavior. | Unprivileged process identity and seccomp restrictions block escalation paths. | -:::{dropdown} 🛡️ Kernel-Level Isolation -OpenShell enforces isolation at the Linux kernel level using Landlock for filesystem restrictions, seccomp for system call filtering, and network namespaces for traffic control. These mechanisms operate below the application layer, so agents cannot bypass them regardless of the tools or languages they use. -::: +## Protection Layers at a Glance -:::{dropdown} 📜 Declarative Policy Enforcement -A single YAML policy file defines all security boundaries for a sandbox: allowed filesystem paths, permitted network destinations, restricted processes, and inference routing rules. Policies are hot-reloadable, so you can tighten or relax rules on a running sandbox without restarting the agent. -::: +OpenShell applies defense in depth across four policy domains: -:::{dropdown} 🔐 Credential Containment -Credentials are injected into sandboxes as environment variables at startup and are scoped to the sandbox's isolated namespace. They cannot be read by processes outside the sandbox, and network policies prevent agents from transmitting them to unauthorized endpoints. -::: +| Layer | What it protects | When it applies | +|---|---|---| +| Filesystem | Prevents reads/writes outside allowed paths. | Locked at sandbox creation. | +| Network | Blocks unauthorized outbound connections. | Hot-reloadable at runtime. | +| Process | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | +| Inference | Reroutes model API calls to controlled backends. | Hot-reloadable at runtime. | -:::{dropdown} 🔀 Private Inference Routing -The built-in inference router intercepts LLM API calls and redirects them to local or self-hosted backends based on your routing policy. Sensitive prompts and completions stay on infrastructure you control. Routes are configurable per sandbox and can be updated without restarting agents. -::: +For details, refer to [Built-in Default Policy](../sandboxes/index.md#built-in-default-policy) and [Customize Sandbox Policies](../sandboxes/policies.md). -:::{dropdown} 🔍 Full L7 Traffic Inspection -Every outbound TCP connection from a sandbox passes through an L7 proxy that resolves the calling process, evaluates the destination against the active policy, and either allows, denies, or reroutes the request. For REST endpoints, the proxy decrypts TLS, inspects HTTP method and path, and applies fine-grained access rules. -::: +## Common Use Cases -## Use Cases - -The following are common use cases for OpenShell. - -:::{dropdown} 💻 Secure Coding Agents -Run AI coding assistants such as Claude Code, OpenCode, or OpenClaw inside a sandbox where they can read and modify project files but cannot access SSH keys, cloud credentials, or files outside the project directory. Network policies restrict which package registries and APIs the agent can reach. -::: - -:::{dropdown} 🏢 Private Enterprise Development -Route all LLM inference through self-hosted NVIDIA NIM endpoints or private API backends. Proprietary source code and internal documentation stay on your infrastructure and are never sent to third-party LLM providers. -::: - -:::{dropdown} ✅ Compliance and Audit -Declarative policies serve as auditable security controls. Each sandbox runs under a well-defined policy that specifies exactly what the agent can access. Policy files can be version-controlled and reviewed as part of your security and compliance processes. -::: - -:::{dropdown} 📦 Community and Custom Sandbox Images -Use pre-built sandbox images from the [OpenShell Community](https://github.com/NVIDIA/OpenShell-Community) catalog or bring your own container. Community sandboxes bundle domain-specific tools, policies, and skills, while custom containers let you package any environment your agents need. -::: +- **Secure coding agents**: Run Claude Code, OpenCode, or OpenClaw with constrained file and network access. +- **Private enterprise development**: Route inference to self-hosted or private backends while keeping sensitive context under your control. +- **Compliance and audit**: Treat policy YAML as version-controlled security controls that can be reviewed and audited. +- **Reusable environments**: Use community sandbox images or bring your own containerized runtime. --- ## Next Steps - [Architecture Overview](architecture.md): Understand the components that make up the OpenShell runtime. -- [Get Started](../index.md): Install the CLI and create your first sandbox. -- [Safety and Privacy](../safety-and-privacy/index.md): Learn how OpenShell enforces isolation across all protection layers. +- [Quickstart](get-started.md): Install the CLI and create your first sandbox. +- [Sandboxes](../sandboxes/index.md): Learn how OpenShell enforces isolation across all protection layers. diff --git a/docs/get-started/quickstart.md b/docs/get-started/quickstart.md deleted file mode 100644 index acec1ac372..0000000000 --- a/docs/get-started/quickstart.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: - page: "Quickstart" - nav: "Quickstart" -description: "Install the OpenShell CLI and create your first sandboxed AI agent in two commands." -keywords: ["openshell install", "quickstart", "sandbox create", "getting started"] -topics: ["generative_ai", "cybersecurity"] -tags: ["ai_agents", "sandboxing", "installation", "quickstart"] -content: - type: get_started - difficulty: technical_beginner - audience: [engineer, data_scientist] ---- - - - -# Quickstart - -This page gets you from zero to a running, policy-enforced sandbox in two commands. - -## Prerequisites - -Before you begin, make sure you have: - -- Python 3.12 or later -- Docker Desktop running on your machine - -## Install the OpenShell CLI - -```bash -pip install openshell -``` - -## Create Your First OpenShell Sandbox - -Choose the tab that matches your agent: - -::::{tab-set} - -:::{tab-item} Claude Code -```console -$ openshell sandbox create -- claude -``` - -```text -✓ Runtime ready -✓ Discovered Claude credentials (ANTHROPIC_API_KEY) -✓ Created sandbox: keen-fox -✓ Policy loaded (4 protection layers active) - -Connecting to keen-fox... -``` - -The CLI detects your `ANTHROPIC_API_KEY`, creates a provider, builds the sandbox, applies a default policy, and drops you into an interactive session. No additional configuration is required. -::: - -:::{tab-item} Community Sandbox -```console -$ openshell sandbox create --from openclaw -``` - -The `--from` flag pulls a pre-built sandbox definition from the [OpenShell Community](https://github.com/NVIDIA/OpenShell-Community) catalog. Each definition bundles a container image, a tailored policy, and optional skills into a single package. -::: - -:::: - -## What Happens Behind the Scenes - -When you create a sandbox, OpenShell activates the following protection layers. - -| Protection Layer | Description | -|------------------------|-----------------------------------------------------------------------------------------------| -| Filesystem isolation | The agent can only read and write paths that the policy explicitly permits. | -| Network enforcement | Outbound connections are denied by default. The policy allowlists specific hosts, ports, and binaries. | -| Process restrictions | The agent runs as a non-root user inside the container. | -| Inference privacy | LLM API traffic is routed through a privacy-aware proxy. Credentials never leak outside the sandbox. | - -A single YAML policy file controls all four layers. You can hot-reload network and inference rules on a running sandbox without restarting it. - -:::{note} -For OpenCode or Codex, the default policy does not cover the required endpoints. Follow the [Run OpenCode with NVIDIA Inference](run-opencode.md) tutorial for agent-specific setup. -::: - -## Next Steps - -You now have a working sandbox. From here, you can: - -- Follow the [Tutorials](tutorials.md) for step-by-step walkthroughs with Claude Code, OpenClaw, and OpenCode. -- Learn how sandboxes work in [Sandboxes](../sandboxes/create-and-manage.md). -- Write your own policies in [Safety and Privacy](../safety-and-privacy/index.md). diff --git a/docs/get-started/run-claude.md b/docs/get-started/run-claude.md deleted file mode 100644 index c42deaa9e7..0000000000 --- a/docs/get-started/run-claude.md +++ /dev/null @@ -1,119 +0,0 @@ - - -# Run Claude Code Safely - -This tutorial walks you through the path to running Claude Code inside a OpenShell sandbox. By the end of this tutorial, you will have an isolated environment with credentials securely injected and a default policy controlling what the agent can access. - -## What You Will Learn - -- Create a sandbox with a single command. -- Understand how OpenShell auto-discovers provider credentials. -- Inspect what the default policy allows and denies. -- Connect to a running sandbox and work inside it. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- `ANTHROPIC_API_KEY` environment variable set on your host machine. - -## Create the Sandbox - -Run the following command: - -```console -$ openshell sandbox create -- claude -``` - -This single command performs four actions: - -1. Bootstraps the runtime. On first use, the CLI provisions a local k3s cluster inside Docker and deploys the OpenShell control plane. This happens once. Subsequent commands reuse the existing cluster. -2. Auto-discovers credentials. The CLI detects that `claude` is a recognized tool and reads the `ANTHROPIC_API_KEY` environment variable from your shell. It creates a provider automatically. -3. Creates the sandbox. The CLI provisions an isolated container and applies the default policy. This policy allows Claude Code to reach `api.anthropic.com` and a small set of supporting endpoints while blocking everything else. -4. Drops you into the sandbox. You land in an interactive SSH session, ready to work. - -:::{note} -The first bootstrap takes a few minutes depending on your network speed. The CLI prints progress as each component starts. Subsequent sandbox creations are much faster. -::: - -## Work Inside the Sandbox - -You are now inside the sandbox. Start Claude Code: - -```console -$ claude -``` - -Your credentials are available as environment variables. Verify this with: - -```console -$ echo $ANTHROPIC_API_KEY -sk-ant-... -``` - -The sandbox provides a working directory at `/sandbox` where you can create and edit files. Standard development tools — git, common language runtimes, and package managers — are available within the boundaries set by the policy. - -## Check Sandbox Status - -Open a second terminal on your host machine to inspect the sandbox from outside. - -1. In the second terminal, list all sandboxes: - - ```console - $ openshell sandbox list - ``` - -2. Launch the OpenShell Terminal for a live dashboard that shows sandbox status, active network connections, and policy decisions in real time: - - ```console - $ openshell term - ``` - -## Connect from VS Code (Optional) - -If you prefer a graphical editor, connect to the sandbox with VS Code Remote-SSH. - -Export the sandbox SSH configuration: - -```console -$ openshell sandbox ssh-config >> ~/.ssh/config -``` - -Then open VS Code, install the Remote - SSH extension if needed, and connect to the host named after your sandbox. VS Code opens a full editor session inside the isolated environment. - -:::{tip} -Replace `` with your sandbox name. Run `openshell sandbox list` to find it if you did not specify one at creation time. -::: - -## Clean Up - -Exit the sandbox shell: - -```console -$ exit -``` - -Delete the sandbox: - -```console -$ openshell sandbox delete -``` - -:::{tip} -If you want the sandbox to persist after you disconnect, add the `--keep` flag at creation time: - -```console -$ openshell sandbox create --keep -- claude -``` - -This is useful when you plan to reconnect later or iterate on the policy while the sandbox runs. -::: - -## Next Steps - -- {doc}`../sandboxes/create-and-manage`: Learn the isolation model and sandbox lifecycle. -- {doc}`../sandboxes/providers`: Understand how credentials are injected without exposing them to agent code. -- {doc}`../safety-and-privacy/default-policies`: What the built-in default policy allows and denies. -- {doc}`../safety-and-privacy/policies`: Write custom policies and configure network rules. diff --git a/docs/get-started/run-openclaw.md b/docs/get-started/run-openclaw.md deleted file mode 100644 index 3ad44636bf..0000000000 --- a/docs/get-started/run-openclaw.md +++ /dev/null @@ -1,101 +0,0 @@ - - -# Run OpenClaw Safely - -This tutorial shows you how to launch a sandbox with OpenClaw from the [OpenShell Community catalog](https://github.com/NVIDIA/OpenShell-Community) using the `--from` flag. This is a pre-built sandbox configuration that includes a container image, a tailored policy, and optional skills. - -## What You Will Learn - -- Understand what community sandboxes are and how they differ from default sandboxes. -- Use the `--from` flag to pull and build a complete sandbox configuration. -- Inspect the bundled policy that ships with a community sandbox. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- NVIDIA GPU with drivers installed. OpenClaw requires GPU acceleration. - -## Create the Sandbox - -Run the following command: - -```console -$ openshell sandbox create --from openclaw --keep -``` - -The `--from` flag tells the CLI to pull a sandbox definition from the OpenShell Community catalog. Here is what happens behind the scenes: - -1. Fetches the definition. The CLI downloads the OpenClaw sandbox definition from the OpenShell-Community repository. This includes a Dockerfile, a policy YAML, and any bundled skills. -2. Builds the image. The CLI builds the Dockerfile locally using Docker. The resulting image includes all tools and dependencies that OpenClaw needs. -3. Applies the bundled policy. Instead of the generic default policy, the sandbox starts with a policy written specifically for the OpenClaw workload. It allows the endpoints and binaries that OpenClaw requires. -4. Creates and keeps the sandbox. The `--keep` flag ensures the sandbox stays running after creation so you can connect and disconnect freely. - -:::{note} -The first build takes longer because Docker needs to pull base layers and install dependencies. Subsequent creates reuse the cached image. -::: - -## Connect to the Sandbox - -After creation completes, connect to the running sandbox: - -```console -$ openshell sandbox connect -``` - -Replace `` with the sandbox name shown in the creation output. If you did not specify a name with `--name`, the CLI assigns one automatically. Run `openshell sandbox list` to find it. - -## Explore the Environment - -The sandbox comes pre-configured for the OpenClaw workload. The tools, runtimes, and libraries that OpenClaw needs are already installed in the container image. The policy is tuned to allow the specific network endpoints and operations that OpenClaw uses, so you can start working immediately without policy adjustments. - -## Inspect the Bundled Policy - -To see exactly what the sandbox is allowed to do, pull the full policy: - -```console -$ openshell policy get --full -``` - -This outputs the complete policy YAML. Review it to understand the sandbox's permissions: - -- Network policies, which hosts and ports the sandbox can reach, and which binaries are allowed to initiate those connections. -- Filesystem policy, which paths are read-only and which are read-write. -- Process restrictions, which user and group the sandbox runs as. -- Inference rules, which inference routing hints are allowed. - -Reviewing the bundled policy is a good practice before you use a community sandbox for sensitive work. - -:::{tip} -Save the policy to a file for reference or as a starting point for customization: - -```console -$ openshell policy get --full > openclaw-policy.yaml -``` -::: - -## Clean Up - -Exit the sandbox if you are connected: - -```console -$ exit -``` - -Delete the sandbox: - -```console -$ openshell sandbox delete -``` - -:::{note} -The OpenShell Community repository accepts contributions. If you build a sandbox configuration that would be useful to others, submit it to the [OpenShell-Community](https://github.com/NVIDIA/OpenShell-Community) repository. -::: - -## Next Steps - -- {doc}`../sandboxes/community-sandboxes`: Full reference on community sandbox definitions, available images, and how to contribute your own. -- {doc}`../safety-and-privacy/policies`: Learn the policy format and how to customize what a sandbox can do. -- {doc}`../sandboxes/create-and-manage`: Understand the isolation model and lifecycle behind every sandbox. diff --git a/docs/get-started/run-opencode.md b/docs/get-started/run-opencode.md deleted file mode 100644 index 287372ed27..0000000000 --- a/docs/get-started/run-opencode.md +++ /dev/null @@ -1,257 +0,0 @@ - - -# Run OpenCode with NVIDIA Inference - -This tutorial walks you through a realistic setup where you run [OpenCode](https://opencode.ai) inside an OpenShell sandbox and configure private inference through `inference.local`. Along the way, you will hit a policy denial, diagnose it from logs, write a custom policy, and configure inference routing. This is the full policy iteration loop that you will use whenever you onboard a new tool. - -## What You Will Learn - -- Create a provider manually using the `--from-existing` flag. -- Write a custom policy to replace the default policy. -- Read sandbox logs to diagnose denied actions. -- Distinguish between agent traffic and sandbox inference traffic. -- Configure inference routing for code running inside the sandbox. - -## Prerequisites - -- Met the prerequisites and installed the OpenShell CLI as described in the {doc}`quickstart` guide. -- `NVIDIA_API_KEY` environment variable set on your host machine with a valid NVIDIA API key. - -## Create the Provider - -In the Claude Code tutorial, the CLI auto-discovers credentials. Here you create a provider explicitly, which gives you control over the provider name and type. - -```console -$ openshell provider create --name nvidia --type nvidia --from-existing -``` - -The `--from-existing` flag tells the CLI to discover credentials from your local environment. It finds `NVIDIA_API_KEY` and stores it securely. The provider is now available to attach to any sandbox. - -Verify the provider exists: - -```console -$ openshell provider list -``` - -## Create the Sandbox - -Create a sandbox with the NVIDIA provider attached and OpenCode as the startup command: - -```console -$ openshell sandbox create --name opencode-sandbox --provider nvidia --keep -- opencode -``` - -The `--keep` flag keeps the sandbox alive after you exit, which you need for the iteration steps ahead. The CLI creates the sandbox with the default policy, injects the NVIDIA credentials, and starts OpenCode. - -## Hit a Policy Denial - -Try using OpenCode inside the sandbox. You will find that calls to NVIDIA inference endpoints fail. The default policy is designed around Claude Code, not OpenCode, so the required endpoints are not allowlisted. - -Open a second terminal and check the logs: - -```console -$ openshell logs opencode-sandbox --tail -``` - -Alternatively, launch the OpenShell Terminal for a live view: - -```console -$ openshell term -``` - -Look for lines like these: - -```text -action=deny host=integrate.api.nvidia.com binary=/usr/local/bin/opencode reason="no matching network policy" -action=deny host=opencode.ai binary=/usr/bin/node reason="no matching network policy" -``` - -Each log entry tells you the exact host, binary, and reason for the denial. - -## Understand the Denial - -The default policy contains a `nvidia_inference` network policy entry, but it is configured for a narrow set of binaries - typically `/usr/local/bin/claude` and `/usr/bin/node`. When OpenCode makes HTTP calls through its own binary, `curl`, or a shell subprocess, those connections do not match any policy rule and get denied. - -Two separate problems are at play: - -- OpenCode's own traffic. OpenCode contacts `opencode.ai` for its API and `integrate.api.nvidia.com` for inference. Neither endpoint has a matching rule for the binaries OpenCode uses. -- Missing endpoint. The default policy has no entry for `opencode.ai` at all. Even if the binary matched, the destination is not listed. - -This is expected behavior. OpenShell denies everything by default. You need to write a policy that explicitly allows what OpenCode needs. - -## Write a Custom Policy - -Create a file called `opencode-policy.yaml` with the following content: - -```yaml -version: 1 -filesystem_policy: - include_workdir: true - read_only: - - /usr - - /lib - - /proc - - /dev/urandom - - /app - - /etc - - /var/log - read_write: - - /sandbox - - /tmp - - /dev/null -landlock: - compatibility: best_effort -process: - run_as_user: sandbox - run_as_group: sandbox -network_policies: - opencode_api: - name: opencode-api - endpoints: - - host: opencode.ai - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - nvidia_inference: - name: nvidia-inference - endpoints: - - host: integrate.api.nvidia.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - - path: /usr/bin/curl - - path: /bin/bash - npm_registry: - name: npm-registry - endpoints: - - host: registry.npmjs.org - port: 443 - binaries: - - path: /usr/bin/npm - - path: /usr/bin/node - - path: /usr/local/bin/npm - - path: /usr/local/bin/node - github_rest_api: - name: github-rest-api - endpoints: - - host: api.github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: read-only - binaries: - - path: /usr/local/bin/opencode - - path: /usr/bin/node - - path: /usr/bin/gh - github_ssh_over_https: - name: github-ssh-over-https - endpoints: - - host: github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - rules: - - allow: - method: GET - path: "/**/info/refs*" - - allow: - method: POST - path: "/**/git-upload-pack" - binaries: - - path: /usr/bin/git -``` - -This policy differs from the default in three key ways: - -- `opencode_api`: Allows OpenCode and Node.js to reach `opencode.ai:443`. -- Broader `nvidia_inference` binaries: Adds `/usr/local/bin/opencode`, `/usr/bin/curl`, and `/bin/bash` so OpenCode's subprocesses can reach the NVIDIA endpoint. -- GitHub access: Scoped to support OpenCode's git operations. - -:::{warning} -The `filesystem_policy`, `landlock`, and `process` sections are static. They are set at sandbox creation time and cannot be changed on a running sandbox. To modify these, delete and recreate the sandbox. The `network_policies` section is dynamic and can be hot-reloaded. -::: - -## Apply the Policy - -Push your custom policy to the running sandbox: - -```console -$ openshell policy set opencode-sandbox --policy opencode-policy.yaml --wait -``` - -The `--wait` flag blocks until the sandbox confirms the policy is loaded. - -Verify the policy revision was accepted: - -```console -$ openshell policy list opencode-sandbox -``` - -The latest revision should show status `loaded`. - -## Configure Inference Routing - -So far, you have allowed the OpenCode *agent* to reach `integrate.api.nvidia.com` directly through network policy. But code that OpenCode writes and runs inside the sandbox should use `https://inference.local`. - -Configure inference so `inference.local` routes to your NVIDIA provider: - -```console -$ openshell inference set \ - --provider nvidia \ - --model z-ai/glm5 -``` - -Verify the active configuration: - -```console -$ openshell inference get -``` - -:::{note} -*Network policies* and managed inference are two separate enforcement points. Network policies control which external hosts the agent binary can reach directly. Inference configuration controls where userland calls to `https://inference.local` are routed. -::: - -## Verify the Policy - -Tail the logs again: - -```console -$ openshell logs opencode-sandbox --tail -``` - -You should see `action=allow` lines for the endpoints you added. Connections to `opencode.ai`, `integrate.api.nvidia.com`, and GitHub should show `action=allow`. - -To verify userland inference, run code inside the sandbox that targets `https://inference.local/v1`. - -If you still see denials, read the log line carefully. It tells you the exact host, port, and binary that was blocked. Add the missing entry to your policy and push again with `openshell policy set`. This observe-modify-push cycle is the normal workflow for onboarding any new tool in OpenShell. - -## Clean Up - -When you are finished, delete the sandbox: - -```console -$ openshell sandbox delete opencode-sandbox -``` - -## Next Steps - -- {doc}`../safety-and-privacy/policies`: Full reference on policy YAML structure, static and dynamic fields, and enforcement modes. -- {doc}`../safety-and-privacy/policies`: How network policy fits into the sandbox iteration workflow. -- {doc}`../inference/index`: `inference.local`, supported API patterns, and request routing. -- {doc}`../sandboxes/providers`: Provider types, credential discovery, and manual and automatic creation. -- {doc}`../safety-and-privacy/index`: The four protection layers and how they interact. diff --git a/docs/get-started/tutorials.md b/docs/get-started/tutorials.md deleted file mode 100644 index 4b69dee937..0000000000 --- a/docs/get-started/tutorials.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: - page: "OpenShell Tutorials" - nav: "Tutorials" -description: "Step-by-step tutorials for running AI agents inside OpenShell sandboxes." -keywords: ["openshell tutorials", "claude code sandbox", "opencode sandbox", "openclaw sandbox"] -topics: ["generative_ai", "cybersecurity"] -tags: ["ai_agents", "sandboxing", "tutorial"] -content: - type: tutorial - difficulty: technical_beginner - audience: [engineer, data_scientist] ---- - - - -# Tutorials - -Each tutorial below walks you through running a specific AI agent inside a OpenShell sandbox. Choose the tutorial that matches your agent. - -::::{grid} 1 1 2 2 -:gutter: 3 - -:::{grid-item-card} Run Claude Code Safely -:link: run-claude -:link-type: doc - -Create a sandbox with Claude Code. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::{grid-item-card} Run OpenClaw Safely -:link: run-openclaw -:link-type: doc - -Launch a sandbox with OpenClaw from the OpenShell Community catalog using the `--from` flag. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::{grid-item-card} Run OpenCode with NVIDIA Inference -:link: run-opencode -:link-type: doc - -Launch a sandbox with OpenCode with NVIDIA inference routed to NVIDIA API endpoints. - -+++ -{bdg-secondary}`Tutorial` -::: - -:::: - -```{toctree} -:hidden: -:maxdepth: 2 - -Run Claude Code Safely -Run OpenClaw Safely -Run OpenCode with NVIDIA Inference -``` diff --git a/docs/index.md b/docs/index.md index cd2bb40bb7..eec20c0b6d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,9 +24,9 @@ content: # NVIDIA OpenShell -[![GitHub](https://img.shields.io/badge/github-repo-green?logo=github)](https://github.com/NVIDIA/OpenShell) -[![License](https://img.shields.io/badge/License-Apache_2.0-blue)](https://github.com/NVIDIA/OpenShell/blob/main/LICENSE) -[![PyPI](https://img.shields.io/badge/PyPI-openshell-orange?logo=pypi)](https://pypi.org/project/openshell/) +[![GitHub](https://img.shields.io/badge/github-repo-green?logo=github)](https://github.com/NVIDIA/NemoClaw) +[![License](https://img.shields.io/badge/License-Apache_2.0-blue)](https://github.com/NVIDIA/NemoClaw/blob/main/LICENSE) +[![PyPI](https://img.shields.io/badge/PyPI-nemoclaw-orange?logo=pypi)](https://pypi.org/project/nemoclaw/) OpenShell is the safe, private runtime for autonomous AI agents. It provides sandboxed execution environments that protect your data, credentials, and infrastructure. Agents run with exactly the permissions they need and @@ -97,13 +97,13 @@ Install the CLI and create your first sandbox in two commands.
-
$ pip install openshell
-
$ openshell sandbox create -- claude--from openclaw
+
$ uv pip install nemoclaw
+
$ nemoclaw sandbox create -- claude--from openclaw
``` -Refer to the [Quickstart](get-started/quickstart.md) for more details. +Refer to the [Quickstart](about/get-started.md) for more details. --- @@ -122,31 +122,31 @@ Learn about OpenShell and its capabilities. {bdg-secondary}`Concept` ::: -:::{grid-item-card} Get Started -:link: get-started/quickstart +:::{grid-item-card} Quickstart +:link: about/get-started :link-type: doc -Quickstart guide and tutorials for creating a OpenShell sandbox with Claude Code, OpenClaw, and OpenCode. +Install the CLI and create your first sandbox in two commands. +++ {bdg-secondary}`Tutorial` ::: -:::{grid-item-card} Sandboxes -:link: sandboxes/index +:::{grid-item-card} Tutorials +:link: tutorials/index :link-type: doc -Create, manage, and customize sandboxes. Use community images or bring your own container. +End-to-end guides: GitHub repo access, custom policies, and more. +++ -{bdg-secondary}`Concept` +{bdg-secondary}`Tutorial` ::: -:::{grid-item-card} Safety and Privacy -:link: safety-and-privacy/index +:::{grid-item-card} Sandboxes +:link: sandboxes/index :link-type: doc -Write policies that control what agents can access. Iterate on network rules in real time. +Create, manage, and customize sandboxes. Configure policies, providers, and community images. +++ {bdg-secondary}`Concept` @@ -193,8 +193,8 @@ Release Notes :caption: Get Started :hidden: -get-started/quickstart -get-started/tutorials +Quickstart +tutorials/index ``` ```{toctree} @@ -204,18 +204,10 @@ get-started/tutorials sandboxes/index sandboxes/create-and-manage sandboxes/providers +sandboxes/policies sandboxes/community-sandboxes ``` -```{toctree} -:caption: Safety and Privacy -:hidden: - -safety-and-privacy/index -safety-and-privacy/default-policies -safety-and-privacy/policies -``` - ```{toctree} :caption: Inference Routing :hidden: @@ -231,14 +223,6 @@ inference/configure reference/cli reference/default-policy reference/policy-schema -reference/architecture -``` - -```{toctree} -:caption: Troubleshooting -:hidden: - -troubleshooting ``` ```{toctree} diff --git a/docs/inference/configure.md b/docs/inference/configure.md index 6463daf716..771932dee7 100644 --- a/docs/inference/configure.md +++ b/docs/inference/configure.md @@ -5,43 +5,71 @@ # Configure Inference Routing -OpenShell exposes one managed inference backend behind `https://inference.local` -for the active gateway. +This page covers the managed local inference endpoint (`https://inference.local`). External inference endpoints go through sandbox `network_policies` — see [Network Access Rules](/sandboxes/index.md#network-access-rules) for details. -External inference endpoints still go through sandbox `network_policies`. This -page covers the special local inference endpoint only. +The configuration consists of two values: -That configuration consists of two values: - -- a provider record name -- a model ID +| Value | Description | +|---|---| +| Provider record | The credential backend OpenShell uses to authenticate with the upstream model host. | +| Model ID | The model to use for generation requests. | ## Step 1: Create a Provider Create a provider that holds the backend credentials you want OpenShell to use. +:::::{tab-set} + +::::{tab-item} NVIDIA API Catalog + +```console +$ nemoclaw provider create --name nvidia-prod --type nvidia --from-existing +``` + +This reads `NVIDIA_API_KEY` from your environment. + +:::: + +::::{tab-item} Local / self-hosted endpoint + +```console +$ nemoclaw provider create \ + --name my-local-model \ + --type openai \ + --credential OPENAI_API_KEY=empty-if-not-required \ + --config OPENAI_BASE_URL=http://192.168.10.15/v1 +``` + +Use `--config OPENAI_BASE_URL` to point to any OpenAI-compatible server running on your network. Set `OPENAI_API_KEY` to a dummy value if the server does not require authentication. + +:::: + +::::{tab-item} Anthropic + ```console -$ openshell provider create --name nvidia-prod --type nvidia --from-existing +$ nemoclaw provider create --name anthropic-prod --type anthropic --from-existing ``` -You can also use `openai` or `anthropic` providers. +This reads `ANTHROPIC_API_KEY` from your environment. + +:::: + +::::: ## Step 2: Set Inference Routing Point `inference.local` at that provider and choose the model to use: ```console -$ openshell inference set \ +$ nemoclaw inference set \ --provider nvidia-prod \ --model nvidia/nemotron-3-nano-30b-a3b ``` -This sets the managed inference configuration. - ## Step 3: Verify the Active Config ```console -$ openshell inference get +$ nemoclaw inference get provider: nvidia-prod model: nvidia/nemotron-3-nano-30b-a3b version: 1 @@ -52,19 +80,18 @@ version: 1 Use `update` when you want to change only one field: ```console -$ openshell inference update --model nvidia/nemotron-3-nano-30b-a3b +$ nemoclaw inference update --model nvidia/nemotron-3-nano-30b-a3b ``` -Or switch providers without repeating the current model manually: +Or switch providers without repeating the current model: ```console -$ openshell inference update --provider openai-prod +$ nemoclaw inference update --provider openai-prod ``` ## Use It from a Sandbox -Once inference is configured, userland code inside any sandbox can call -`https://inference.local` directly: +Once inference is configured, code inside any sandbox can call `https://inference.local` directly: ```python from openai import OpenAI @@ -77,24 +104,33 @@ response = client.chat.completions.create( ) ``` -The client-supplied model is ignored for generation requests. OpenShell -rewrites it to the configured model before forwarding upstream. +The client-supplied model is ignored for generation requests. OpenShell rewrites it to the configured model before forwarding upstream. + +Use this endpoint when inference should stay local to the host for privacy and security reasons. External providers that should be reached directly belong in `network_policies` instead. + +### Verify the Endpoint from a Sandbox -Use this endpoint when inference should stay local to the host for privacy and -security reasons. External providers that should be reached directly belong in -`network_policies` instead. +`nemoclaw inference get` confirms the configuration was saved, but does not verify the upstream endpoint is reachable. To confirm end-to-end connectivity, connect to a sandbox and run: + +```bash +curl https://inference.local/v1/responses \ + -H "Content-Type: application/json" \ + -d '{ + "instructions": "You are a helpful assistant.", + "input": "Hello!" + }' +``` -## Good to Know +A successful response confirms the privacy router can reach the configured backend and the model is serving requests. -- Gateway-scoped: every sandbox on the active gateway sees the same - `inference.local` backend. -- HTTPS only: `inference.local` is intercepted only for HTTPS traffic. +:::{note} +- **Gateway-scoped** — every sandbox on the active gateway sees the same `inference.local` backend. +- **HTTPS only** — `inference.local` is intercepted only for HTTPS traffic. +::: ## Next Steps -- {doc}`index`: understand the interception flow and supported API patterns. -- [Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation): - configure direct access to external inference endpoints. -- {doc}`../sandboxes/providers`: create and manage provider records. -- {doc}`../reference/cli`: see the CLI reference for `openshell inference` - commands. +- **How does inference routing work?** See {doc}`index` for the interception flow and supported API patterns. +- **Need to control external endpoints?** See [Network Access Rules](/sandboxes/index.md#network-access-rules). +- **Managing provider records?** See {doc}`../sandboxes/providers`. +- **CLI reference?** See {doc}`../reference/cli` for `nemoclaw inference` commands. diff --git a/docs/inference/index.md b/docs/inference/index.md index da8abe0858..531cdf4f35 100644 --- a/docs/inference/index.md +++ b/docs/inference/index.md @@ -7,78 +7,55 @@ OpenShell handles inference in two ways: -- External inference endpoints are controlled by sandbox `network_policies`. -- Each sandbox also exposes `https://inference.local`, a special endpoint for - inference that should stay local to the host for privacy and security. +| Path | How It Works | +|---|---| +| **External endpoints** | Traffic to hosts like `api.openai.com` or `api.anthropic.com` is treated like any other outbound request — allowed or denied by `network_policies`. See [Network Access Rules](/sandboxes/index.md#network-access-rules). | +| **`inference.local`** | A special endpoint exposed inside every sandbox for inference that should stay local to the host for privacy and security. The {doc}`privacy router ` strips the original credentials, injects the configured backend credentials, and forwards to the managed model endpoint. | -## External Inference +## How `inference.local` Works -If sandbox code calls an external inference API like `api.openai.com` or -`api.anthropic.com`, that traffic is treated like any other outbound network -request. It is allowed or denied by `network_policies`. +When code inside a sandbox calls `https://inference.local`, the privacy router routes the request to the configured backend for that gateway. The configured model is applied to generation requests, and provider credentials are supplied by OpenShell rather than by code inside the sandbox. -Refer to {doc}`/safety-and-privacy/policies` and the -[Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation) -section for details. +If code calls an external inference host directly, that traffic is evaluated only by `network_policies`. -## `inference.local` - -Every sandbox also exposes a special endpoint: `https://inference.local`. - -This endpoint exists so inference can be routed to a model running locally on -the same host. In the future, it can also route to a model managed by the -cluster. It is the special case for inference that should stay local for -privacy and security reasons. - -## Using `inference.local` - -When code inside a sandbox calls `https://inference.local`, OpenShell routes the -request to the configured backend for that gateway. - -The configured model is applied to generation requests, and provider -credentials are supplied by OpenShell rather than by code inside the sandbox. - -If code calls an external inference host directly, that traffic is evaluated -only by `network_policies`. +| Property | Detail | +|---|---| +| Credentials | No sandbox API keys needed — credentials come from the configured provider record. | +| Configuration | One provider and one model define sandbox inference. | +| Provider support | OpenAI, Anthropic, and NVIDIA providers all work through the same endpoint. | +| Hot-refresh | Provider credential changes and inference updates are picked up without recreating sandboxes. | ## Supported API Patterns -Supported request patterns depend on the provider configured for -`inference.local`. +Supported request patterns depend on the provider configured for `inference.local`. -For OpenAI-compatible providers, these patterns are supported: +:::::{tab-set} + +::::{tab-item} OpenAI-compatible | Pattern | Method | Path | |---|---|---| -| OpenAI Chat Completions | `POST` | `/v1/chat/completions` | -| OpenAI Completions | `POST` | `/v1/completions` | -| OpenAI Responses | `POST` | `/v1/responses` | +| Chat Completions | `POST` | `/v1/chat/completions` | +| Completions | `POST` | `/v1/completions` | +| Responses | `POST` | `/v1/responses` | | Model Discovery | `GET` | `/v1/models` | | Model Discovery | `GET` | `/v1/models/*` | -For Anthropic-compatible providers, this pattern is supported: +:::: + +::::{tab-item} Anthropic-compatible | Pattern | Method | Path | |---|---|---| -| Anthropic Messages | `POST` | `/v1/messages` | +| Messages | `POST` | `/v1/messages` | -Requests to `inference.local` that do not match the configured provider's -supported patterns are denied. +:::: -## Key Properties +::::: -- External endpoints use `network_policies`. -- Explicit local endpoint: special local routing happens through - `inference.local`. -- No sandbox API keys: credentials come from the configured provider record. -- Single managed config: one provider and one model define sandbox inference. -- Provider-agnostic: OpenAI, Anthropic, and NVIDIA providers all work through - the same endpoint. -- Hot-refresh: provider credential changes and inference updates are picked up - without recreating sandboxes. +Requests to `inference.local` that do not match the configured provider's supported patterns are denied. ## Next Steps -- {doc}`configure`: configure the backend behind `inference.local`. -- [Network policy evaluation](/safety-and-privacy/policies.md#network-policy-evaluation): - understand how external endpoints are controlled. +- **Ready to configure?** Set up the backend behind `inference.local` in {doc}`configure`. +- **Need to control external endpoints?** See [Network Access Rules](/sandboxes/index.md#network-access-rules). diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md deleted file mode 100644 index f545289c3f..0000000000 --- a/docs/reference/architecture.md +++ /dev/null @@ -1,207 +0,0 @@ ---- -title: - page: "Architecture Reference" - nav: "Architecture" -description: "Detailed reference for OpenShell architecture: gateway, sandbox internals, policy engine, privacy router, and remote deployment." -keywords: ["openshell architecture", "sandbox architecture", "agent isolation", "k3s", "policy engine"] -topics: ["generative_ai", "cybersecurity"] -tags: ["ai_agents", "sandboxing", "security", "architecture"] -content: - type: reference - difficulty: technical_advanced - audience: [engineer, data_scientist] ---- - - - -# Architecture Reference - -This page provides detailed technical information about each OpenShell component. -For a high-level summary, refer to the [Architecture Overview](../about/architecture.md). - -## Component Diagram - -```{mermaid} -graph TB - subgraph docker["Docker Container"] - subgraph k3s["k3s Cluster"] - gw["Gateway"] - pr["Privacy Router"] - - subgraph pod1["Sandbox"] - sup1["Supervisor"] - proxy1["L7 Proxy"] - pe1["Policy Engine"] - agent1["Agent"] - - sup1 --> proxy1 - sup1 --> agent1 - proxy1 --> pe1 - end - - subgraph pod2["Sandbox"] - sup2["Supervisor"] - proxy2["L7 Proxy"] - pe2["Policy Engine"] - agent2["Agent"] - - sup2 --> proxy2 - sup2 --> agent2 - proxy2 --> pe2 - end - - gw -- "credentials,
policies" --> sup1 - gw -- "credentials,
policies" --> sup2 - end - end - - cli["openshell CLI"] -- "gRPC" --> gw - agent1 -- "all outbound
traffic" --> proxy1 - agent2 -- "all outbound
traffic" --> proxy2 - proxy1 -- "policy-approved
traffic" --> internet["External Services"] - proxy2 -- "policy-approved
traffic" --> internet - proxy1 -- "inference traffic" --> pr - proxy2 -- "inference traffic" --> pr - pr -- "routed requests" --> backend["LLM Backend"] - - style cli fill:#ffffff,stroke:#000000,color:#000000 - style gw fill:#76b900,stroke:#000000,color:#000000 - style pr fill:#76b900,stroke:#000000,color:#000000 - style sup1 fill:#76b900,stroke:#000000,color:#000000 - style proxy1 fill:#76b900,stroke:#000000,color:#000000 - style pe1 fill:#76b900,stroke:#000000,color:#000000 - style agent1 fill:#ffffff,stroke:#000000,color:#000000 - style sup2 fill:#76b900,stroke:#000000,color:#000000 - style proxy2 fill:#76b900,stroke:#000000,color:#000000 - style pe2 fill:#76b900,stroke:#000000,color:#000000 - style agent2 fill:#ffffff,stroke:#000000,color:#000000 - style internet fill:#ffffff,stroke:#000000,color:#000000 - style backend fill:#ffffff,stroke:#000000,color:#000000 - style docker fill:#f5f5f5,stroke:#000000,color:#000000 - style k3s fill:#e8e8e8,stroke:#000000,color:#000000 - style pod1 fill:#f5f5f5,stroke:#000000,color:#000000 - style pod2 fill:#f5f5f5,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -## Gateway - -The gateway is the central control-plane API. It coordinates sandbox lifecycle -and state, acts as the auth boundary, and brokers all requests across the -platform. It exposes a gRPC API consumed by the CLI and handles: - -- Sandbox lifecycle: creates, monitors, and deletes sandbox pods. -- Provider storage: stores encrypted provider credentials. -- Policy distribution: delivers policy YAML to sandboxes at startup and on - hot-reload. -- SSH termination: terminates SSH tunnels from the CLI and routes them to - the correct sandbox. - -The CLI never talks to sandbox pods directly. All commands go through the -gateway. - -## Sandbox - -Each sandbox is an isolated runtime that includes container supervision and -general L7 egress routing. It runs as a Kubernetes pod containing a supervisor -process, an L7 proxy, and the agent. - -### Supervisor - -The supervisor is the sandbox's init process. It establishes all isolation -boundaries before starting the agent: - -1. Fetch credentials from the gateway for all attached providers. -2. Set up the network namespace. The sandbox gets its own network stack - with no default route. All outbound traffic is redirected through the proxy. -3. Apply Landlock filesystem restrictions based on the policy. -4. Apply seccomp filters to restrict available system calls. -5. Start the L7 proxy in the sandbox's network namespace. -6. Start the SSH server for interactive access. -7. Start the agent as a child process with credentials injected as - environment variables. - -### L7 Proxy - -Every outbound TCP connection from any process in the sandbox is routed through -the proxy. For each connection, the proxy: - -1. Resolves the calling binary through `/proc//exe`, ancestor process - walking, and `/proc//cmdline`. -2. Queries the policy engine with the destination host, port, and resolved - binary path. -3. Acts on the decision: allow the connection directly, hand it to the - privacy router for inference routing, or deny it. Refer to - {doc}`../safety-and-privacy/policies` for the full decision model. - -For endpoints configured with `protocol: rest` and `tls: terminate`, the proxy -performs full L7 inspection: it decrypts TLS, reads the HTTP method and path, -evaluates access rules, then re-encrypts and forwards the request. - -## Policy Engine - -The policy engine is the definition and enforcement layer for filesystem, -network, and process constraints. Defense in depth enforces policies from the -application layer down to infrastructure and kernel layers. - -The engine evaluates policies compiled from the sandbox's policy YAML. It is -queried synchronously by the proxy on every outbound connection. Policy updates -delivered through hot-reload are compiled and loaded without restarting the proxy. - -## Privacy Router - -The privacy router is a privacy-aware LLM routing layer that keeps sensitive -context on sandbox compute and routes based on cost/privacy policy. - -When the policy engine determines that a connection should be inspected for -inference, the privacy router: - -1. Reads the intercepted HTTP request. -2. Checks whether the method and path match a recognized inference API pattern - (`/v1/chat/completions`, `/v1/completions`, `/v1/messages`). -3. Selects a route whose `routing_hint` appears in the sandbox policy's - `allowed_routes`. -4. Strips the original authorization header. -5. Injects the route's API key and model ID. -6. Forwards the request to the route's backend URL. - -The router refreshes its route list periodically from the gateway, so routes -created with `openshell inference create` become available without restarting -sandboxes. - -## Remote Deployment - -OpenShell can deploy the cluster to a remote host via SSH. This is useful for -shared team environments or running sandboxes on machines with more resources. - -### Deploy - -```console -$ openshell gateway start --remote user@host --ssh-key ~/.ssh/id_rsa -``` - -The CLI connects to the remote machine over SSH, installs k3s, deploys the -OpenShell control plane, and registers the cluster locally. The remote machine -needs Docker installed. - -### Tunnel - -After deploying to a remote host, set up a tunnel for CLI access: - -```console -$ openshell gateway tunnel -``` - -This establishes an SSH tunnel from your local machine to the remote cluster's -API server. All subsequent CLI commands route through this tunnel transparently. - -### Remote Architecture - -The architecture is identical to a local deployment. The only difference is -that the Docker container runs on the remote host instead of your workstation. -The CLI communicates with the gateway over the SSH tunnel. Sandbox SSH -connections are also tunneled through the gateway. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index e8ae9d5fe5..0b38bf56e3 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -5,22 +5,19 @@ # CLI Reference -Complete command reference for the `openshell` CLI. Every subcommand, flag, and option is documented here. +Complete command reference for the `nemoclaw` CLI. Every subcommand, flag, and option is documented here. ## Command Tree ```text -openshell +nemoclaw ├── status ├── logs [name] +├── term ├── forward │ ├── start │ ├── stop │ └── list -├── policy -│ ├── set -│ ├── get -│ └── list ├── gateway │ ├── start │ ├── stop @@ -37,6 +34,10 @@ openshell │ ├── upload [name] │ ├── download [name] │ └── ssh-config +├── policy +│ ├── set +│ ├── get +│ └── list ├── provider │ ├── create │ ├── get @@ -47,24 +48,22 @@ openshell │ ├── set │ ├── update │ └── get -├── term └── completions ``` -## Top-Level Commands +:::{tip} +Commands that accept an optional `[name]` argument — such as `get`, `connect`, `upload`, `download`, and `logs` — fall back to the last-used sandbox when the name is omitted. The CLI records the sandbox name each time you create or connect, and prints a hint showing which sandbox was selected. +::: -Commands available directly under `openshell` for common operations. +## Status, Logs, and Terminal | Command | Description | |---|---| -| `openshell status` | Show the health and status of the active gateway. | -| `openshell logs [name]` | View sandbox logs. Use `--tail` for streaming, `--source` and `--level` to filter. When name is omitted, uses the last-used sandbox. | -| `openshell forward start ` | Forward a sandbox port to the host. Add `-d` for background mode. | -| `openshell forward stop ` | Stop an active port forward. | -| `openshell forward list` | List all active port forwards. | -| `openshell policy set ` | Apply or update a policy on a running sandbox. Pass `--policy `. | -| `openshell policy get ` | Show the active policy for a sandbox. Add `--full` for the complete policy with metadata. | -| `openshell policy list ` | List all policy versions applied to a sandbox, with status. | +| `nemoclaw status` | Show the health and status of the active gateway. | +| `nemoclaw logs [name]` | View sandbox logs. Use `--tail` for streaming, `--source` and `--level` to filter. | +| `nemoclaw term` | Launch the OpenShell Terminal — a dashboard showing sandbox status, live logs, and policy decisions in a single view. Navigate with `j`/`k`, press `f` to follow live output, `s` to filter by source, and `q` to quit. | + +Refer to {doc}`/sandboxes/create-and-manage` for more on monitoring sandboxes and reading log entries. ## Gateway Commands @@ -72,13 +71,13 @@ Manage the OpenShell runtime cluster. | Command | Description | |---|---| -| `openshell gateway start` | Deploy a new cluster. Add `--remote user@host` for remote deployment. | -| `openshell gateway stop` | Stop the active cluster, preserving state. | -| `openshell gateway destroy` | Permanently remove the cluster and all its data. | -| `openshell gateway info` | Show detailed information about the cluster. | -| `openshell gateway tunnel` | Set up a kubectl tunnel to a remote cluster. | -| `openshell gateway select ` | Set the active cluster. All subsequent commands target this cluster. | -| `openshell gateway select` | List all registered clusters (when called without a name). | +| `nemoclaw gateway start` | Deploy a new cluster. Add `--remote user@host` for remote deployment. | +| `nemoclaw gateway stop` | Stop the active cluster, preserving state. | +| `nemoclaw gateway destroy` | Permanently remove the cluster and all its data. | +| `nemoclaw gateway info` | Show detailed information about the cluster. | +| `nemoclaw gateway tunnel` | Set up a kubectl tunnel to a remote cluster. | +| `nemoclaw gateway select ` | Set the active cluster. All subsequent commands target this cluster. | +| `nemoclaw gateway select` | List all registered clusters (when called without a name). | ## Sandbox Commands @@ -86,14 +85,14 @@ Create and manage isolated agent execution environments. | Command | Description | |---|---| -| `openshell sandbox create` | Create a new sandbox. See flag reference below. | -| `openshell sandbox get [name]` | Show detailed information about a sandbox. When name is omitted, uses the last-used sandbox. | -| `openshell sandbox list` | List all sandboxes in the active cluster. | -| `openshell sandbox delete ` | Delete one or more sandboxes by name. | -| `openshell sandbox connect [name]` | Open an interactive SSH session into a running sandbox. When name is omitted, reconnects to the last-used sandbox. | -| `openshell sandbox upload [name]` | Upload files from the host into a sandbox. When name is omitted, uses the last-used sandbox. | -| `openshell sandbox download [name]` | Download files from a sandbox to the host. When name is omitted, uses the last-used sandbox. | -| `openshell sandbox ssh-config ` | Print SSH config for a sandbox. Append to `~/.ssh/config` for VS Code Remote-SSH. | +| `nemoclaw sandbox create` | Create a new sandbox. See flag reference below. | +| `nemoclaw sandbox get [name]` | Show detailed information about a sandbox. | +| `nemoclaw sandbox list` | List all sandboxes in the active cluster. | +| `nemoclaw sandbox delete ` | Delete one or more sandboxes by name. | +| `nemoclaw sandbox connect [name]` | Open an interactive SSH session into a running sandbox. | +| `nemoclaw sandbox upload [name]` | Upload files from the host into a sandbox. | +| `nemoclaw sandbox download [name]` | Download files from a sandbox to the host. | +| `nemoclaw sandbox ssh-config ` | Print SSH config for a sandbox. Append to `~/.ssh/config` for VS Code Remote-SSH. | ### Sandbox Create Flags @@ -108,17 +107,37 @@ Create and manage isolated agent execution environments. | `--from` | Build from a community sandbox name, local Dockerfile directory, or container image reference. | | `-- ` | The command to run inside the sandbox. Everything after `--` is passed as the agent command. | +## Policy Commands + +Apply and inspect sandbox policies at runtime. + +| Command | Description | +|---|---| +| `nemoclaw policy set ` | Apply or update a policy on a running sandbox. Pass `--policy `. | +| `nemoclaw policy get ` | Show the active policy for a sandbox. Add `--full` for the complete policy with metadata. | +| `nemoclaw policy list ` | List all policy versions applied to a sandbox, with status. | + +## Port Forwarding Commands + +Forward sandbox ports to the host for local access. + +| Command | Description | +|---|---| +| `nemoclaw forward start ` | Forward a sandbox port to the host. Add `-d` for background mode. | +| `nemoclaw forward stop ` | Stop an active port forward. | +| `nemoclaw forward list` | List all active port forwards. | + ## Provider Commands Manage credential providers that inject secrets into sandboxes. | Command | Description | |---|---| -| `openshell provider create` | Create a new credential provider. See flag reference below. | -| `openshell provider get ` | Show details of a provider. | -| `openshell provider list` | List all providers in the active cluster. | -| `openshell provider update ` | Update a provider's credentials or configuration. | -| `openshell provider delete ` | Delete a provider. | +| `nemoclaw provider create` | Create a new credential provider. See flag reference below. | +| `nemoclaw provider get ` | Show details of a provider. | +| `nemoclaw provider list` | List all providers in the active cluster. | +| `nemoclaw provider update ` | Update a provider's credentials or configuration. | +| `nemoclaw provider delete ` | Delete a provider. | ### Provider Create Flags @@ -134,7 +153,7 @@ Manage credential providers that inject secrets into sandboxes. Configure the backend used by `https://inference.local`. -### `openshell inference set` +### `nemoclaw inference set` Set the provider and model for managed inference. Both flags are required. @@ -143,7 +162,7 @@ Set the provider and model for managed inference. Both flags are required. | `--provider` | Provider record name to use for injected credentials. | | `--model` | Model identifier to force on generation requests. | -### `openshell inference update` +### `nemoclaw inference update` Update only the fields you specify. @@ -152,56 +171,41 @@ Update only the fields you specify. | `--provider` | Replace the current provider record. | | `--model` | Replace the current model ID. | -### `openshell inference get` - -Show the current inference configuration, including provider, model, and -version. - -## OpenShell Terminal - -`openshell term` launches the OpenShell Terminal, a dashboard that shows sandbox -status, live logs, and policy decisions in a single view. Navigate with `j`/`k`, -press `f` to follow live output, `s` to filter by source, and `q` to quit. - -Refer to {doc}`/sandboxes/create-and-manage` for more on monitoring sandboxes and reading log entries. - -## Sandbox Name Fallback - -Commands that accept an optional `[name]` argument, such as `get`, `connect`, `upload`, `download`, and `logs`, fall back to the last-used sandbox when the name is omitted. The CLI records the sandbox name each time you create or connect to a sandbox. When falling back, the CLI prints a hint showing which sandbox was selected. +### `nemoclaw inference get` -If no sandbox has been used yet and no name is provided, the command exits with an error prompting you to specify a name. +Show the current inference configuration, including provider, model, and version. ## Environment Variables | Variable | Description | |---|---| -| `OPENSHELL_CLUSTER` | Name of the cluster to operate on. Overrides the active cluster set by `openshell gateway select`. | -| `OPENSHELL_SANDBOX_POLICY` | Default path to a policy YAML file. When set, `openshell sandbox create` uses this policy if no `--policy` flag is provided. | +| `NEMOCLAW_CLUSTER` | Name of the cluster to operate on. Overrides the active cluster set by `nemoclaw gateway select`. | +| `NEMOCLAW_SANDBOX_POLICY` | Default path to a policy YAML file. When set, `nemoclaw sandbox create` uses this policy if no `--policy` flag is provided. | ## Shell Completions Generate shell completion scripts for tab completion: ```console -$ openshell completions bash -$ openshell completions zsh -$ openshell completions fish +$ nemoclaw completions bash +$ nemoclaw completions zsh +$ nemoclaw completions fish ``` Pipe the output to your shell's config file: ```console -$ openshell completions zsh >> ~/.zshrc +$ nemoclaw completions zsh >> ~/.zshrc $ source ~/.zshrc ``` -## Self-Teaching +## Built-in Help Every command and subcommand includes built-in help. Use `--help` at any level to see available subcommands, flags, and usage examples: ```console -$ openshell --help -$ openshell sandbox --help -$ openshell sandbox create --help -$ openshell gateway --help +$ nemoclaw --help +$ nemoclaw sandbox --help +$ nemoclaw sandbox create --help +$ nemoclaw gateway --help ``` diff --git a/docs/reference/default-policy.md b/docs/reference/default-policy.md index 5c80d15231..5b47624249 100644 --- a/docs/reference/default-policy.md +++ b/docs/reference/default-policy.md @@ -2,6 +2,22 @@ The default policy is the policy applied when you create an OpenShell sandbox without `--policy`. It is defined in the [`deploy/docker/sandbox/dev-sandbox-policy.yaml`](https://github.com/NVIDIA/OpenShell/blob/main/deploy/docker/sandbox/dev-sandbox-policy.yaml) file. +## Agent Compatibility + +The following table shows the coverage of the default policy for common agents. + +| Agent | Coverage | Action Required | +|---|---|---| +| Claude Code | Full | None. Works out of the box. | +| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. | +| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | + +:::{important} +If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. +::: + +## Default Policy Blocks + The following tables show the default policy blocks pre-configured in the file. ```{policy-table} deploy/docker/sandbox/dev-sandbox-policy.yaml diff --git a/docs/reference/policy-schema.md b/docs/reference/policy-schema.md index 8c5aa308c5..2f388ed18d 100644 --- a/docs/reference/policy-schema.md +++ b/docs/reference/policy-schema.md @@ -132,7 +132,7 @@ Each endpoint defines a reachable destination and optional inspection rules. |---|---|---|---| | `host` | string | Yes | Hostname or IP address. Supports wildcards: `*.example.com` matches any subdomain. | | `port` | integer | Yes | TCP port number. | -| `protocol` | string | No | Set to `rest` to enable L7 (HTTP) inspection. Omit for L4-only (TCP passthrough). | +| `protocol` | string | No | Set to `rest` to enable HTTP request inspection. Omit for TCP passthrough. | | `tls` | string | No | TLS handling mode. `terminate` decrypts TLS at the proxy for inspection. `passthrough` forwards encrypted traffic without inspection. Only relevant when `protocol` is `rest`. | | `enforcement` | string | No | `enforce` actively blocks disallowed requests. `audit` logs violations but allows traffic through. | | `access` | string | No | HTTP access level. One of `read-only`, `read-write`, or `full`. Mutually exclusive with `rules`. | diff --git a/docs/safety-and-privacy/default-policies.md b/docs/safety-and-privacy/default-policies.md deleted file mode 100644 index f32ef9195e..0000000000 --- a/docs/safety-and-privacy/default-policies.md +++ /dev/null @@ -1,36 +0,0 @@ - - -# Built-in Default Policy - -NVIDIA OpenShell ships a built-in policy that covers common agent workflows out of the box. -When you create a sandbox without `--policy`, OpenShell applies the default policy. This policy controls three things: - -- What the agent can access on disk. Filesystem paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. -- What the agent can reach on the network. Each network policy block pairs a set of allowed destinations (host and port) with a set of allowed binaries (executable paths inside the sandbox). The proxy resolves every outbound connection to the binary that opened it. A connection is allowed only when both the destination and the calling binary match an entry in the same block. Everything else is denied. -- What privileges the agent has. The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. There is no `sudo`, no `setuid`, and no path to elevated privileges. - -## Agent Compatibility - -The following table shows the coverage of the default policy for common agents. - -| Agent | Coverage | Action Required | -|---|---|---| -| Claude Code | Full | None. Works out of the box. | -| OpenCode | Partial | Add `opencode.ai` endpoint and OpenCode binary paths. See [Run OpenCode with NVIDIA Inference](../get-started/run-opencode.md). | -| Codex | None | Provide a complete custom policy with OpenAI endpoints and Codex binary paths. | - -:::{important} -If you run a non-Claude agent without a custom policy, the agent's API calls are denied by the proxy. You must provide a policy that declares the agent's endpoints and binaries. -::: - -## What the Default Policy Allows - -The default policy defines six network policy blocks, plus filesystem isolation, Landlock enforcement, and process identity. For the full breakdown of each block, see {doc}`../reference/default-policy`. - -## Next Steps - -- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. -- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. diff --git a/docs/safety-and-privacy/index.md b/docs/safety-and-privacy/index.md deleted file mode 100644 index f647b49e52..0000000000 --- a/docs/safety-and-privacy/index.md +++ /dev/null @@ -1,90 +0,0 @@ - - -# About Safety and Privacy - -OpenShell wraps every sandbox in four independent protection layers. No single -point of failure can compromise your environment. Each layer covers gaps the -others cannot. - -```{mermaid} -graph TB - subgraph runtime["OpenShell Runtime"] - direction TB - - subgraph layers["Protection Layers"] - direction TB - - fs["Filesystem — Landlock LSM"] - net["Network — Proxy + Policy Engine"] - proc["Process — seccomp + Unprivileged User"] - inf["Inference — Privacy Router"] - - subgraph sandbox["Sandbox"] - agent(["AI Agent"]) - end - end - end - - agent -- "read /sandbox ✔" --> fs - agent -- "read /etc/shadow ✘" --> fs - agent -- "curl approved.com ✔" --> net - agent -- "curl evil.com ✘" --> net - agent -- "sudo install pkg ✘" --> proc - agent -- "call api.openai.com" --> inf - inf -- "reroute → your backend ✔" --> net - - style runtime fill:#f5f5f5,stroke:#000000,color:#000000 - style layers fill:#e8e8e8,stroke:#000000,color:#000000 - style sandbox fill:#f5f5f5,stroke:#000000,color:#000000 - style agent fill:#ffffff,stroke:#000000,color:#000000 - style fs fill:#76b900,stroke:#000000,color:#000000 - style net fill:#76b900,stroke:#000000,color:#000000 - style proc fill:#76b900,stroke:#000000,color:#000000 - style inf fill:#76b900,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -## How the Layers Work Together - -You control all four layers through a single YAML policy. - -| Layer | What It Protects | When It Applies | -|---|---|---| -| **Filesystem** (Landlock LSM) | Prevents reads/writes outside allowed paths. | Locked at sandbox creation. | -| **Network** (Proxy + Policy Engine) | Blocks unauthorized outbound connections. | Hot-reloadable at runtime. | -| **Process** (seccomp + unprivileged user) | Blocks privilege escalation and dangerous syscalls. | Locked at sandbox creation. | -| **Inference** (Privacy Router) | Reroutes API calls to backends you control. | Hot-reloadable at runtime. | - -Filesystem and process restrictions are locked at creation time. Network and -inference rules are hot-reloadable on a running sandbox, so you can iterate on -access rules without recreating the sandbox. - -## Threat Scenarios - -When an AI agent runs with unrestricted access, it can read any file, reach any -network host, call any API with your credentials, and install arbitrary software. -The table below shows how the four layers address concrete threats. - -| Threat | Without Protection | With OpenShell | -|---|---|---| -| **Data exfiltration** | Agent uploads source code to an external server via `curl`. | Network policy blocks all outbound connections except explicitly approved hosts. | -| **Credential theft** | Agent reads `~/.ssh/id_rsa` or `~/.aws/credentials` and exfiltrates them. | [Landlock](https://docs.kernel.org/security/landlock.html) limits the agent to declared paths (`/sandbox`, `/tmp`, read-only system dirs). | -| **Unauthorized API calls** | Agent calls `api.openai.com` with your key, sending data to a third-party provider. | Privacy router intercepts and reroutes calls to a backend you control. | -| **Privilege escalation** | Agent runs `sudo apt install`, modifies `/etc/passwd`, or scans the internal network. | Agent runs as an unprivileged user with seccomp filters; no `sudo`, no `setuid`. | - -:::{important} -All four layers work together. No single layer is sufficient on its own. -Filesystem restrictions do not prevent network exfiltration. Network policies do -not prevent local privilege escalation. Process restrictions do not control -where inference traffic goes. Defense in depth means every layer covers gaps -that the others cannot. -::: - -## Next Steps - -- {doc}`default-policies`: The built-in policy that ships with OpenShell and what each block allows. -- {doc}`policies`: Write custom policies, configure network rules, and iterate on a running sandbox. diff --git a/docs/safety-and-privacy/policies.md b/docs/safety-and-privacy/policies.md deleted file mode 100644 index e491b2f10d..0000000000 --- a/docs/safety-and-privacy/policies.md +++ /dev/null @@ -1,195 +0,0 @@ - - -# Policy Configuration - -A policy is a single YAML document that controls what a sandbox can do: filesystem access, process identity, network access, and inference routing. You attach it when creating a sandbox; the network and inference sections can be updated on a running sandbox without restarting. - -## Policy Structure - -A policy has five top-level sections: `version`, `filesystem_policy`, `landlock`, `process`, `network_policies`, and `inference`. Static sections (`filesystem_policy`, `landlock`, `process`) are locked at sandbox creation and require recreation to change. Dynamic sections (`network_policies`, `inference`) are hot-reloadable on a running sandbox. The `landlock` section configures [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforcement at the kernel level. - -```yaml -version: 1 - -# Static: locked at sandbox creation. Paths the agent can read vs read/write. -filesystem_policy: - read_only: [/usr, /lib, /etc] - read_write: [/sandbox, /tmp] - -# Static: Landlock LSM kernel enforcement. best_effort uses highest ABI the host supports. -landlock: - compatibility: best_effort - -# Static: Unprivileged user/group the agent process runs as. -process: - run_as_user: sandbox - run_as_group: sandbox - -# Dynamic: hot-reloadable. Named blocks of endpoints + binaries allowed to reach them. -network_policies: - my_api: - name: my-api - endpoints: - - host: api.example.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - access: full - binaries: - - path: /usr/bin/curl - -# Dynamic: hot-reloadable. Routing hints this sandbox can use for inference (e.g. local, nvidia). -inference: - allowed_routes: [local] -``` - -For the complete field reference, see the [Policy Schema Reference](../reference/policy-schema.md). - -## Network Policy Evaluation - -Every outbound connection from the sandbox goes through the proxy. The proxy matches the destination such as host and port and the calling binary to an endpoint in one of the `network_policies` blocks. - -- If an endpoint matches the destination and the binary is listed in that block's `binaries`, the connection is allowed. -- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is also checked against that endpoint's `rules` (method and path). -- If no endpoint matches and inference routes are configured, the request may be rerouted for inference. -- Otherwise the connection is denied. - -Endpoints without `protocol` or `tls` (L4-only) allow the TCP stream through without inspecting payloads. For the full endpoint schema, access presets, and binary matching, see the [Policy Schema Reference](../reference/policy-schema.md). - -## Example Policy for GitHub Repository Access - -The following policy block allows Claude and the GitHub CLI to reach `api.github.com` with granular per-endpoint rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for `alpha-repo`; and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. - -Add this block to the `network_policies` section of your sandbox policy. - -```yaml - github_repos: - name: github_repos - endpoints: - - host: api.github.com - port: 443 - protocol: rest - tls: terminate - enforcement: enforce - rules: - # Read-only access to all GitHub API paths - - allow: - method: GET - path: "/**" - - allow: - method: HEAD - path: "/**" - - allow: - method: OPTIONS - path: "/**" - # GraphQL API (used by gh CLI for most operations) - - allow: - method: POST - path: "/graphql" - # alpha-repo: full write access - - allow: - method: "*" - path: "/repos//alpha-repo/**" - # bravo-repo: create + edit issues - - allow: - method: POST - path: "/repos//bravo-repo/issues" - - allow: - method: PATCH - path: "/repos//bravo-repo/issues/*" - binaries: - - { path: /usr/local/bin/claude } - - { path: /usr/bin/gh } -``` - -Apply with `openshell policy set --policy --wait`. - -## Debug Denied Requests - -Check `openshell logs --tail --source sandbox` for the denied host, path, and binary. Add or adjust the matching endpoint or rules in the relevant policy block (for example, add a new `allow` rule for the method and path, or add the binary to that block's `binaries` list). See [Hot-Reload Policy Updates](#hot-reload-policy-updates) for the full iteration workflow. - -## Apply a Custom Policy - -Pass a policy YAML file when creating the sandbox: - -```console -$ openshell sandbox create --policy ./my-policy.yaml --keep -- claude -``` - -The `--keep` flag keeps the sandbox running after the initial command exits, which is useful when you plan to iterate on the policy. - -To avoid passing `--policy` every time, set a default policy with an environment variable: - -```console -$ export OPENSHELL_SANDBOX_POLICY=./my-policy.yaml -$ openshell sandbox create --keep -- claude -``` - -The CLI uses the policy from `OPENSHELL_SANDBOX_POLICY` whenever `--policy` is not explicitly provided. - -## Hot-Reload Policy Updates - -To change what the sandbox can access, pull the current policy, edit the YAML, and push the update. The workflow is iterative: create the sandbox, monitor logs for denied actions, pull the policy, modify it, push, and verify. - -```{mermaid} -flowchart TD - A["1. Create sandbox with initial policy"] --> B["2. Monitor logs for denied actions"] - B --> C["3. Pull current policy"] - C --> D["4. Modify the policy YAML"] - D --> E["5. Push updated policy"] - E --> F["6. Verify the new revision loaded"] - F --> B - - style A fill:#76b900,stroke:#000000,color:#000000 - style B fill:#76b900,stroke:#000000,color:#000000 - style C fill:#76b900,stroke:#000000,color:#000000 - style D fill:#ffffff,stroke:#000000,color:#000000 - style E fill:#76b900,stroke:#000000,color:#000000 - style F fill:#76b900,stroke:#000000,color:#000000 - - linkStyle default stroke:#76b900,stroke-width:2px -``` - -The following steps outline the hot-reload policy update workflow. - -1. Create the sandbox with your initial policy (or set `OPENSHELL_SANDBOX_POLICY`). - - ```console - $ openshell sandbox create --policy ./my-policy.yaml --keep -- claude - ``` - -2. Monitor denials — each log entry shows host, port, binary, and reason. Alternatively use `openshell term` for a live dashboard. - - ```console - $ openshell logs --tail --source sandbox - ``` - -3. Pull the current policy. Strip the metadata header (Version, Hash, Status) before reusing the file. - - ```console - $ openshell policy get --full > current-policy.yaml - ``` - -4. Edit the YAML: add or adjust `network_policies` entries, binaries, `access` or `rules`, or `inference.allowed_routes`. - -5. Push the updated policy. Exit codes: 0 = loaded, 1 = validation failed, 124 = timeout. - - ```console - $ openshell policy set --policy current-policy.yaml --wait - ``` - -6. Verify the new revision. If status is `loaded`, repeat from step 2 as needed; if `failed`, fix the policy and repeat from step 4. - - ```console - $ openshell policy list - ``` - -## Next Steps - -- {doc}`default-policies`: The built-in policy that ships with OpenShell and what each block allows. -- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. -- [Safety and Privacy](index.md): Threat scenarios and protection layers. diff --git a/docs/sandboxes/community-sandboxes.md b/docs/sandboxes/community-sandboxes.md index 6d3c11d3ca..3c09ff9ca9 100644 --- a/docs/sandboxes/community-sandboxes.md +++ b/docs/sandboxes/community-sandboxes.md @@ -90,5 +90,5 @@ or anything else), consider contributing it back so others can use it. ## Next Steps -- {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`../safety-and-privacy/policies`: Customize the policy applied to any sandbox +- **Need to supply API keys or tokens?** Set up {doc}`providers` for credential management. +- **Want to customize the sandbox policy?** Write custom rules in {doc}`policies`. diff --git a/docs/sandboxes/create-and-manage.md b/docs/sandboxes/create-and-manage.md index 21f9e6ad3e..292620ed48 100644 --- a/docs/sandboxes/create-and-manage.md +++ b/docs/sandboxes/create-and-manage.md @@ -7,17 +7,16 @@ This page walks you through the full sandbox lifecycle: creating, inspecting, connecting to, monitoring, and deleting sandboxes. For background on what sandboxes are and how the runtime works, refer to [About Sandboxes](index.md). -## Prerequisites - -Ensure the following are installed before creating sandboxes. - -- OpenShell CLI installed (`pip install openshell`) -- Docker running on your machine +:::{warning} +Docker must be running before you create a sandbox. If it isn't, the CLI +returns a connection-refused error (`os error 61`) without explaining +the cause. Start Docker and try again. +::: ## Create a Sandbox ```console -$ openshell sandbox create -- claude +$ nemoclaw sandbox create -- claude ``` If you have an existing gateway, a sandbox will be created within that gateway or if you don't have one, one will be created for you. @@ -26,7 +25,7 @@ If you have an existing gateway, a sandbox will be created within that gateway o A fully specified creation command might look like: ```console -$ openshell sandbox create \ +$ nemoclaw sandbox create \ --name dev \ --provider my-claude \ --policy policy.yaml \ @@ -41,6 +40,23 @@ This is especially useful when you are iterating on a policy or want to reconnect later from another terminal or VS Code. ::: +## Create from a Community Sandbox or Custom Image + +Use `--from` to create a sandbox from a pre-built community package, a local directory, or a container image: + +```console +$ nemoclaw sandbox create --from openclaw +``` + +The CLI resolves the name against the [NemoClaw Community](https://github.com/NVIDIA/NemoClaw-Community) catalog, pulls the bundled Dockerfile and policy, builds the image locally, and creates the sandbox. For the full catalog and how to contribute your own, refer to {doc}`community-sandboxes`. + +You can also point `--from` at a local directory or a container image reference: + +```console +$ nemoclaw sandbox create --from ./my-sandbox-dir +$ nemoclaw sandbox create --from my-registry.example.com/my-image:latest +``` + ## List and Inspect Sandboxes Check the status of your sandboxes and retrieve detailed information about individual ones. @@ -48,13 +64,13 @@ Check the status of your sandboxes and retrieve detailed information about indiv List all sandboxes: ```console -$ openshell sandbox list +$ nemoclaw sandbox list ``` Get detailed information about a specific sandbox: ```console -$ openshell sandbox get my-sandbox +$ nemoclaw sandbox get my-sandbox ``` ## Connect to a Sandbox @@ -66,7 +82,7 @@ Access a running sandbox through an interactive SSH session or VS Code Remote-SS Open an SSH session into a running sandbox: ```console -$ openshell sandbox connect my-sandbox +$ nemoclaw sandbox connect my-sandbox ``` ## View Logs @@ -76,24 +92,24 @@ Stream and filter sandbox logs to monitor agent activity and diagnose policy dec Stream sandbox logs: ```console -$ openshell logs my-sandbox +$ nemoclaw logs my-sandbox ``` Use flags to filter and follow output: | Flag | Purpose | Example | |---|---|---| -| `--tail` | Stream logs in real time | `openshell logs my-sandbox --tail` | +| `--tail` | Stream logs in real time | `nemoclaw logs my-sandbox --tail` | | `--source` | Filter by log source | `--source sandbox` | | `--level` | Filter by severity | `--level warn` | | `--since` | Show logs from a time window | `--since 5m` | ## Monitor your Sandbox -OpenShell Terminal is a real-time dashboard that combines sandbox status and live logs in a single view. +NemoClaw Terminal is a real-time dashboard that combines sandbox status and live logs in a single view. ```console -$ openshell term +$ nemoclaw term ``` The dashboard shows: @@ -101,7 +117,7 @@ The dashboard shows: - **Sandbox status** — name, phase, image, attached providers, age, and active port forwards. - **Live log stream** — outbound connections, policy decisions, and inference interceptions as they happen. Logs are labeled by source: `sandbox` (proxy and policy events) or `gateway` (lifecycle events). -Use the terminal to spot blocked connections (`action=deny` entries) and inference interceptions (`action=inspect_for_inference` entries). If a connection is blocked unexpectedly, add the host to your network policy — refer to {doc}`../safety-and-privacy/policies` for the workflow. +Use the terminal to spot blocked connections (`action=deny` entries) and inference interceptions (`action=inspect_for_inference` entries). If a connection is blocked unexpectedly, add the host to your network policy — refer to {doc}`policies` for the workflow. ## Transfer Files @@ -111,18 +127,18 @@ Transfer files between your host machine and a running sandbox. Upload files from your host into the sandbox: ```console -$ openshell sandbox upload my-sandbox ./src /sandbox/src +$ nemoclaw sandbox upload my-sandbox ./src /sandbox/src ``` Download files from the sandbox to your host: ```console -$ openshell sandbox download my-sandbox /sandbox/output ./local +$ nemoclaw sandbox download my-sandbox /sandbox/output ./local ``` :::{note} You can also upload files at creation time with the `--upload` flag on -`openshell sandbox create`. +`nemoclaw sandbox create`. ::: ## Delete Sandboxes @@ -132,11 +148,12 @@ Remove sandboxes when they are no longer needed. Deleting a sandbox stops all pr Delete a sandbox by name: ```console -$ openshell sandbox delete my-sandbox +$ nemoclaw sandbox delete my-sandbox ``` ## Next Steps -- {doc}`community-sandboxes`: Use pre-built sandboxes from the community catalog -- {doc}`providers`: Create and attach credential providers -- {doc}`../safety-and-privacy/policies`: Control what the agent can access \ No newline at end of file +- **Want a complete end-to-end example?** Follow the {doc}`/tutorials/github-sandbox` tutorial. +- **Need to supply API keys or tokens?** Set up {doc}`providers` for credential management. +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Want a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. \ No newline at end of file diff --git a/docs/sandboxes/index.md b/docs/sandboxes/index.md index b15ee9830c..9261a3e7f7 100644 --- a/docs/sandboxes/index.md +++ b/docs/sandboxes/index.md @@ -5,7 +5,7 @@ # About Sandboxes -A OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs inside a Kubernetes pod with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. +An OpenShell sandbox is a safe, private execution environment for an AI agent. Each sandbox runs with multiple layers of protection that prevent unauthorized data access, credential exposure, and network exfiltration. Protection layers include filesystem restrictions (Landlock), system call filtering (seccomp), network namespace isolation, and a privacy-enforcing HTTP CONNECT proxy. ## Sandbox Lifecycle @@ -15,24 +15,78 @@ Every sandbox moves through a defined set of phases: |---|---| | Provisioning | The runtime is setting up the sandbox environment, injecting credentials, and applying your policy. | | Ready | The sandbox is running. The agent process is active and all isolation layers are enforced. You can connect, sync files, and view logs. | -| Error | Something went wrong during provisioning or execution. Check logs with `openshell logs` for details. | +| Error | Something went wrong during provisioning or execution. Check logs with `nemoclaw logs` for details. | | Deleting | The sandbox is being torn down. The system releases resources and purges credentials. | -## The OpenShell Runtime +## Built-in Default Policy -Sandboxes run inside a lightweight runtime cluster that OpenShell manages for -you. The cluster runs as a [k3s](https://k3s.io/) Kubernetes distribution -inside a Docker container on your machine. +OpenShell ships a built-in policy that covers common agent workflows out of the box. +When you create a sandbox without `--policy`, the default policy is applied. It controls three things: -You do not need to set this up manually. The first time you run a command -that needs a cluster (such as `openshell sandbox create`), the CLI provisions -one automatically. +| Layer | What It Controls | How It Works | +|---|---|---| +| Filesystem | What the agent can access on disk | Paths are split into read-only and read-write sets. [Landlock LSM](https://docs.kernel.org/security/landlock.html) enforces these restrictions at the kernel level. | +| Network | What the agent can reach on the network | Each policy block pairs allowed destinations (host and port) with allowed binaries (executable paths). The proxy matches every outbound connection to the binary that opened it. Both must match or the connection is denied. | +| Process | What privileges the agent has | The agent runs as an unprivileged user with seccomp filters that block dangerous system calls. No `sudo`, no `setuid`, no path to elevated privileges. | + +For the full breakdown of each default policy block and agent compatibility details, see {doc}`../reference/default-policy`. + +## Policy Structure + +A policy has static sections (`filesystem_policy`, `landlock`, `process`) that are locked at sandbox creation, and dynamic sections (`network_policies`, `inference`) that are hot-reloadable on a running sandbox. + +```yaml +version: 1 + +# Static: locked at sandbox creation. Paths the agent can read vs read/write. +filesystem_policy: + read_only: [/usr, /lib, /etc] + read_write: [/sandbox, /tmp] + +# Static: Landlock LSM kernel enforcement. best_effort uses highest ABI the host supports. +landlock: + compatibility: best_effort + +# Static: Unprivileged user/group the agent process runs as. +process: + run_as_user: sandbox + run_as_group: sandbox + +# Dynamic: hot-reloadable. Named blocks of endpoints + binaries allowed to reach them. +network_policies: + my_api: + name: my-api + endpoints: + - host: api.example.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + access: full + binaries: + - path: /usr/bin/curl + +# Dynamic: hot-reloadable. Routing hints this sandbox can use for inference (e.g. local, nvidia). +inference: + allowed_routes: [local] +``` + +For the complete structure and every field, see the [Policy Schema Reference](../reference/policy-schema.md). + +## Network Access Rules + +Network access is controlled by policy blocks under `network_policies`. Each block has a **name**, a list of **endpoints** (host, port, protocol, and optional rules), and a list of **binaries** that are allowed to use those endpoints. + +Every outbound connection from the sandbox goes through the proxy: + +- The proxy queries the {doc}`policy engine <../about/architecture>` with the **destination** (host and port) and the **calling binary**. A connection is allowed only when both match an entry in the same policy block. +- For endpoints with `protocol: rest` and `tls: terminate`, each HTTP request is checked against that endpoint's `rules` (method and path). +- If no endpoint matches and inference routes are configured, the request may be rerouted for inference. +- Otherwise the connection is denied. Endpoints without `protocol` or `tls` allow the TCP stream through without inspecting payloads. ## Next Steps -- {doc}`create-and-manage`: Create, inspect, connect, monitor, and delete - sandboxes. -- {doc}`providers`: Create and attach credential providers so agents can - authenticate with external services. -- {doc}`community-sandboxes`: Use pre-built sandboxes from the community - catalog. +- **Ready to create your first sandbox?** Start with {doc}`create-and-manage`. +- **Need to supply API keys or tokens?** Set up {doc}`providers` before creating. +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Want a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. diff --git a/docs/sandboxes/policies.md b/docs/sandboxes/policies.md new file mode 100644 index 0000000000..02530c3df3 --- /dev/null +++ b/docs/sandboxes/policies.md @@ -0,0 +1,172 @@ + + +# Customize Sandbox Policies + +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.md). + +## Quick Start: Apply a Custom Policy + +Pass a policy YAML file when creating the sandbox: + +```console +$ openshell sandbox create --policy ./my-policy.yaml --keep -- claude +``` + +The `--keep` flag keeps the sandbox running after the initial command exits, which is useful when you plan to iterate on the policy. + +To avoid passing `--policy` every time, set a default policy with an environment variable: + +```console +$ export OPENSHELL_SANDBOX_POLICY=./my-policy.yaml +$ openshell sandbox create --keep -- claude +``` + +The CLI uses the policy from `OPENSHELL_SANDBOX_POLICY` whenever `--policy` is not explicitly provided. + +## Iterate on a Running Sandbox + +To change what the sandbox can access, pull the current policy, edit the YAML, and push the update. The workflow is iterative: create the sandbox, monitor logs for denied actions, pull the policy, modify it, push, and verify. + +```{mermaid} +flowchart TD + A["1. Create sandbox with initial policy"] --> B["2. Monitor logs for denied actions"] + B --> C["3. Pull current policy"] + C --> D["4. Modify the policy YAML"] + D --> E["5. Push updated policy"] + E --> F["6. Verify the new revision loaded"] + F --> B + + style A fill:#76b900,stroke:#000000,color:#000000 + style B fill:#76b900,stroke:#000000,color:#000000 + style C fill:#76b900,stroke:#000000,color:#000000 + style D fill:#ffffff,stroke:#000000,color:#000000 + style E fill:#76b900,stroke:#000000,color:#000000 + style F fill:#76b900,stroke:#000000,color:#000000 + + linkStyle default stroke:#76b900,stroke-width:2px +``` + +The following steps outline the hot-reload policy update workflow. + +1. Create the sandbox with your initial policy by following [Quick Start: Apply a Custom Policy](#quick-start-apply-a-custom-policy) above (or set `OPENSHELL_SANDBOX_POLICY`). + +2. Monitor denials — each log entry shows host, port, binary, and reason. Alternatively use `openshell term` for a live dashboard. + + ```console + $ openshell logs --tail --source sandbox + ``` + +3. Pull the current policy. Strip the metadata header (Version, Hash, Status) before reusing the file. + + ```console + $ openshell policy get --full > current-policy.yaml + ``` + +4. Edit the YAML: add or adjust `network_policies` entries, binaries, `access` or `rules`, or `inference.allowed_routes`. + +5. Push the updated policy. Exit codes: 0 = loaded, 1 = validation failed, 124 = timeout. + + ```console + $ openshell policy set --policy current-policy.yaml --wait + ``` + +6. Verify the new revision. If status is `loaded`, repeat from step 2 as needed; if `failed`, fix the policy and repeat from step 4. + + ```console + $ openshell policy list + ``` + +## Debug Denied Requests + +Check `openshell logs --tail --source sandbox` for the denied host, path, and binary. + +When triaging denied requests, check: + +- Destination host and port to confirm which endpoint is missing. +- Calling binary path to confirm which `binaries` entry needs to be added or adjusted. +- HTTP method and path (for REST endpoints) to confirm which `rules` entry needs to be added or adjusted. + +Then push the updated policy as described above. + +## Examples + +Add these blocks to the `network_policies` section of your sandbox policy. Apply with `openshell policy set --policy --wait`. +Use **Simple endpoint** for host-level allowlists and **Granular rules** for method/path control. + +:::::{tab-set} + +::::{tab-item} Simple endpoint +Allow `pip install` and `uv pip install` to reach PyPI: + +```yaml + pypi: + name: pypi + endpoints: + - host: pypi.org + port: 443 + - host: files.pythonhosted.org + port: 443 + binaries: + - { path: /usr/bin/pip } + - { path: /usr/local/bin/uv } +``` + +Endpoints without `protocol` or `tls` use TCP passthrough — the proxy allows the stream without inspecting payloads. +:::: + +::::{tab-item} Granular rules +Allow Claude and the GitHub CLI to reach `api.github.com` with per-path rules: read-only (GET, HEAD, OPTIONS) and GraphQL (POST) for all paths; full write access for `alpha-repo`; and create/edit issues only for `bravo-repo`. Replace `` with your GitHub org or username. + +:::{tip} +For an end-to-end walkthrough that combines this policy with a GitHub credential provider and sandbox creation, see {doc}`/tutorials/github-sandbox`. +::: + +```yaml + github_repos: + name: github_repos + endpoints: + - host: api.github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + - allow: + method: GET + path: "/**" + - allow: + method: HEAD + path: "/**" + - allow: + method: OPTIONS + path: "/**" + - allow: + method: POST + path: "/graphql" + - allow: + method: "*" + path: "/repos//alpha-repo/**" + - allow: + method: POST + path: "/repos//bravo-repo/issues" + - allow: + method: PATCH + path: "/repos//bravo-repo/issues/*" + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/bin/gh } +``` + +Endpoints with `protocol: rest` and `tls: terminate` enable HTTP request inspection — the proxy decrypts TLS and checks each HTTP request against the `rules` list. +:::: + +::::: + +## Next Steps + +- **New to policies?** Read about {doc}`policy structure and network access rules ` first. +- **Need the full field reference?** See the [Policy Schema Reference](../reference/policy-schema.md). +- **Looking for the default policy breakdown?** See {doc}`../reference/default-policy`. diff --git a/docs/sandboxes/providers.md b/docs/sandboxes/providers.md index 5c9e84627d..b4c812a829 100644 --- a/docs/sandboxes/providers.md +++ b/docs/sandboxes/providers.md @@ -111,7 +111,7 @@ The following provider types are supported. | `claude` | `ANTHROPIC_API_KEY`, `CLAUDE_API_KEY` | Claude Code, Anthropic API | | `codex` | `OPENAI_API_KEY` | OpenAI Codex | | `opencode` | `OPENCODE_API_KEY`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY` | opencode tool | -| `github` | `GITHUB_TOKEN`, `GH_TOKEN` | GitHub API, `gh` CLI | +| `github` | `GITHUB_TOKEN`, `GH_TOKEN` | GitHub API, `gh` CLI — see {doc}`/tutorials/github-sandbox` | | `gitlab` | `GITLAB_TOKEN`, `GLAB_TOKEN`, `CI_JOB_TOKEN` | GitLab API, `glab` CLI | | `nvidia` | `NVIDIA_API_KEY` | NVIDIA API Catalog | | `generic` | User-defined | Any service with custom credentials | @@ -124,5 +124,6 @@ environment variable names and values yourself with `--credential`. ## Next Steps -- {doc}`create-and-manage`: Full sandbox lifecycle management -- {doc}`../safety-and-privacy/index`: Why credential isolation matters \ No newline at end of file +- **Want to control what the agent can access?** Write a custom policy in {doc}`policies`. +- **Looking for a pre-built environment?** Browse the {doc}`community-sandboxes` catalog. +- [Policy Schema Reference](../reference/policy-schema.md): Complete field reference for the policy YAML. \ No newline at end of file diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 28a8bea5e6..0000000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,135 +0,0 @@ - - -# Troubleshooting - -Use this guide to troubleshoot problems with OpenShell. - -## Cluster Issues - -Troubleshoot problems with deploying, connecting to, and running OpenShell clusters. - -### Cluster Deploy Fails - -**Symptom:** `openshell gateway start` exits with an error. - -**Check:** -1. Is Docker running? The cluster requires Docker to be active. -2. Is the port already in use? Try a different port: `--port 8081`. -3. Does a stale container exist? Destroy and redeploy: `openshell gateway destroy && openshell gateway start`. - -### Cluster Not Reachable - -**Symptom:** `openshell status` fails to connect. - -**Check:** -1. Is the cluster container running? `docker ps | grep openshell`. -2. Was the cluster stopped? Redeploy: `openshell gateway start`. -3. For remote clusters, is the SSH connection working? - -### Health Check Fails During Deploy - -**Symptom:** Deploy hangs or times out waiting for health checks. - -**Check:** -1. View container logs: `docker logs openshell-cluster`. -2. Check if k3s started: the bootstrap process waits up to 180 attempts (six minutes) for cluster readiness. -3. Look for resource constraints. k3s needs sufficient memory and disk. - -## Sandbox Issues - -Troubleshoot problems with creating, connecting to, and configuring sandboxes. - -### Sandbox Stuck in Provisioning - -**Symptom:** Sandbox shows `Provisioning` status and does not become `Ready`. - -**Check:** -1. View sandbox logs: `openshell logs --source gateway`. -2. Check if the container image can be pulled. -3. For custom images, verify the image was pushed: `openshell sandbox image push`. - -### Cannot Connect to Sandbox - -**Symptom:** `openshell sandbox connect ` fails. - -**Check:** -1. Is the sandbox in `Ready` state? `openshell sandbox get `. -2. Is SSH accessible? The tunnel goes through the gateway. Verify cluster connectivity first. - -### Network Requests Denied - -**Symptom:** The agent cannot reach a remote host. - -**Check:** -1. Stream sandbox logs: `openshell logs --tail --source sandbox`. -2. Look for `deny` actions. They include the destination, binary, and reason. -3. Update the policy to allow the blocked endpoint. Refer to [](safety-and-privacy/policies.md). - -### Policy Update Fails - -**Symptom:** `openshell policy set` returns an error or the status shows `failed`. - -**Check:** -1. Are you changing a static field? `filesystem_policy`, `landlock`, and `process` cannot change after creation. -2. Are you adding/removing `network_policies` to change the network mode? This is not allowed. The mode is fixed at creation. -3. Check the error message in `openshell policy list `. - -## Provider Issues - -Troubleshoot problems with provider credential discovery and injection into sandboxes. - -### Provider Discovery Finds No Credentials - -**Symptom:** `--from-existing` creates a provider with no credentials. - -**Check:** -1. Are the expected environment variables set? (for example, `ANTHROPIC_API_KEY` for Claude). -2. Do the expected config files exist? (for example, `~/.claude.json`). -3. Try explicit credentials: `--credential ANTHROPIC_API_KEY=sk-...`. - -### Sandbox Missing Credentials - -**Symptom:** Environment variables for a provider are not set inside the sandbox. - -**Check:** -1. Was the provider attached? `openshell sandbox get `. Check the providers list. -2. Does the provider have credentials? `openshell provider get `. -3. Are the credential keys valid env var names? Keys with dots, dashes, or spaces are silently skipped. - -## Custom Container Issues - -Troubleshoot problems with building and running custom container images in sandboxes. - -### Custom Image Fails to Start - -**Symptom:** Sandbox with `--from ` goes to `Error` state. - -**Check:** -1. Is the image pushed to the cluster? `openshell sandbox image push --dockerfile ./Dockerfile --tag my-image`. -2. Does the image have glibc and `/proc`? Distroless / `FROM scratch` images are not supported. -3. For proxy mode, does the image have `iproute2`? Network namespace setup requires it. - -## Port Forwarding Issues - -Troubleshoot problems with forwarding local ports into sandbox services. - -### Port Forward Not Working - -**Symptom:** `localhost:` does not connect to the sandbox service. - -**Check:** -1. Is the forward running? `openshell forward list`. -2. Is the service listening on that port inside the sandbox? -3. Is the sandbox still in `Ready` state? -4. Try stopping and restarting: `openshell forward stop && openshell forward start -d`. - -## Getting More Information - -Use these techniques to gather additional diagnostic detail when troubleshooting. - -- Increase CLI verbosity: `openshell -vvv ` for trace-level output. -- View gateway-side logs: `openshell logs --source gateway`. -- View sandbox-side logs: `openshell logs --source sandbox --level debug`. diff --git a/docs/tutorials/github-sandbox.md b/docs/tutorials/github-sandbox.md new file mode 100644 index 0000000000..64b311c9cd --- /dev/null +++ b/docs/tutorials/github-sandbox.md @@ -0,0 +1,308 @@ + + +# Set Up a Sandbox with GitHub Repo Access + +Agents often need to work across multiple repositories with different levels of trust. An agent might need full read-write access to a feature repo where it commits code, but only read access to a shared library repo that it references without modifying. OpenShell policies let you express this distinction — the agent can clone and push to one repo while treating another as a read-only dependency. + +This tutorial sets up exactly that scenario: + +- **alpha-repo** — the agent's working repo. Full read-write access: clone, push, create PRs and issues. +- **bravo-repo** — a reference repo. Read-only access: clone and browse, but push and write API calls are denied. + +Access is locked to these two repos. The agent cannot clone, fetch, or call the API for any other repository on GitHub. + +By the end you will have: + +- A GitHub credential provider injecting your token into the sandbox +- A policy that extends the default with scoped GitHub access to exactly two repos +- A running sandbox where Claude Code, OpenCode, and the `gh` CLI can all interact with GitHub + +## Prerequisites + +Before you begin, make sure you have: + +- Completed the {doc}`Quickstart
` (CLI installed, Docker running) +- A GitHub personal access token (PAT) with `repo` scope, exported as `GITHUB_TOKEN` +- Your agent's API key set (e.g., `ANTHROPIC_API_KEY` for Claude Code) + +## Step 1: Create a GitHub Provider + +:::{admonition} Already have a sandbox running? +:class: tip + +If you followed the Quickstart and already have a sandbox without a GitHub provider, you have two options: + +1. **Add a provider to a new sandbox** — delete the existing sandbox, create the provider below, and recreate the sandbox with `--provider my-github` in Step 3. +2. **Set the token inside the sandbox** — connect with `nemoclaw sandbox connect ` and run `export GITHUB_TOKEN=`. This skips the provider workflow but the token is not persisted across sandbox recreations. +::: + +Create a provider that reads your GitHub token from the environment: + +```console +$ nemoclaw provider create --name my-github --type github --from-existing +``` + +This reads `GITHUB_TOKEN` (and `GH_TOKEN` if set) from your shell and stores them in the provider. The sandbox receives these as environment variables at runtime. + +For more on provider types, see {doc}`/sandboxes/providers`. + +## Step 2: Write the Policy + +Create a file called `github-policy.yaml`. This policy starts from the {doc}`default policy ` and replaces the GitHub blocks with scoped rules that grant read-write access to `alpha-repo` and read-only access to `bravo-repo`. + +Replace `` throughout with your GitHub organization or username. + +```yaml +version: 1 + +# ── Static (locked at sandbox creation) ────────────────────────── + +filesystem_policy: + include_workdir: true + read_only: + - /usr + - /lib + - /proc + - /dev/urandom + - /app + - /etc + - /var/log + read_write: + - /sandbox + - /tmp + - /dev/null + +landlock: + compatibility: best_effort + +process: + run_as_user: sandbox + run_as_group: sandbox + +# ── Dynamic (hot-reloadable) ───────────────────────────────────── + +network_policies: + + # Claude Code ↔ Anthropic API + claude_code: + name: claude-code + endpoints: + - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full, tls: terminate } + - { host: statsig.anthropic.com, port: 443 } + - { host: sentry.io, port: 443 } + - { host: raw.githubusercontent.com, port: 443 } + - { host: platform.claude.com, port: 443 } + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/bin/node } + + # NVIDIA inference endpoint + nvidia_inference: + name: nvidia-inference + endpoints: + - { host: integrate.api.nvidia.com, port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /bin/bash } + - { path: /usr/local/bin/opencode } + + # ── GitHub: git operations (clone, fetch, push) ────────────── + + github_git: + name: github-git + endpoints: + - host: github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + # alpha-repo: clone, fetch, and push + - allow: + method: GET + path: "//alpha-repo.git/info/refs*" + - allow: + method: POST + path: "//alpha-repo.git/git-upload-pack" + - allow: + method: POST + path: "//alpha-repo.git/git-receive-pack" + # bravo-repo: clone and fetch only (no push) + - allow: + method: GET + path: "//bravo-repo.git/info/refs*" + - allow: + method: POST + path: "//bravo-repo.git/git-upload-pack" + binaries: + - { path: /usr/bin/git } + + # ── GitHub: REST API ───────────────────────────────────────── + + github_api: + name: github-api + endpoints: + - host: api.github.com + port: 443 + protocol: rest + tls: terminate + enforcement: enforce + rules: + # GraphQL API (used by gh CLI) + - allow: + method: POST + path: "/graphql" + # alpha-repo: full read-write (PRs, issues, comments, etc.) + - allow: + method: "*" + path: "/repos//alpha-repo/**" + # bravo-repo: read-only + - allow: + method: GET + path: "/repos//bravo-repo/**" + - allow: + method: HEAD + path: "/repos//bravo-repo/**" + - allow: + method: OPTIONS + path: "/repos//bravo-repo/**" + binaries: + - { path: /usr/local/bin/claude } + - { path: /usr/local/bin/opencode } + - { path: /usr/bin/gh } + - { path: /usr/bin/curl } + + # ── Package managers ───────────────────────────────────────── + + pypi: + name: pypi + endpoints: + - { host: pypi.org, port: 443 } + - { host: files.pythonhosted.org, port: 443 } + - { host: github.com, port: 443 } + - { host: objects.githubusercontent.com, port: 443 } + - { host: api.github.com, port: 443 } + - { host: downloads.python.org, port: 443 } + binaries: + - { path: /sandbox/.venv/bin/python } + - { path: /sandbox/.venv/bin/python3 } + - { path: /sandbox/.venv/bin/pip } + - { path: /app/.venv/bin/python } + - { path: /app/.venv/bin/python3 } + - { path: /app/.venv/bin/pip } + - { path: /usr/local/bin/uv } + - { path: "/sandbox/.uv/python/**" } + + # ── VS Code Remote ────────────────────────────────────────── + + vscode: + name: vscode + endpoints: + - { host: update.code.visualstudio.com, port: 443 } + - { host: "*.vo.msecnd.net", port: 443 } + - { host: vscode.download.prss.microsoft.com, port: 443 } + - { host: marketplace.visualstudio.com, port: 443 } + - { host: "*.gallerycdn.vsassets.io", port: 443 } + binaries: + - { path: /usr/bin/curl } + - { path: /usr/bin/wget } + - { path: "/sandbox/.vscode-server/**" } + - { path: "/sandbox/.vscode-remote-containers/**" } +``` + +**What the GitHub blocks do:** + +| Block | Endpoint | Access | +|---|---|---| +| `github_git` | `github.com:443` | Git Smart HTTP with TLS termination. Clone and fetch allowed for both repos. Push (`git-receive-pack`) allowed only for `alpha-repo`. All other repos are denied. | +| `github_api` | `api.github.com:443` | REST API with TLS termination. Full read-write for `alpha-repo`. Read-only (GET, HEAD, OPTIONS) for `bravo-repo`. All other repos are denied. | + +The remaining blocks (`claude_code`, `nvidia_inference`, `pypi`, `vscode`) match the {doc}`default policy ` so the sandbox behaves the same as a standard sandbox for everything outside of GitHub. + +For background on how network policy blocks work, see [Network Access Rules](/sandboxes/index.md#network-access-rules). + +## Step 3: Create the Sandbox + +Create the sandbox with both the GitHub provider and your policy: + +```console +$ nemoclaw sandbox create \ + --provider my-github \ + --policy github-policy.yaml \ + --keep \ + -- claude +``` + +The `--keep` flag keeps the sandbox running after Claude Code exits, so you can reconnect or iterate on the policy. + +## Step 4: Verify Access + +Once Claude Code is running inside the sandbox, ask it to exercise both repos. The policy should allow writes to `alpha-repo` and block writes to `bravo-repo`. + +**Test read-write access** — ask Claude to clone, commit, and push to `alpha-repo`: + +```text +Clone https://github.com//alpha-repo.git, add a blank line to the +README, commit, and push. +``` + +Claude clones the repo, makes the edit, and pushes. The sandbox logs show `action=allow` for both `github.com` (git push) and `api.github.com` (any API calls Claude makes along the way). + +**Test read-only enforcement** — ask Claude to try the same thing with `bravo-repo`: + +```text +Clone https://github.com//bravo-repo.git, add a blank line to the +README, commit, and push. +``` + +Claude clones successfully (read is allowed), but the push fails. The proxy denies `git-receive-pack` for `bravo-repo` and Claude reports the error. You can confirm in the logs: + +```console +$ nemoclaw logs --tail --source sandbox +``` + +Look for an `action=deny` entry showing `host=github.com` and `path=//bravo-repo.git/git-receive-pack`. + +**Test API scoping** — ask Claude to create an issue on each repo: + +```text +Create a GitHub issue titled "Test from sandbox" on /alpha-repo. +Then try to create the same issue on /bravo-repo. +``` + +The first issue is created. The second is denied — the policy only allows GET/HEAD/OPTIONS for `bravo-repo`, so the POST to create an issue is blocked. + +## Step 5: Iterate on the Policy + +To grant access to additional repos or change access levels, edit `github-policy.yaml` and push the update to the running sandbox: + +```console +$ nemoclaw policy set --policy github-policy.yaml --wait +``` + +For example, to grant write access to `bravo-repo` as well, add another rule under `github_api`: + +```yaml + - allow: + method: "*" + path: "/repos//bravo-repo/**" +``` + +And add a push rule under `github_git`: + +```yaml + - allow: + method: POST + path: "//bravo-repo.git/git-receive-pack" +``` + +For the full iterate workflow (pull current policy, edit, push, verify), see {doc}`/sandboxes/policies`. + +## Next Steps + +- **Need other credentials?** See {doc}`/sandboxes/providers` for all supported provider types. +- **Want finer policy control?** See {doc}`/sandboxes/policies` for more examples and the iterate workflow. +- **Looking for the full YAML reference?** See the [Policy Schema Reference](/reference/policy-schema.md). diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md new file mode 100644 index 0000000000..5421ee61f3 --- /dev/null +++ b/docs/tutorials/index.md @@ -0,0 +1,29 @@ + + +# Tutorials + +Step-by-step guides that walk through complete workflows from start to finish. + +::::{grid} 1 1 2 2 +:gutter: 3 + +:::{grid-item-card} GitHub Repo Access +:link: github-sandbox +:link-type: doc + +Create a sandbox with scoped GitHub access — read-write to one repo, read-only to another. + ++++ +{bdg-secondary}`Sandbox` {bdg-secondary}`Policy` {bdg-secondary}`Provider` +::: + +:::: + +```{toctree} +:hidden: + +github-sandbox +```