Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ You can use OpenSandbox for personal or commercial projects in compliance with t
### Server Runtime

- [x] **OpenSandbox Kubernetes Runtime** - High-performance sandbox scheduling implementation (see [`kubernetes/`](kubernetes/README.md))
- [ ] **kubernetes-sigs/agent-sandbox Support** - Integration with [kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox)
- [x] **kubernetes-sigs/agent-sandbox Support** - Integration with [kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox)
- [ ] **Declarative Network Isolation** - Network egress control with allow/deny rules for specific domains (see [OSEP-0001](oseps/0001-fqdn-based-egress-control.md))
- [x] DNS-based egress control (Layer 1)
- [ ] Network-based egress control (Layer 2)
Expand Down
2 changes: 1 addition & 1 deletion docs/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ OpenSandbox 提供了丰富的示例来演示不同场景下的沙箱使用方
### Server Runtime

- [x] **自研 Kubernetes 沙箱调度器** - 高性能沙箱调度实现(见 [`kubernetes/`](../kubernetes/README-ZH.md))
- [ ] **kubernetes-sigs/agent-sandbox 支持** - 集成 [kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox) 沙箱调度能力
- [x] **kubernetes-sigs/agent-sandbox 支持** - 集成 [kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox) 沙箱调度能力
- [ ] **声明式网络隔离** - 支持允许/禁止特定域名规则的网络 egress 访问控制(见 [OSEP-0001](../oseps/0001-fqdn-based-egress-control.md))
- [x] 基于 DNS 的 Egress 控制(Layer 1)
- [ ] 基于网络的 Egress 控制(Layer 2)
Expand Down
3 changes: 2 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
Examples for common OpenSandbox use cases. Each subdirectory contains runnable code and documentation.

## Integrations / Sandboxes
- [**aio-sandbox**](aio-sandbox): Basic example for agent_sandbox
- [**aio-sandbox**](aio-sandbox): Basic example for agent-infra sandbox (AIO)
- [**agent-sandbox**](agent-sandbox): Create an agent-sandbox instance and run a command
- [**code-interpreter**](code-interpreter): Code Interpreter SDK singleton example
- [**rl-training**](rl-training): Reinforcement learning training loop inside a sandbox
- [**claude-code**](claude-code): Call Claude (Anthropic) API/CLI within the sandbox
Expand Down
55 changes: 55 additions & 0 deletions examples/agent-sandbox/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Agent-Sandbox Example

This example creates a sandbox backed by `kubernetes-sigs/agent-sandbox` and
executes `echo hello world` via the OpenSandbox Python SDK.

## Prerequisites

- A Kubernetes cluster with the agent-sandbox controller and CRDs installed.
- OpenSandbox server configured with Kubernetes runtime and `workload_provider = "agent-sandbox"`.
- Sandbox image should include `bash` (default example uses `ubuntu:22.04`).

## Start OpenSandbox server

1. Copy the example config and edit it for agent-sandbox:

```shell
cd server
cp example.config.toml ~/.sandbox.toml
```

2. Update `~/.sandbox.toml` with the following sections:

```toml
[runtime]
type = "kubernetes"
execd_image = "opensandbox/execd:latest"

[kubernetes]
namespace = "default"
# kubeconfig_path = "/absolute/path/to/kubeconfig" # optional if running in-cluster
workload_provider = "agent-sandbox"

[agent_sandbox]
shutdown_policy = "Delete"
```

3. Start the server:

```shell
cd server
uv sync && uv run python -m src.main
```

## Run the example

```shell
uv pip install opensandbox
uv run python examples/agent-sandbox/main.py
```

## Expected output

```text
command output: hello world
```
48 changes: 48 additions & 0 deletions examples/agent-sandbox/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2025 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import asyncio
import os
from datetime import timedelta

from opensandbox import Sandbox
from opensandbox.config import ConnectionConfig


async def main() -> None:
domain = os.getenv("SANDBOX_DOMAIN", "localhost:8080")
api_key = os.getenv("SANDBOX_API_KEY")
image = os.getenv("SANDBOX_IMAGE", "ubuntu:22.04")

config = ConnectionConfig(
domain=domain,
api_key=api_key,
request_timeout=timedelta(seconds=60),
)

sandbox = await Sandbox.create(
image,
connection_config=config,
timeout=timedelta(minutes=10),
)

async with sandbox:
execution = await sandbox.commands.run("echo hello world")
stdout = execution.logs.stdout[0].text if execution.logs.stdout else ""
print(f"command output: {stdout}")
await sandbox.kill()


if __name__ == "__main__":
asyncio.run(main())
8 changes: 8 additions & 0 deletions server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ curl -X DELETE \
|-----|------|---------|-------------|
| `docker.network_mode` | string | `"host"` | Network mode (`"host"` or `"bridge"`) |

