From 5c3a8650286b2d3b1ddce8db196e7ffe60f37181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E7=84=B6?= Date: Fri, 20 Mar 2026 22:21:30 +0800 Subject: [PATCH 1/3] feat(execd): add EXECD_CLONE3_COMPAT seccomp-based clone3 fallback --- components/execd/README.md | 39 ++++++++ components/execd/README_zh.md | 41 ++++++++ components/execd/go.mod | 3 +- components/execd/go.sum | 2 + components/execd/main.go | 3 + components/execd/pkg/clone3compat/compat.go | 27 ++++++ .../execd/pkg/clone3compat/compat_linux.go | 97 +++++++++++++++++++ .../execd/pkg/clone3compat/compat_stub.go | 20 ++++ 8 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 components/execd/pkg/clone3compat/compat.go create mode 100644 components/execd/pkg/clone3compat/compat_linux.go create mode 100644 components/execd/pkg/clone3compat/compat_stub.go diff --git a/components/execd/README.md b/components/execd/README.md index dce1fd739..6cc3d43ca 100644 --- a/components/execd/README.md +++ b/components/execd/README.md @@ -11,6 +11,7 @@ English | [中文](README_zh.md) - [Architecture](#architecture) - [Getting Started](#getting-started) - [Configuration](#configuration) + - [Linux `clone3` compatibility inside sandboxes](#linux-clone3-compatibility-inside-sandboxes) - [API Reference](#api-reference) - [Supported Languages](#supported-languages) - [Development](#development) @@ -82,6 +83,7 @@ English | [中文](README_zh.md) | `pkg/jupyter/execute/` | Execution result types and stream parsers | | `pkg/jupyter/session/` | Session management and lifecycle | | `pkg/util/` | Utilities (safe goroutine helpers, glob helpers) | +| `pkg/clone3compat/` | Optional seccomp shim for `clone3` → `ENOSYS` on Linux | | `tests/` | Test scripts and tools | ## Getting Started @@ -169,6 +171,43 @@ export JUPYTER_TOKEN=your-token Environment variables override defaults but are superseded by explicit CLI flags. +| Variable | Description | +|----------|-------------| +| `EXECD_CLONE3_COMPAT` | Linux only. See [below](#linux-clone3-compatibility-inside-sandboxes). | + +### Linux `clone3` compatibility inside sandboxes + +Some sandbox images ship **glibc ≥ 2.34**, which prefers the `clone3(2)` syscall. On **older container engines** (for example Docker **before 20.10.10** and matching containerd CRI versions), or wherever `clone3` is not handled correctly, **process creation can fail**. That affects anything that forks or execs: **Go `os/exec`** inside execd, shell commands, package managers (`apt`, `dnf`), and language runtimes that start subprocesses. + +Typical symptoms are errors mentioning **`clone3`**, **`Function not implemented`**, or **`Operation not permitted`** when running commands or code **inside the sandbox**—not necessarily when starting the OpenSandbox server on the host. + +#### Enabling the built-in workaround + +execd can install a **seccomp** rule so `clone3` returns **`ENOSYS`**, forcing libc and the Go runtime to fall back to `clone(2)`—the same idea as [AkihiroSuda/clone3-workaround](https://github.com/AkihiroSuda/clone3-workaround). Implementation: [`pkg/clone3compat/`](pkg/clone3compat/). + +Set the variable **in the sandbox container environment** (where execd is PID 1 or otherwise started): + +| Value | Behavior | +|-------|----------| +| `1`, `true`, `yes`, `on` | Load the filter at the beginning of `main` (after Go runtime `init`). | +| `reexec` | Load the filter, then `exec` the same binary again so subsequent `init` runs already under seccomp (closest to wrapping with the external workaround binary). | + +Unset, empty, or `0` / `false` / `off` / `no` disables the feature. + +#### SDK + +Set `EXECD_CLONE3_COMPAT` in `Sandbox.create` `env` so execd sees it when the sandbox starts: + +```python +sandbox = await Sandbox.create( + "opensandbox/code-interpreter:v1.0.2", + entrypoint=["/opt/opensandbox/code-interpreter.sh"], + env={"EXECD_CLONE3_COMPAT": "1"}, +) +``` + +The sandbox must allow **seccomp** and **`PR_SET_NO_NEW_PRIVS`** for the filter to load. Upgrading the host container engine/kernel is the long-term fix when possible. + ## API Reference [API Spec](../../specs/execd-api.yaml). diff --git a/components/execd/README_zh.md b/components/execd/README_zh.md index 35c3e4aac..26e012ddf 100644 --- a/components/execd/README_zh.md +++ b/components/execd/README_zh.md @@ -12,6 +12,7 @@ - [架构设计](#架构设计) - [快速开始](#快速开始) - [配置说明](#配置说明) + - [沙箱内的 Linux clone3 兼容](#沙箱内的-linux-clone3-兼容) - [API 参考](#api-参考) - [支持的语言](#支持的语言) - [开发指南](#开发指南) @@ -80,6 +81,7 @@ | `pkg/jupyter/execute/` | 执行结果类型与流解析器 | | `pkg/jupyter/session/` | 会话管理与生命周期 | | `pkg/util/` | 通用工具(安全 goroutine、glob 辅助) | +| `pkg/clone3compat/` | Linux 下可选 seccomp,使 `clone3` 返回 `ENOSYS` | | `tests/` | 测试脚本和工具 | ## 快速开始 @@ -167,6 +169,45 @@ export JUPYTER_TOKEN=your-token 环境变量优先于默认值,但会被显式的 CLI 标志覆盖。 +| 变量 | 说明 | +|------|------| +| `EXECD_CLONE3_COMPAT` | 仅 Linux。详见 [下文](#沙箱内的-linux-clone3-兼容)。 | + +### 沙箱内的 Linux clone3 兼容 + +部分沙箱镜像使用 **glibc ≥ 2.34**,会优先使用 **`clone3(2)`** 系统调用。在**较旧的容器引擎**上(例如 Docker **低于 20.10.10** 及对应 containerd CRI 版本),或运行时对 `clone3` 支持不完整时,**创建子进程可能失败**。 + +受影响场景包括:execd 内部的 **Go `os/exec`**、shell 命令、`apt`/`dnf` 等包管理器,以及会拉子进程的语言运行时。 + +常见报错里会出现 **`clone3`**、**`Function not implemented`** 或 **`Operation not permitted`**,且多发生在**沙箱内**执行命令或代码时,而不一定是宿主机上启动 OpenSandbox 服务时。 + +#### 启用内置规避 + +execd 可通过 **seccomp** 让 `clone3` 返回 **`ENOSYS`**,迫使 libc 与 Go 运行时回退到 **`clone(2)`**,思路与 [AkihiroSuda/clone3-workaround](https://github.com/AkihiroSuda/clone3-workaround) 一致。实现见 [`pkg/clone3compat/`](pkg/clone3compat/)。 + +在**沙箱容器环境变量**中设置(execd 作为容器入口或主进程时): + +| 取值 | 行为 | +|------|------| +| `1`、`true`、`yes`、`on` | 在 `main` 开头加载过滤器(Go `init` 之后)。 | +| `reexec` | 加载过滤器后对同二进制再 `exec` 一次,使后续 `init` 已在 seccomp 下运行(最接近外挂 workaround 二进制的方式)。 | + +未设置、为空,或为 `0` / `false` / `off` / `no` 时关闭。 + +#### SDK + +在 `Sandbox.create` 的 `env` 中设置 `EXECD_CLONE3_COMPAT`,使 execd 在沙箱启动时即可读到: + +```python +sandbox = await Sandbox.create( + "opensandbox/code-interpreter:v1.0.2", + entrypoint=["/opt/opensandbox/code-interpreter.sh"], + env={"EXECD_CLONE3_COMPAT": "1"}, +) +``` + +沙箱需允许加载 seccomp 过滤器(**seccomp**、**`PR_SET_NO_NEW_PRIVS`**)。长期仍建议在宿主机上升级容器引擎/内核,使 `clone3` 全链路可用。 + ## API 参考 [API Spec](../../specs/execd-api.yaml)。 diff --git a/components/execd/go.mod b/components/execd/go.mod index 0b3f39cb5..c19f37a2c 100644 --- a/components/execd/go.mod +++ b/components/execd/go.mod @@ -5,6 +5,7 @@ go 1.24.0 require ( github.com/alibaba/opensandbox/internal v0.0.0 github.com/bmatcuk/doublestar/v4 v4.9.1 + github.com/elastic/go-seccomp-bpf v1.6.0 github.com/gin-gonic/gin v1.10.0 github.com/go-playground/validator/v10 v10.28.0 github.com/go-sql-driver/mysql v1.8.1 @@ -13,6 +14,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible github.com/stretchr/testify v1.10.0 go.uber.org/automaxprocs v1.6.0 + golang.org/x/sys v0.38.0 k8s.io/apimachinery v0.34.2 k8s.io/client-go v0.34.2 ) @@ -54,7 +56,6 @@ require ( golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/components/execd/go.sum b/components/execd/go.sum index 0ebe846c5..9cb6871af 100644 --- a/components/execd/go.sum +++ b/components/execd/go.sum @@ -14,6 +14,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elastic/go-seccomp-bpf v1.6.0 h1:NYduiYxRJ0ZkIyQVwlSskcqPPSg6ynu5pK0/d7SQATs= +github.com/elastic/go-seccomp-bpf v1.6.0/go.mod h1:5tFsTvH4NtWGfpjsOQD53H8HdVQ+zSZFRUDSGevC0Kc= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= diff --git a/components/execd/main.go b/components/execd/main.go index e9b1d7641..fc051a166 100644 --- a/components/execd/main.go +++ b/components/execd/main.go @@ -22,6 +22,7 @@ import ( _ "go.uber.org/automaxprocs/maxprocs" + "github.com/alibaba/opensandbox/execd/pkg/clone3compat" "github.com/alibaba/opensandbox/execd/pkg/flag" "github.com/alibaba/opensandbox/execd/pkg/log" _ "github.com/alibaba/opensandbox/execd/pkg/util/safego" @@ -31,6 +32,8 @@ import ( // main initializes and starts the execd server. func main() { + clone3compat.MaybeApply() + version.EchoVersion("OpenSandbox Execd") flag.InitFlags() diff --git a/components/execd/pkg/clone3compat/compat.go b/components/execd/pkg/clone3compat/compat.go new file mode 100644 index 000000000..e46e78337 --- /dev/null +++ b/components/execd/pkg/clone3compat/compat.go @@ -0,0 +1,27 @@ +// 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. + +// Package clone3compat installs an optional seccomp rule so clone3(2) returns ENOSYS and +// libc / the Go runtime fall back to clone(2), following the same idea as +// https://github.com/AkihiroSuda/clone3-workaround . +// +// Enable on Linux via environment when starting execd: +// +// EXECD_CLONE3_COMPAT=1 — install the filter at process start (after Go runtime init). +// EXECD_CLONE3_COMPAT=reexec — install the filter then re-exec the same binary so all +// package init code runs with the filter already active +// (closest to wrapping with the external clone3-workaround binary). +// +// Disabled when unset or empty, or set to 0, false, off, no. +package clone3compat diff --git a/components/execd/pkg/clone3compat/compat_linux.go b/components/execd/pkg/clone3compat/compat_linux.go new file mode 100644 index 000000000..c3d9792e4 --- /dev/null +++ b/components/execd/pkg/clone3compat/compat_linux.go @@ -0,0 +1,97 @@ +// 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. + +//go:build linux + +package clone3compat + +import ( + "errors" + "fmt" + "os" + "strings" + "syscall" + + seccomp "github.com/elastic/go-seccomp-bpf" + "golang.org/x/sys/unix" +) + +const ( + envCompat = "EXECD_CLONE3_COMPAT" + envApplied = "_EXECD_CLONE3_COMPAT_APPLIED" +) + +// MaybeApply optionally installs a seccomp rule so clone3 returns ENOSYS, matching the +// behavior of https://github.com/AkihiroSuda/clone3-workaround . +func MaybeApply() { + mode := strings.ToLower(strings.TrimSpace(os.Getenv(envCompat))) + switch mode { + case "", "0", "false", "off", "no": + return + case "1", "true", "yes", "on": + if err := loadClone3EnosysFilter(); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "execd: %v\n", err) + os.Exit(1) + } + case "reexec": + if os.Getenv(envApplied) == "1" { + return + } + if err := loadClone3EnosysFilter(); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "execd: %v\n", err) + os.Exit(1) + } + if err := os.Setenv(envApplied, "1"); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "execd: clone3 compat: set %s: %v\n", envApplied, err) + os.Exit(1) + } + exe, err := os.Readlink("/proc/self/exe") + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "execd: clone3 compat: readlink /proc/self/exe: %v\n", err) + os.Exit(1) + } + exe = strings.TrimSuffix(exe, " (deleted)") + if err := unix.Exec(exe, os.Args, os.Environ()); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "execd: clone3 compat: exec: %v\n", err) + os.Exit(1) + } + default: + _, _ = fmt.Fprintf(os.Stderr, "execd: invalid %s=%q (use 1, true, or reexec)\n", envCompat, os.Getenv(envCompat)) + os.Exit(1) + } +} + +func loadClone3EnosysFilter() error { + if !seccomp.Supported() { + return errors.New("clone3 compat: seccomp is not available on this kernel") + } + f := seccomp.Filter{ + NoNewPrivs: true, + Flag: seccomp.FilterFlagTSync, + Policy: seccomp.Policy{ + DefaultAction: seccomp.ActionAllow, + Syscalls: []seccomp.SyscallGroup{ + { + Names: []string{"clone3"}, + // Not plain ActionErrno: assembler defaults errno to EPERM. + Action: seccomp.ActionErrno | seccomp.Action(syscall.ENOSYS), + }, + }, + }, + } + if err := seccomp.LoadFilter(f); err != nil { + return fmt.Errorf("clone3 compat: %w", err) + } + return nil +} diff --git a/components/execd/pkg/clone3compat/compat_stub.go b/components/execd/pkg/clone3compat/compat_stub.go new file mode 100644 index 000000000..2f13a3c88 --- /dev/null +++ b/components/execd/pkg/clone3compat/compat_stub.go @@ -0,0 +1,20 @@ +// 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. + +//go:build !linux + +package clone3compat + +// MaybeApply is a no-op on non-Linux platforms. +func MaybeApply() {} From 66c5bf6393fbebc07336ec6d07cfefd66d9c9397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E7=84=B6?= Date: Fri, 20 Mar 2026 23:06:59 +0800 Subject: [PATCH 2/3] feat(code-interpreter): add EXECD_CLONE3_COMPAT seccomp-based clone3 fallback --- sandboxes/code-interpreter/Dockerfile | 13 +++++++ sandboxes/code-interpreter/README.md | 5 +++ sandboxes/code-interpreter/README_zh.md | 5 +++ .../scripts/code-interpreter.sh | 34 +++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/sandboxes/code-interpreter/Dockerfile b/sandboxes/code-interpreter/Dockerfile index 2a1aa0135..f72ee6a41 100644 --- a/sandboxes/code-interpreter/Dockerfile +++ b/sandboxes/code-interpreter/Dockerfile @@ -16,6 +16,19 @@ FROM opensandbox/code-interpreter-base:latest +ARG TARGETARCH +# Prebuilt binary from https://github.com/AkihiroSuda/clone3-workaround/releases/tag/v1.0.0 (amd64 only). +# The binary is linked against libseccomp (runtime package libseccomp2 on Ubuntu). +RUN set -eux; \ + if [ "${TARGETARCH}" = "amd64" ]; then \ + apt-get update && apt-get install -y --no-install-recommends libseccomp2 && rm -rf /var/lib/apt/lists/*; \ + curl -fsSL -o /usr/local/bin/clone3-workaround \ + https://github.com/AkihiroSuda/clone3-workaround/releases/download/v1.0.0/clone3-workaround.x86_64; \ + chmod 755 /usr/local/bin/clone3-workaround; \ + else \ + echo "Skipping clone3-workaround: upstream provides amd64/x86_64 binary only (TARGETARCH=${TARGETARCH})"; \ + fi + # Install Python kernels RUN set -euo pipefail \ && echo "Setting up ipykernel for Python 3.10, 3.11, 3.12, 3.13, 3.14" \ diff --git a/sandboxes/code-interpreter/README.md b/sandboxes/code-interpreter/README.md index 2b7943a20..bf6f5356c 100644 --- a/sandboxes/code-interpreter/README.md +++ b/sandboxes/code-interpreter/README.md @@ -12,6 +12,7 @@ provide an out-of-the-box multi-language code execution environment. - **Version Switching**: Easy runtime version switching without rebuilding - **Jupyter Integration**: Built-in Jupyter Notebook with multi-language kernels - **Multi-Architecture**: Supports both amd64 and arm64 architectures +- **clone3-workaround (amd64)**: The image installs [AkihiroSuda/clone3-workaround](https://github.com/AkihiroSuda/clone3-workaround) v1.0.0 as `/usr/local/bin/clone3-workaround` on **linux/amd64** only (upstream ships no arm64 binary), plus **`libseccomp2`** because the upstream binary is dynamically linked to `libseccomp`. Use it to wrap commands on very old Docker/containerd hosts, e.g. `clone3-workaround apt-get update`. - **Production Ready**: Optimized for containerized execution environments ## Supported Languages & Versions @@ -58,6 +59,10 @@ docker run -it --rm \ opensandbox/code-interpreter:latest ``` +### `EXECD_CLONE3_COMPAT` (clone3-workaround) + +If you set `EXECD_CLONE3_COMPAT` to `1`, `true`, `yes`, `on`, or `reexec` (same semantics as [execd](../../components/execd/README.md#linux-clone3-compatibility-inside-sandboxes)), the entrypoint script **re-executes itself** under `/usr/local/bin/clone3-workaround` before Jupyter and kernel setup. That binary is included on **linux/amd64** only; on **arm64** builds the script prints a warning and continues without wrapping. After a successful wrap, the script **unsets** `EXECD_CLONE3_COMPAT` in the running process tree. Use `0`, `false`, `off`, `no`, or leave unset to disable. + ## Version Switching The image includes a built-in version switching script `/opt/opensandbox/code-interpreter-env.sh`. You need to use the diff --git a/sandboxes/code-interpreter/README_zh.md b/sandboxes/code-interpreter/README_zh.md index e68b2584c..9a201d22c 100644 --- a/sandboxes/code-interpreter/README_zh.md +++ b/sandboxes/code-interpreter/README_zh.md @@ -11,6 +11,7 @@ - **版本切换**:无需重新构建,支持运行时快速切换版本 - **Jupyter 集成**:内置 Jupyter Notebook 并支持多语言内核 - **多架构支持**:同时支持 amd64 和 arm64 架构 +- **clone3-workaround(仅 amd64)**:在 **linux/amd64** 镜像中安装 [AkihiroSuda/clone3-workaround](https://github.com/AkihiroSuda/clone3-workaround) v1.0.0 至 `/usr/local/bin/clone3-workaround`(上游无 arm64 预编译包),并安装 **`libseccomp2`**(上游二进制动态链接 `libseccomp`)。在极旧 Docker/containerd 宿主机上可用其包裹命令,例如 `clone3-workaround apt-get update`。 - **生产就绪**:针对容器化执行环境进行了优化 ## 支持的语言与版本 @@ -57,6 +58,10 @@ docker run -it --rm \ sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:latest ``` +### `EXECD_CLONE3_COMPAT`(clone3-workaround) + +若将 `EXECD_CLONE3_COMPAT` 设为 `1`、`true`、`yes`、`on` 或 `reexec`(与 [execd](../../components/execd/README_zh.md#沙箱内的-linux-clone3-兼容) 一致),入口脚本会在启动 Jupyter/内核前用 **`/usr/local/bin/clone3-workaround` 重新 `exec` 自身**。**linux/amd64** 镜像内含该二进制;**arm64** 构建会打印警告并跳过包装。包装成功后脚本会在当前进程树中 **`unset` `EXECD_CLONE3_COMPAT`**。设为 `0`、`false`、`off`、`no` 或不设置则关闭此逻辑。 + ## 如何切换版本 镜像内置了一个环境切换脚本 `/opt/opensandbox/code-interpreter-env.sh`,你需要使用 `source` 命令加载它来修改当前 Shell diff --git a/sandboxes/code-interpreter/scripts/code-interpreter.sh b/sandboxes/code-interpreter/scripts/code-interpreter.sh index 11968c1df..96b77ab91 100755 --- a/sandboxes/code-interpreter/scripts/code-interpreter.sh +++ b/sandboxes/code-interpreter/scripts/code-interpreter.sh @@ -13,6 +13,40 @@ # See the License for the specific language governing permissions and # limitations under the License. +# If EXECD_CLONE3_COMPAT is set (same accepted values as execd's pkg/clone3compat), re-exec this +# script under AkihiroSuda/clone3-workaround so the rest of startup runs with clone3 -> ENOSYS. +# See https://github.com/AkihiroSuda/clone3-workaround — binary is /usr/local/bin/clone3-workaround (amd64 image only). +_execd_clone3_compat_normalized=$( + echo "${EXECD_CLONE3_COMPAT:-}" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' +) +case "${_execd_clone3_compat_normalized}" in +"" | 0 | false | off | no) ;; +1 | true | yes | on | reexec) + if [ -z "${_CODE_INTERPRETER_CLONE3_WRAPPED:-}" ]; then + _ci_script=${BASH_SOURCE[0]} + if command -v readlink >/dev/null 2>&1 && _rp=$(readlink -f "${_ci_script}" 2>/dev/null); then + _ci_script=${_rp} + fi + if [ -x /usr/local/bin/clone3-workaround ]; then + export _CODE_INTERPRETER_CLONE3_WRAPPED=1 + exec /usr/local/bin/clone3-workaround /bin/bash "${_ci_script}" "$@" + else + echo "code-interpreter: EXECD_CLONE3_COMPAT is set but /usr/local/bin/clone3-workaround is missing (not installed for this architecture); continuing without wrapper" >&2 + fi + fi + unset _ci_script _rp + ;; +*) + echo "code-interpreter: invalid EXECD_CLONE3_COMPAT=${EXECD_CLONE3_COMPAT:-} (use 1, true, yes, on, or reexec)" >&2 + exit 1 + ;; +esac +unset _execd_clone3_compat_normalized + +if [ -n "${_CODE_INTERPRETER_CLONE3_WRAPPED:-}" ]; then + unset EXECD_CLONE3_COMPAT +fi + declare -a pids=() BASHRC_FILE=${BASHRC_FILE:-/root/.bashrc} From c923d6e5e992bf96b4209ba7f9a8da326a92ed36 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Mar 2026 15:40:39 +0000 Subject: [PATCH 3/3] chore: bump code-interpreter to v1.0.2.clone3.fix1 --- README.md | 2 +- components/execd/README.md | 2 +- components/execd/README_zh.md | 2 +- docs/README_zh.md | 2 +- docs/secure-container.md | 2 +- examples/claude-code/README.md | 6 +++--- examples/claude-code/main.py | 2 +- examples/code-interpreter/README.md | 10 +++++----- examples/code-interpreter/main.py | 2 +- examples/code-interpreter/main_use_pool.py | 2 +- examples/codex-cli/README.md | 6 +++--- examples/codex-cli/main.py | 2 +- examples/gemini-cli/README.md | 6 +++--- examples/gemini-cli/main.py | 2 +- examples/google-adk/README.md | 6 +++--- examples/google-adk/main.py | 2 +- examples/iflow-cli/README.md | 6 +++--- examples/iflow-cli/main.py | 2 +- examples/kimi-cli/README.md | 6 +++--- examples/kimi-cli/main.py | 2 +- examples/langgraph/README.md | 6 +++--- examples/langgraph/main.py | 2 +- examples/rl-training/README.md | 2 +- examples/rl-training/main.py | 2 +- kubernetes/config/samples/sandbox_v1alpha1_pool.yaml | 2 +- sdks/code-interpreter/csharp/README.md | 4 ++-- sdks/code-interpreter/csharp/README_zh.md | 6 +++--- sdks/code-interpreter/javascript/README.md | 4 ++-- sdks/code-interpreter/javascript/README_zh.md | 4 ++-- sdks/code-interpreter/kotlin/README.md | 4 ++-- sdks/code-interpreter/kotlin/README_zh.md | 4 ++-- sdks/code-interpreter/python/README.md | 4 ++-- sdks/code-interpreter/python/README_zh.md | 4 ++-- 33 files changed, 60 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 1e495df89..c32430e13 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ from opensandbox.models import WriteEntry async def main() -> None: # 1. Create a sandbox sandbox = await Sandbox.create( - "opensandbox/code-interpreter:v1.0.2", + "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={"PYTHON_VERSION": "3.11"}, timeout=timedelta(minutes=10), diff --git a/components/execd/README.md b/components/execd/README.md index 6cc3d43ca..8625df8ce 100644 --- a/components/execd/README.md +++ b/components/execd/README.md @@ -200,7 +200,7 @@ Set `EXECD_CLONE3_COMPAT` in `Sandbox.create` `env` so execd sees it when the sa ```python sandbox = await Sandbox.create( - "opensandbox/code-interpreter:v1.0.2", + "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={"EXECD_CLONE3_COMPAT": "1"}, ) diff --git a/components/execd/README_zh.md b/components/execd/README_zh.md index 26e012ddf..214769856 100644 --- a/components/execd/README_zh.md +++ b/components/execd/README_zh.md @@ -200,7 +200,7 @@ execd 可通过 **seccomp** 让 `clone3` 返回 **`ENOSYS`**,迫使 libc 与 G ```python sandbox = await Sandbox.create( - "opensandbox/code-interpreter:v1.0.2", + "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={"EXECD_CLONE3_COMPAT": "1"}, ) diff --git a/docs/README_zh.md b/docs/README_zh.md index 6e9fc8d71..42ea79964 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -104,7 +104,7 @@ from opensandbox.models import WriteEntry async def main() -> None: # 1. Create a sandbox sandbox = await Sandbox.create( - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint= ["/opt/opensandbox/code-interpreter.sh"], env={"PYTHON_VERSION": "3.11"}, timeout=timedelta(minutes=10), diff --git a/docs/secure-container.md b/docs/secure-container.md index 67b608847..bb608bdb0 100644 --- a/docs/secure-container.md +++ b/docs/secure-container.md @@ -546,7 +546,7 @@ spec: runtimeClassName: gvisor containers: - name: sandbox-container - image: opensandbox/code-interpreter:v1.0.2 + image: opensandbox/code-interpreter:v1.0.2.clone3.fix1 capacitySpec: bufferMax: 10 bufferMin: 2 diff --git a/examples/claude-code/README.md b/examples/claude-code/README.md index cf54b4f79..5fddc5ee5 100644 --- a/examples/claude-code/README.md +++ b/examples/claude-code/README.md @@ -7,10 +7,10 @@ Access Claude via the `claude-cli` npm package in OpenSandbox. Pre-pull the code-interpreter image (includes Node.js): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Then start the local OpenSandbox server, stdout logs will be visible in the terminal: @@ -39,7 +39,7 @@ The script installs the Claude CLI (`npm i -g @anthropic-ai/claude-code@latest`) - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `ANTHROPIC_AUTH_TOKEN`: Your Anthropic auth token (required) - `ANTHROPIC_BASE_URL`: Anthropic API endpoint (optional; e.g., self-hosted proxy) - `ANTHROPIC_MODEL`: Model name (default: `claude_sonnet4`) diff --git a/examples/claude-code/main.py b/examples/claude-code/main.py index 3b1ce92ad..29c861ecc 100644 --- a/examples/claude-code/main.py +++ b/examples/claude-code/main.py @@ -44,7 +44,7 @@ async def main() -> None: claude_model_name = os.getenv("ANTHROPIC_MODEL", "claude_sonnet4") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/code-interpreter/README.md b/examples/code-interpreter/README.md index 19882e519..a5fb9a89f 100644 --- a/examples/code-interpreter/README.md +++ b/examples/code-interpreter/README.md @@ -7,10 +7,10 @@ Complete demonstration of running Python code using the Code Interpreter SDK. Pull the prebuilt image from a registry: ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` ## Start OpenSandbox server [local] @@ -39,7 +39,7 @@ The script creates a Sandbox + CodeInterpreter, runs a Python code snippet and p - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) ## Example output @@ -117,7 +117,7 @@ spec: mountPath: /opt/opensandbox/bin containers: - name: sandbox - image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 + image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 command: - "/bin/sh" - "-c" @@ -172,7 +172,7 @@ The script creates a Sandbox + CodeInterpreter, runs a Python code snippet and p - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) ## Example output diff --git a/examples/code-interpreter/main.py b/examples/code-interpreter/main.py index 5dfaac15b..4824f62f8 100644 --- a/examples/code-interpreter/main.py +++ b/examples/code-interpreter/main.py @@ -26,7 +26,7 @@ async def main() -> None: api_key = os.getenv("SANDBOX_API_KEY") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/code-interpreter/main_use_pool.py b/examples/code-interpreter/main_use_pool.py index cf29cee30..4da131bd9 100644 --- a/examples/code-interpreter/main_use_pool.py +++ b/examples/code-interpreter/main_use_pool.py @@ -26,7 +26,7 @@ async def main() -> None: api_key = os.getenv("SANDBOX_API_KEY") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/codex-cli/README.md b/examples/codex-cli/README.md index aedb04ada..2c0a05e97 100644 --- a/examples/codex-cli/README.md +++ b/examples/codex-cli/README.md @@ -7,10 +7,10 @@ Use the official `@openai/codex` npm package to call OpenAI/Codex-like models in Pre-pull the code-interpreter image (includes Node.js): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Start the local OpenSandbox server, logs will be visible in the terminal: @@ -37,7 +37,7 @@ The script installs the Codex CLI (`npm install -g @openai/codex@latest`) at run - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `OPENAI_API_KEY`: Your OpenAI API key (required) - `OPENAI_BASE_URL`: OpenAI API endpoint (default: `https://api.openai.com/v1`) - `OPENAI_MODEL`: Model to use (default: `gpt-4o-mini`) diff --git a/examples/codex-cli/main.py b/examples/codex-cli/main.py index 5fa0bfd3a..9a0ea4422 100644 --- a/examples/codex-cli/main.py +++ b/examples/codex-cli/main.py @@ -44,7 +44,7 @@ async def main() -> None: openai_model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/gemini-cli/README.md b/examples/gemini-cli/README.md index 54dfbadcd..b3989728d 100644 --- a/examples/gemini-cli/README.md +++ b/examples/gemini-cli/README.md @@ -7,10 +7,10 @@ Call Google Gemini via the `@google/gemini-cli` npm package in OpenSandbox. Pre-pull the code-interpreter image (includes Node.js): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Start the local OpenSandbox server, logs will be visible in the terminal: @@ -37,7 +37,7 @@ The script installs the Gemini CLI (`npm install -g @google/gemini-cli@latest`) - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `GEMINI_API_KEY`: Your Google Gemini API key (required) - `GEMINI_BASE_URL`: Gemini API endpoint (optional; e.g., proxy) - `GEMINI_MODEL`: Model to use (default: `gemini-2.5-flash`) diff --git a/examples/gemini-cli/main.py b/examples/gemini-cli/main.py index 3b3d415b0..d2d12c5ec 100644 --- a/examples/gemini-cli/main.py +++ b/examples/gemini-cli/main.py @@ -44,7 +44,7 @@ async def main() -> None: gemini_model = os.getenv("GEMINI_MODEL", "gemini-2.5-flash") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/google-adk/README.md b/examples/google-adk/README.md index cecdff9a1..736c7a7dd 100644 --- a/examples/google-adk/README.md +++ b/examples/google-adk/README.md @@ -8,10 +8,10 @@ drives tool calls that execute inside a sandbox. Pre-pull the code-interpreter image (includes Python): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Start the local OpenSandbox server, logs will be visible in the terminal: @@ -40,7 +40,7 @@ cleans up the sandbox. - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `GOOGLE_API_KEY`: Gemini API key (required) - `GOOGLE_ADK_MODEL`: Gemini model name (default: `gemini-2.5-flash`) diff --git a/examples/google-adk/main.py b/examples/google-adk/main.py index ac4991ed3..d3ecbbff3 100644 --- a/examples/google-adk/main.py +++ b/examples/google-adk/main.py @@ -39,7 +39,7 @@ async def main() -> None: api_key = os.getenv("SANDBOX_API_KEY") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) model_name = os.getenv("GOOGLE_ADK_MODEL", "gemini-2.5-flash") diff --git a/examples/iflow-cli/README.md b/examples/iflow-cli/README.md index 195debcaf..7d5ff39b5 100644 --- a/examples/iflow-cli/README.md +++ b/examples/iflow-cli/README.md @@ -7,10 +7,10 @@ Call OpenAI-compatible iFlow/custom HTTP endpoints via the `iflow-cli` npm packa Pre-pull the code-interpreter image (includes Node.js): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Start the local OpenSandbox server, logs will be visible in the terminal: @@ -39,7 +39,7 @@ The script installs the iFlow CLI (`npm install -g @iflow-ai/iflow-cli@latest`) - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `IFLOW_API_KEY`: Your iFlow/DashScope API key (required) - `IFLOW_BASE_URL`: The iFlow API endpoint URL (default: `https://apis.iflow.cn/v1`) - `IFLOW_MODEL_NAME`: Model to use (default: `qwen3-coder-plus`) diff --git a/examples/iflow-cli/main.py b/examples/iflow-cli/main.py index a78e8b0ab..eb5034b0c 100644 --- a/examples/iflow-cli/main.py +++ b/examples/iflow-cli/main.py @@ -45,7 +45,7 @@ async def main() -> None: iflow_model_name = os.getenv("IFLOW_MODEL_NAME", "qwen3-coder-plus") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/kimi-cli/README.md b/examples/kimi-cli/README.md index db28ab910..56437ef16 100644 --- a/examples/kimi-cli/README.md +++ b/examples/kimi-cli/README.md @@ -7,10 +7,10 @@ Run [Kimi Code CLI](https://github.com/MoonshotAI/kimi-cli) (Moonshot AI) inside Pre-pull the code-interpreter image (includes Python 3.12+): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Then start the local OpenSandbox server, stdout logs will be visible in the terminal: @@ -37,7 +37,7 @@ The script installs Kimi Code CLI (`pip install kimi-cli`) at runtime (Python 3. - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `KIMI_API_KEY`: Your Moonshot AI / Kimi API key (required) - `KIMI_BASE_URL`: Kimi API endpoint (optional; defaults to Kimi's official endpoint) - `KIMI_MODEL_NAME`: Model to use (default: `kimi-k2.5`) diff --git a/examples/kimi-cli/main.py b/examples/kimi-cli/main.py index 6cbad5519..f94bd4a00 100644 --- a/examples/kimi-cli/main.py +++ b/examples/kimi-cli/main.py @@ -44,7 +44,7 @@ async def main() -> None: kimi_model_name = os.getenv("KIMI_MODEL_NAME", "kimi-k2.5") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/langgraph/README.md b/examples/langgraph/README.md index d091cd072..e8c50f5e1 100644 --- a/examples/langgraph/README.md +++ b/examples/langgraph/README.md @@ -9,10 +9,10 @@ a decision node to retry with a fallback command if the run step fails. Pre-pull the code-interpreter image (includes Python): ```shell -docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 +docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 # use docker hub -# docker pull opensandbox/code-interpreter:v1.0.2 +# docker pull opensandbox/code-interpreter:v1.0.2.clone3.fix1 ``` Start the local OpenSandbox server, logs will be visible in the terminal: @@ -42,7 +42,7 @@ The workflow writes files, executes a job, retries with a fallback command on fa - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication (optional for local) -- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Sandbox image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `ANTHROPIC_API_KEY`: Your Anthropic API key (required if `ANTHROPIC_AUTH_TOKEN` is unset) - `ANTHROPIC_AUTH_TOKEN`: Alternate Anthropic auth token (uses `Authorization` header) - `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` should not be set together diff --git a/examples/langgraph/main.py b/examples/langgraph/main.py index a31e1a65d..2d3df02ca 100644 --- a/examples/langgraph/main.py +++ b/examples/langgraph/main.py @@ -86,7 +86,7 @@ async def create_sandbox(state: WorkflowState) -> WorkflowState: api_key = os.getenv("SANDBOX_API_KEY") image = os.getenv( "SANDBOX_IMAGE", - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", ) config = ConnectionConfig( diff --git a/examples/rl-training/README.md b/examples/rl-training/README.md index f61da8568..4960562fe 100644 --- a/examples/rl-training/README.md +++ b/examples/rl-training/README.md @@ -30,7 +30,7 @@ The script provisions a sandbox, installs RL dependencies, trains a DQN agent on - `SANDBOX_DOMAIN`: Sandbox service address (default: `localhost:8080`) - `SANDBOX_API_KEY`: API key if your server requires authentication -- `SANDBOX_IMAGE`: Docker image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2`) +- `SANDBOX_IMAGE`: Docker image to use (default: `sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1`) - `RL_TIMESTEPS`: Training timesteps to run (default: `5000`) ## TensorBoard diff --git a/examples/rl-training/main.py b/examples/rl-training/main.py index 345609a2b..32cde6d8f 100644 --- a/examples/rl-training/main.py +++ b/examples/rl-training/main.py @@ -136,7 +136,7 @@ async def _install_requirements(sandbox: Sandbox) -> bool: async def main() -> None: domain = os.getenv("SANDBOX_DOMAIN", "localhost:8080") api_key = os.getenv("SANDBOX_API_KEY") - image = os.getenv("SANDBOX_IMAGE", "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2") + image = os.getenv("SANDBOX_IMAGE", "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1") timesteps = os.getenv("RL_TIMESTEPS", "5000") config = ConnectionConfig( diff --git a/kubernetes/config/samples/sandbox_v1alpha1_pool.yaml b/kubernetes/config/samples/sandbox_v1alpha1_pool.yaml index 80973c353..20df3bdc2 100644 --- a/kubernetes/config/samples/sandbox_v1alpha1_pool.yaml +++ b/kubernetes/config/samples/sandbox_v1alpha1_pool.yaml @@ -44,7 +44,7 @@ spec: mountPath: /opt/opensandbox/bin containers: - name: sandbox - image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2 + image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1 command: - "/bin/sh" - "-c" diff --git a/sdks/code-interpreter/csharp/README.md b/sdks/code-interpreter/csharp/README.md index d912b152b..5db84d010 100644 --- a/sdks/code-interpreter/csharp/README.md +++ b/sdks/code-interpreter/csharp/README.md @@ -40,7 +40,7 @@ try await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { ConnectionConfig = config, - Image = "opensandbox/code-interpreter:v1.0.2", + Image = "opensandbox/code-interpreter:v1.0.2.clone3.fix1", Entrypoint = new[] { "/opt/opensandbox/code-interpreter.sh" }, Env = new Dictionary { @@ -88,7 +88,7 @@ using var loggerFactory = LoggerFactory.Create(builder => await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { ConnectionConfig = new ConnectionConfig(), - Image = "opensandbox/code-interpreter:v1.0.2", + Image = "opensandbox/code-interpreter:v1.0.2.clone3.fix1", Entrypoint = new[] { "/opt/opensandbox/code-interpreter.sh" }, Diagnostics = new SdkDiagnosticsOptions { diff --git a/sdks/code-interpreter/csharp/README_zh.md b/sdks/code-interpreter/csharp/README_zh.md index 1e2c7f932..9292deb55 100644 --- a/sdks/code-interpreter/csharp/README_zh.md +++ b/sdks/code-interpreter/csharp/README_zh.md @@ -47,7 +47,7 @@ var config = new ConnectionConfig(new ConnectionConfigOptions await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { ConnectionConfig = config, - Image = "opensandbox/code-interpreter:v1.0.2", + Image = "opensandbox/code-interpreter:v1.0.2.clone3.fix1", Entrypoint = new[] { "/opt/opensandbox/code-interpreter.sh" }, Env = new Dictionary { @@ -94,7 +94,7 @@ using var loggerFactory = LoggerFactory.Create(builder => await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { - Image = "opensandbox/code-interpreter:v1.0.2", + Image = "opensandbox/code-interpreter:v1.0.2.clone3.fix1", Diagnostics = new SdkDiagnosticsOptions { LoggerFactory = loggerFactory @@ -131,7 +131,7 @@ Code Interpreter SDK 依赖于专门的环境。请确保您的沙箱提供者 await using var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions { ConnectionConfig = config, - Image = "opensandbox/code-interpreter:v1.0.2", + Image = "opensandbox/code-interpreter:v1.0.2.clone3.fix1", Entrypoint = new[] { "/opt/opensandbox/code-interpreter.sh" }, Env = new Dictionary { diff --git a/sdks/code-interpreter/javascript/README.md b/sdks/code-interpreter/javascript/README.md index d42c7aba4..63349b2c5 100644 --- a/sdks/code-interpreter/javascript/README.md +++ b/sdks/code-interpreter/javascript/README.md @@ -49,7 +49,7 @@ const config = new ConnectionConfig({ // 2. Create a Sandbox with the code-interpreter image + runtime versions const sandbox = await Sandbox.create({ connectionConfig: config, - image: "opensandbox/code-interpreter:v1.0.2", + image: "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint: ["/opt/opensandbox/code-interpreter.sh"], env: { PYTHON_VERSION: "3.11", @@ -99,7 +99,7 @@ You can specify the desired version of a programming language by setting the cor ```ts const sandbox = await Sandbox.create({ connectionConfig: config, - image: "opensandbox/code-interpreter:v1.0.2", + image: "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint: ["/opt/opensandbox/code-interpreter.sh"], env: { JAVA_VERSION: "17", diff --git a/sdks/code-interpreter/javascript/README_zh.md b/sdks/code-interpreter/javascript/README_zh.md index 43bd480a2..db12dfb66 100644 --- a/sdks/code-interpreter/javascript/README_zh.md +++ b/sdks/code-interpreter/javascript/README_zh.md @@ -49,7 +49,7 @@ const config = new ConnectionConfig({ // 2. 创建 Sandbox(必须使用 code-interpreter 镜像),并指定语言版本 const sandbox = await Sandbox.create({ connectionConfig: config, - image: "opensandbox/code-interpreter:v1.0.2", + image: "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint: ["/opt/opensandbox/code-interpreter.sh"], env: { PYTHON_VERSION: "3.11", @@ -99,7 +99,7 @@ Code Interpreter SDK 依赖于特定的运行环境。请确保你的沙箱服 ```ts const sandbox = await Sandbox.create({ connectionConfig: config, - image: "opensandbox/code-interpreter:v1.0.2", + image: "opensandbox/code-interpreter:v1.0.2.clone3.fix1", entrypoint: ["/opt/opensandbox/code-interpreter.sh"], env: { JAVA_VERSION: "17", diff --git a/sdks/code-interpreter/kotlin/README.md b/sdks/code-interpreter/kotlin/README.md index 59fced7e7..b88e7005b 100644 --- a/sdks/code-interpreter/kotlin/README.md +++ b/sdks/code-interpreter/kotlin/README.md @@ -55,7 +55,7 @@ public class QuickStart { // Use try-with-resources to ensure sandbox is closed try (Sandbox sandbox = Sandbox.builder() .connectionConfig(config) - .image("opensandbox/code-interpreter:v1.0.2") + .image("opensandbox/code-interpreter:v1.0.2.clone3.fix1") .entrypoint("/opt/opensandbox/code-interpreter.sh") .env("PYTHON_VERSION", "3.11") // Select specific language version .build()) { @@ -115,7 +115,7 @@ You can specify the desired version of a programming language by setting the cor ```java Sandbox sandbox = Sandbox.builder() - .image("opensandbox/code-interpreter:v1.0.2") + .image("opensandbox/code-interpreter:v1.0.2.clone3.fix1") .entrypoint("/opt/opensandbox/code-interpreter.sh") .env("JAVA_VERSION", "17") .env("GO_VERSION", "1.23") diff --git a/sdks/code-interpreter/kotlin/README_zh.md b/sdks/code-interpreter/kotlin/README_zh.md index 4c3e5133c..e2d4c702d 100644 --- a/sdks/code-interpreter/kotlin/README_zh.md +++ b/sdks/code-interpreter/kotlin/README_zh.md @@ -55,7 +55,7 @@ public class QuickStart { // 使用 try-with-resources 确保资源正确关闭 try (Sandbox sandbox = Sandbox.builder() .connectionConfig(config) - .image("sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2") + .image("sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1") .entrypoint("/opt/opensandbox/code-interpreter.sh") .env("PYTHON_VERSION", "3.11") // 指定语言版本 .build()) { @@ -115,7 +115,7 @@ Code Interpreter SDK 依赖于特定的运行环境。请确保你的沙箱服 ```java Sandbox sandbox = Sandbox.builder() - .image("opensandbox/code-interpreter:v1.0.2") + .image("opensandbox/code-interpreter:v1.0.2.clone3.fix1") .entrypoint("/opt/opensandbox/code-interpreter.sh") .env("JAVA_VERSION", "17") .env("GO_VERSION", "1.23") diff --git a/sdks/code-interpreter/python/README.md b/sdks/code-interpreter/python/README.md index a3deb46c2..c4108acee 100644 --- a/sdks/code-interpreter/python/README.md +++ b/sdks/code-interpreter/python/README.md @@ -52,7 +52,7 @@ async def main() -> None: # 2. Create a Sandbox with the code-interpreter image + runtime versions sandbox = await Sandbox.create( - "opensandbox/code-interpreter:v1.0.2", + "opensandbox/code-interpreter:v1.0.2.clone3.fix1", connection_config=config, entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={ @@ -113,7 +113,7 @@ config = ConnectionConfigSync( ) sandbox = SandboxSync.create( - "opensandbox/code-interpreter:v1.0.2", + "opensandbox/code-interpreter:v1.0.2.clone3.fix1", connection_config=config, entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={"PYTHON_VERSION": "3.11"}, diff --git a/sdks/code-interpreter/python/README_zh.md b/sdks/code-interpreter/python/README_zh.md index 18c97534a..3b4dea5cf 100644 --- a/sdks/code-interpreter/python/README_zh.md +++ b/sdks/code-interpreter/python/README_zh.md @@ -48,7 +48,7 @@ async def main() -> None: # 2. 创建 Sandbox(必须使用 code-interpreter 镜像),并指定语言版本 sandbox = await Sandbox.create( - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", connection_config=config, entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={ @@ -108,7 +108,7 @@ config = ConnectionConfigSync( ) sandbox = SandboxSync.create( - "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2", + "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.0.2.clone3.fix1", connection_config=config, entrypoint=["/opt/opensandbox/code-interpreter.sh"], env={"PYTHON_VERSION": "3.11"},