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
79 changes: 79 additions & 0 deletions .github/workflows/publish-csharp-sdks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright 2026 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.

name: Publish C# SDKs

on:
push:
tags:
- "csharp/sandbox/v*"
- "csharp/code-interpreter/v*"

permissions:
contents: read

jobs:
publish:
name: Publish (${{ matrix.sdk.name }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sdk:
- name: sandbox
tagPrefix: sandbox
csprojPath: sdks/sandbox/csharp/src/OpenSandbox/OpenSandbox.csproj
- name: code-interpreter
tagPrefix: code-interpreter
csprojPath: sdks/code-interpreter/csharp/src/OpenSandbox.CodeInterpreter/OpenSandbox.CodeInterpreter.csproj

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"

- name: Parse package version from tag
if: startsWith(github.ref, format('refs/tags/csharp/{0}/v', matrix.sdk.tagPrefix))
shell: bash
run: |
VERSION="${GITHUB_REF_NAME#csharp/${{ matrix.sdk.tagPrefix }}/v}"
echo "PACKAGE_VERSION=$VERSION" >> "$GITHUB_ENV"

- name: Restore
if: startsWith(github.ref, format('refs/tags/csharp/{0}/v', matrix.sdk.tagPrefix))
run: dotnet restore "${{ matrix.sdk.csprojPath }}"

- name: Pack
if: startsWith(github.ref, format('refs/tags/csharp/{0}/v', matrix.sdk.tagPrefix))
run: |
dotnet pack "${{ matrix.sdk.csprojPath }}" \
--configuration Release \
--no-restore \
-p:PackageVersion="${PACKAGE_VERSION}" \
-p:ContinuousIntegrationBuild=true \
--output ./artifacts/${{ matrix.sdk.name }}

- name: Publish to NuGet
if: startsWith(github.ref, format('refs/tags/csharp/{0}/v', matrix.sdk.tagPrefix))
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
dotnet nuget push "./artifacts/${{ matrix.sdk.name }}/*.nupkg" \
--api-key "$NUGET_API_KEY" \
--source "https://api.nuget.org/v3/index.json" \
--skip-duplicate
78 changes: 78 additions & 0 deletions .github/workflows/real-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,81 @@ jobs:
docker ps -aq --filter "label=opensandbox" | xargs -r docker rm -f || true
docker run --rm -v /tmp:/host_tmp alpine rm -rf /host_tmp/opensandbox-e2e || true
pkill -f "python -m src.main" || true

csharp-e2e:
name: C# E2E (docker bridge)
runs-on: self-hosted
env:
UV_BIN: /home/admin/.local/bin
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up uv PATH and verify
run: |
echo "${UV_BIN}" >> "$GITHUB_PATH"
export PATH="${UV_BIN}:${PATH}"
uv --version
uv run python --version

- name: Set up .NET SDK
uses: actions/setup-dotnet@v4
env:
DOTNET_INSTALL_DIR: /home/admin/.local/dotnet
with:
dotnet-version: "10.0.x"

- name: Clean up previous E2E resources
run: |
docker ps -aq --filter "label=opensandbox" | xargs -r docker rm -f || true
docker run --rm -v /tmp:/host_tmp alpine rm -rf /host_tmp/opensandbox-e2e || true

- name: Run tests
run: |
set -e

cat <<EOF > ~/.sandbox.toml
[server]
host = "127.0.0.1"
port = 8080
log_level = "INFO"
api_key = ""
[runtime]
type = "docker"
execd_image = "opensandbox/execd:local"
[egress]
image = "opensandbox/egress:latest"
[docker]
network_mode = "bridge"
[storage]
allowed_host_paths = ["/tmp/opensandbox-e2e"]
EOF

bash ./scripts/csharp-e2e.sh

- name: Eval server logs
if: ${{ always() }}
run: cat server/server.log

- name: Upload Test Report
if: always()
uses: actions/upload-artifact@v4
with:
name: csharp-test-report
path: tests/csharp/build/test-results/
retention-days: 5

- name: Upload execd logs
if: always()
uses: actions/upload-artifact@v4
with:
name: execd-log-for-csharp-e2e
path: /tmp/opensandbox-e2e/logs/
retention-days: 5

- name: Clean up after E2E
if: always()
run: |
docker ps -aq --filter "label=opensandbox" | xargs -r docker rm -f || true
docker run --rm -v /tmp:/host_tmp alpine rm -rf /host_tmp/opensandbox-e2e || true
pkill -f "python -m src.main" || true
24 changes: 24 additions & 0 deletions .github/workflows/sdk-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ on:
branches: [main]
paths:
- "sdks/sandbox/**"
- "sdks/code-interpreter/**"
- "specs/**"
push:
branches: [main]
paths:
- "sdks/sandbox/**"
- "sdks/code-interpreter/**"
- "specs/**"

concurrency:
Expand Down Expand Up @@ -79,3 +81,25 @@ jobs:
working-directory: sdks/sandbox/kotlin
run: |
./gradlew :sandbox:test

csharp-sdk:
name: C# SDK Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"

- name: Run sandbox tests
working-directory: sdks/sandbox/csharp
run: |
dotnet test tests/OpenSandbox.Tests/OpenSandbox.Tests.csproj --configuration Release

- name: Run code interpreter tests
working-directory: sdks/code-interpreter/csharp
run: |
dotnet test tests/OpenSandbox.CodeInterpreter.Tests/OpenSandbox.CodeInterpreter.Tests.csproj --configuration Release
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,5 @@ nbdist/
# Generated files
generated/
**/generated/**
bin/
obj/
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ OpenSandbox is a **general-purpose sandbox platform** for AI applications, offer

## Features

- **Multi-language SDKs**: Client SDKs for Python, Java/Kotlin, and JavaScript/TypeScript.
- **Multi-language SDKs**: Provides sandbox SDKs in Python, Java/Kotlin, JavaScript/TypeScript, C#/.NET, Go (Roadmap), and more.
- **Sandbox Protocol**: Defines sandbox lifecycle management APIs and sandbox execution APIs so you can extend custom sandbox runtimes.
- **Sandbox Runtime**: Built-in lifecycle management supporting Docker and [high-performance Kubernetes runtime](./kubernetes), enabling both local runs and large-scale distributed scheduling.
- **Sandbox Environments**: Built-in Command, Filesystem, and Code Interpreter implementations. Examples cover Coding Agents (e.g., Claude Code), browser automation (Chrome, Playwright), and desktop environments (VNC, VS Code).
Expand Down Expand Up @@ -177,7 +177,7 @@ For more details, please refer to [examples](examples/README.md) and the README

| Directory | Description |
|-----------|------------------------------------------------------------------|
| [`sdks/`](sdks/) | Multi-language SDKs (Python, Java/Kotlin, TypeScript/JavaScript) |
| [`sdks/`](sdks/) | Multi-language SDKs (Python, Java/Kotlin, TypeScript/JavaScript, C#/.NET) |
| [`specs/`](specs/README.md) | OpenAPI specs and lifecycle specifications |
| [`server/`](server/README.md) | Python FastAPI sandbox lifecycle server |
| [`kubernetes/`](kubernetes/README.md) | Kubernetes deployment and examples |
Expand All @@ -197,8 +197,8 @@ For detailed architecture, see [docs/architecture.md](docs/architecture.md).

- [docs/architecture.md](docs/architecture.md) – Overall architecture & design philosophy
- SDK
- Sandbox base SDK ([Java\Kotlin SDK](sdks/sandbox/kotlin/README.md), [Python SDK](sdks/sandbox/python/README.md), [JavaScript/TypeScript SDK](sdks/sandbox/javascript/README.md)) - includes sandbox lifecycle, command execution, file operations
- Code Interpreter SDK ([Java\Kotlin SDK](sdks/code-interpreter/kotlin/README.md), [Python SDK](sdks/code-interpreter/python/README.md), [JavaScript/TypeScript SDK](sdks/code-interpreter/javascript/README.md)) - code interpreter
- Sandbox base SDK ([Java\Kotlin SDK](sdks/sandbox/kotlin/README.md), [Python SDK](sdks/sandbox/python/README.md), [JavaScript/TypeScript SDK](sdks/sandbox/javascript/README.md), [C#/.NET SDK](sdks/sandbox/csharp/README.md)) - includes sandbox lifecycle, command execution, file operations
- Code Interpreter SDK ([Java\Kotlin SDK](sdks/code-interpreter/kotlin/README.md), [Python SDK](sdks/code-interpreter/python/README.md), [JavaScript/TypeScript SDK](sdks/code-interpreter/javascript/README.md), [C#/.NET SDK](sdks/code-interpreter/csharp/README.md)) - code interpreter
- [specs/README.md](specs/README.md) - OpenAPI definitions for sandbox lifecycle API and sandbox execution API
- [server/README.md](server/README.md) - Sandbox server startup and configuration; supports Docker and Kubernetes runtimes

Expand Down
4 changes: 4 additions & 0 deletions docs/.vitepress/scripts/docs-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ const shortTitleByPath = {
"sdks/code-interpreter/javascript/README.md": "Code Interpreter JS SDK",
"sdks/code-interpreter/kotlin/README.md": "Code Interpreter Kotlin SDK",
"sdks/code-interpreter/python/README.md": "Code Interpreter Python SDK",
"sdks/code-interpreter/csharp/README.md": "Code Interpreter C# SDK",
"sdks/sandbox/javascript/README.md": "Sandbox JS SDK",
"sdks/sandbox/kotlin/README.md": "Sandbox Kotlin SDK",
"sdks/sandbox/python/README.md": "Sandbox Python SDK",
"sdks/sandbox/csharp/README.md": "Sandbox C# SDK",
"sdks/mcp/sandbox/python/README.md": "MCP Sandbox Python SDK",
"sdks/sandbox/kotlin/sandbox-api/build/generated/api/execd/README.md": "Sandbox Execd API (Kotlin)",
"sdks/sandbox/kotlin/sandbox-api/build/generated/api/lifecycle/README.md": "Sandbox Lifecycle API (Kotlin)",
Expand Down Expand Up @@ -175,9 +177,11 @@ const shortTitleByPathZh = {
"sdks/code-interpreter/javascript/README.md": "代码解释器 JS SDK",
"sdks/code-interpreter/kotlin/README.md": "代码解释器 Kotlin SDK",
"sdks/code-interpreter/python/README.md": "代码解释器 Python SDK",
"sdks/code-interpreter/csharp/README.md": "代码解释器 C# SDK",
"sdks/sandbox/javascript/README.md": "沙箱 JS SDK",
"sdks/sandbox/kotlin/README.md": "沙箱 Kotlin SDK",
"sdks/sandbox/python/README.md": "沙箱 Python SDK",
"sdks/sandbox/csharp/README.md": "沙箱 C# SDK",
"sdks/mcp/sandbox/python/README.md": "MCP 沙箱 Python SDK",
"sdks/sandbox/kotlin/sandbox-api/build/generated/api/execd/README.md": "沙箱 Execd API(Kotlin)",
"sdks/sandbox/kotlin/sandbox-api/build/generated/api/lifecycle/README.md": "沙箱生命周期 API(Kotlin)",
Expand Down
8 changes: 4 additions & 4 deletions docs/README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ OpenSandbox 是一个面向 AI 应用场景设计的「通用沙箱平台」,

## 核心特性

- **多语言 SDK**:提供 Python、Java/Kotlin、JavaScript/TypeScript 等语言的客户端 SDK。
- **多语言 SDK**:提供 Python、Java/Kotlin、JavaScript/TypeScript、C#/.NET 等语言的客户端 SDK,Go SDK 仍在规划中
- **沙箱协议**:定义了沙箱生命周期管理 API 和沙箱执行 API。你可以通过这些沙箱协议扩展自己的沙箱运行时。
- **沙箱运行时**:沙箱全生命周期管理,支持 Docker 和[自研高性能 Kubernetes 运行时](../kubernetes),实现本地运行、企业级大规模分布式沙箱调度。
- **沙箱环境**:内置 Command、Filesystem、Code Interpreter 实现。并提供 Coding Agent(Claude Code 等)、浏览器自动化(Chrome、Playwright)和桌面环境(VNC、VS Code)等示例。
Expand Down Expand Up @@ -179,7 +179,7 @@ OpenSandbox 提供了丰富的示例来演示不同场景下的沙箱使用方

| 目录 | 说明 |
|------|---------------------------------------------------|
| [`sdks/`](../sdks/) | 多语言 SDK(Python、Java/Kotlin、TypeScript/JavaScript |
| [`sdks/`](../sdks/) | 多语言 SDK(Python、Java/Kotlin、TypeScript/JavaScript、C#/.NET) |
| [`specs/`](../specs/) | OpenAPI 与生命周期规范 |
| [`server/`](../server/README_zh.md) | Python FastAPI 沙箱生命周期服务,并集成多种运行时实现 |
| [`kubernetes/`](../kubernetes/README-ZH.md) | Kubernetes 部署与示例 |
Expand All @@ -199,8 +199,8 @@ OpenSandbox 提供了丰富的示例来演示不同场景下的沙箱使用方

- [docs/architecture.md](architecture.md) – 整体架构 & 设计理念
- SDK
- Sandbox SDK([Java\Kotlin SDK](../sdks/sandbox/kotlin/README_zh.md)、[Python SDK](../sdks/sandbox/python/README_zh.md)、[JavaScript/TypeScript SDK](../sdks/sandbox/javascript/README_zh.md))- 包含沙箱生命周期、命令执行、文件操作
- Code Interpreter SDK([Java\Kotlin SDK](../sdks/code-interpreter/kotlin/README_zh.md) 、[Python SDK](../sdks/code-interpreter/python/README_zh.md)、[JavaScript/TypeScript SDK](../sdks/code-interpreter/javascript/README_zh.md))- 代码解释器
- Sandbox 基础 SDK([Java\Kotlin SDK](../sdks/sandbox/kotlin/README_zh.md)、[Python SDK](../sdks/sandbox/python/README_zh.md)、[JavaScript/TypeScript SDK](../sdks/sandbox/javascript/README_zh.md)、[C#/.NET SDK](../sdks/sandbox/csharp/README_zh.md))- 包含沙箱生命周期、命令执行、文件操作
- Code Interpreter SDK([Java\Kotlin SDK](../sdks/code-interpreter/kotlin/README_zh.md) 、[Python SDK](../sdks/code-interpreter/python/README_zh.md)、[JavaScript/TypeScript SDK](../sdks/code-interpreter/javascript/README_zh.md)、[C#/.NET SDK](../sdks/code-interpreter/csharp/README_zh.md))- 代码解释器
- [specs/README.md](../specs/README_zh.md) - 包含沙箱生命周期 API 和沙箱执行 API 的 OpenAPI 定义
- [server/README.md](../server/README_zh.md) - 包含沙箱 Server 的启动和配置,支持 Docker 与 Kubernetes Runtime

Expand Down
66 changes: 66 additions & 0 deletions scripts/csharp-e2e.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash
# Copyright 2026 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.

set -euxo pipefail

TAG=${TAG:-latest}

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"

# build execd image locally (context must include internal/)
docker build -f components/execd/Dockerfile -t opensandbox/execd:local "${REPO_ROOT}"

# prepare required images from registry
docker pull opensandbox/code-interpreter:${TAG}
echo "-------- Eval test images --------"
docker images

# prepare hostpath volume for e2e test
mkdir -p /tmp/opensandbox-e2e/host-volume-test
mkdir -p /tmp/opensandbox-e2e/logs
echo "opensandbox-e2e-marker" > /tmp/opensandbox-e2e/host-volume-test/marker.txt
chmod -R 755 /tmp/opensandbox-e2e

# prepare Docker named volume for pvc e2e test
docker volume rm opensandbox-e2e-pvc-test 2>/dev/null || true
docker volume create opensandbox-e2e-pvc-test
docker run --rm -v opensandbox-e2e-pvc-test:/data alpine sh -c "\
echo 'pvc-marker-data' > /data/marker.txt && \
mkdir -p /data/datasets/train && \
echo 'pvc-subpath-marker' > /data/datasets/train/marker.txt"
echo "-------- CSHARP E2E test logs for execd --------" > /tmp/opensandbox-e2e/logs/execd.log

# setup server
cd server
: > server.log
(uv sync && uv run python -m src.main) > server.log 2>&1 &
cd ..

# wait for server
sleep 10

# test env for C# fixture
export OPENSANDBOX_TEST_DOMAIN="localhost:8080"
export OPENSANDBOX_TEST_PROTOCOL="http"
export OPENSANDBOX_TEST_API_KEY=""
export OPENSANDBOX_SANDBOX_DEFAULT_IMAGE="opensandbox/code-interpreter:${TAG}"

mkdir -p tests/csharp/build/test-results
dotnet restore "tests/csharp/OpenSandbox.E2ETests/OpenSandbox.E2ETests.csproj"
dotnet test "tests/csharp/OpenSandbox.E2ETests/OpenSandbox.E2ETests.csproj" \
--configuration Release \
--no-restore \
--results-directory "tests/csharp/build/test-results" \
--logger "trx;LogFileName=csharp-e2e.trx"
25 changes: 25 additions & 0 deletions sdks/code-interpreter/csharp/OpenSandbox.CodeInterpreter.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSandbox.CodeInterpreter", "src\OpenSandbox.CodeInterpreter\OpenSandbox.CodeInterpreter.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSandbox.CodeInterpreter.Tests", "tests\OpenSandbox.CodeInterpreter.Tests\OpenSandbox.CodeInterpreter.Tests.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Loading