### Agent-sandbox configuration

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `agent_sandbox.template_file` | string | `null` | Sandbox CR YAML template for agent-sandbox (used when `kubernetes.workload_provider = "agent-sandbox"`) |
| `agent_sandbox.shutdown_policy` | string | `"Delete"` | Shutdown policy on expiry (`"Delete"` or `"Retain"`) |
| `agent_sandbox.ingress_enabled` | boolean | `true` | Whether ingress routing is expected to be enabled |

### Environment variables

| Variable | Description |
Expand Down
8 changes: 8 additions & 0 deletions server/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,14 @@ curl -X DELETE http://localhost:8080/v1/sandboxes/<sandbox-id>
|----|------|--------|------|
| `docker.network_mode` | string | `"host"` | 网络模式(`"host"` 或 `"bridge"`)|

### Agent-sandbox 配置

| 键 | 类型 | 默认值 | 描述 |
|----|------|--------|------|
| `agent_sandbox.template_file` | string | `null` | agent-sandbox 的 Sandbox CR YAML 模板路径(仅在 `kubernetes.workload_provider = "agent-sandbox"` 时使用) |
| `agent_sandbox.shutdown_policy` | string | `"Delete"` | 过期时的关停策略(`"Delete"` 或 `"Retain"`) |
| `agent_sandbox.ingress_enabled` | boolean | `true` | 是否启用 ingress 路由 |

### 环境变量

| 变量 | 描述 |
Expand Down
28 changes: 28 additions & 0 deletions server/src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ class KubernetesRuntimeConfig(BaseModel):
)


class AgentSandboxRuntimeConfig(BaseModel):
"""Agent-sandbox runtime configuration."""

template_file: Optional[str] = Field(
default=None,
description="Path to Sandbox CR YAML template file for agent-sandbox.",
)
shutdown_policy: Literal["Delete", "Retain"] = Field(
default="Delete",
description="Shutdown policy applied when a sandbox expires (Delete or Retain).",
)
ingress_enabled: bool = Field(
default=True,
description="Whether ingress routing to agent-sandbox pods is expected to be enabled.",
)


class RuntimeConfig(BaseModel):
"""Runtime selection (docker, kubernetes, etc.)."""

Expand Down Expand Up @@ -180,6 +197,7 @@ class AppConfig(BaseModel):
server: ServerConfig = Field(default_factory=ServerConfig)
runtime: RuntimeConfig = Field(..., description="Sandbox runtime configuration.")
kubernetes: Optional[KubernetesRuntimeConfig] = None
agent_sandbox: Optional["AgentSandboxRuntimeConfig"] = None
router: Optional[RouterConfig] = None
docker: DockerConfig = Field(default_factory=DockerConfig)

Expand All @@ -188,9 +206,19 @@ def validate_runtime_blocks(self) -> "AppConfig":
if self.runtime.type == "docker":
if self.kubernetes is not None:
raise ValueError("Kubernetes block must be omitted when runtime.type = 'docker'.")
if self.agent_sandbox is not None:
raise ValueError("agent_sandbox block must be omitted when runtime.type = 'docker'.")
elif self.runtime.type == "kubernetes":
if self.kubernetes is None:
self.kubernetes = KubernetesRuntimeConfig()
provider_type = (self.kubernetes.workload_provider or "").lower()
if provider_type == "agent-sandbox":
if self.agent_sandbox is None:
self.agent_sandbox = AgentSandboxRuntimeConfig()
elif self.agent_sandbox is not None:
raise ValueError(
"agent_sandbox block requires kubernetes.workload_provider = 'agent-sandbox'."
)
else:
raise ValueError(f"Unsupported runtime type '{self.runtime.type}'.")
return self
Expand Down
2 changes: 2 additions & 0 deletions server/src/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
"""Sandbox service implementations."""

from src.services.docker import DockerSandboxService
from src.services.k8s.kubernetes_service import KubernetesSandboxService
from src.services.factory import create_sandbox_service
from src.services.sandbox_service import SandboxService

__all__ = [
"SandboxService",
"DockerSandboxService",
"KubernetesSandboxService",
"create_sandbox_service",
]
2 changes: 2 additions & 0 deletions server/src/services/k8s/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
register_provider,
list_available_providers,
PROVIDER_TYPE_BATCHSANDBOX,
PROVIDER_TYPE_AGENT_SANDBOX,
)

__all__ = [
Expand All @@ -30,4 +31,5 @@
"register_provider",
"list_available_providers",
"PROVIDER_TYPE_BATCHSANDBOX",
"PROVIDER_TYPE_AGENT_SANDBOX",
]
Loading
Loading