-
Notifications
You must be signed in to change notification settings - Fork 1.1k
examples(code-sandbox-quickstart): host argv tool allowlist + reference tool loop (#645) [closed → see #1219] #1062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
cgflag
wants to merge
21
commits into
TencentCloud:master
from
cgflag:feat/agent-tool-allowlist-sandbox
Closed
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
8f7e2ff
feat(examples): add agent tool argv allowlist sandbox (#645)
cgflag 64d0fe5
feat(examples): add thin Dockerfile for agent-tool-allowlist (#645)
cgflag 19e549a
test(examples): add local allowlist unit tests (#645)
cgflag f817387
docs(examples): document Path B template and layer honesty (#645)
cgflag c6dd509
fix(examples): avoid remote Dockerfile frontend dependency (#645)
cgflag ca731d2
test(examples): exercise Windows path rejection branch (#645)
cgflag 76ee7fa
feat(examples): add local verify gate and allowlist sync (#645)
cgflag b4b04d5
docs(examples): document verify_local and host DNS caveat (#645)
cgflag d237405
feat(examples): add sidecar allow path for host without DNS (#645)
cgflag f841f37
docs(examples): document host sidecar allow path (#645)
cgflag 68d047a
docs(examples): trim allowlist README to Quick Start style (#645)
cgflag 0541764
test(examples): assert deny path never calls Sandbox.create (#645)
cgflag 0551642
feat(examples): stack Mode-1 airgap on allowlist allow path (#645)
cgflag b776fac
feat(examples): treat interpreter as explicit code-execution capabili…
cgflag e763e59
refactor(examples): DRY assert_allowlisted via is_allowlisted (#645)
cgflag af55c07
fix(examples): use resolved_path consistently in load_local_dotenv (#…
cgflag fa9b32b
chore(examples): tighten allowlist example hygiene from bot nits (#645)
cgflag ea18327
chore(examples): final allowlist hygiene nits (#645)
cgflag 2802bc9
fix(examples): unify deny messages and AST-guard Sandbox.create (#645)
cgflag 0348de6
docs(examples): avoid stale test names; note shlex path caveat (#645)
cgflag bb5732f
fix(examples): harden shlex denials and verify I/O checks (#645)
cgflag File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Required: Cube API server address (dev-env host forward defaults to :13000) | ||
| export E2B_API_URL="http://127.0.0.1:13000" | ||
|
|
||
| # Required: any non-empty value satisfies the SDK check | ||
| export E2B_API_KEY="e2b_000000" | ||
|
|
||
| # Required: template ID from cubemastercli tpl create-from-image | ||
| export CUBE_TEMPLATE_ID="<your-template-id>" | ||
|
|
||
| # --- Host-side allow path without wildcard DNS (run_allowlisted_sidecar.py) --- | ||
| # See docs/guide/connect-existing-cluster.md Option D + examples/e2b-dev-sidecar | ||
| # export CUBE_REMOTE_PROXY_BASE="https://127.0.0.1:11443" | ||
| # export CUBE_REMOTE_PROXY_VERIFY_SSL="false" | ||
| # export CUBE_REMOTE_SANDBOX_DOMAIN="cube.app" | ||
|
|
||
| # Optional: only needed when using Cube's built-in mkcert certificate | ||
| # export SSL_CERT_FILE="/root/.local/share/mkcert/rootCA.pem" | ||
|
|
||
| # Optional: verify_local.py knobs | ||
| # export ALLOWLIST_IMAGE_TAG="agent-tool-allowlist-sandbox:night-verified" | ||
| # export ALLOWLIST_USE_SIDECAR="1" # use run_allowlisted_sidecar.py when env is set |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| .venv/ | ||
| __pycache__/ | ||
| *.py[cod] | ||
| .env |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # Thin wrapper on the official Cube Sandbox code image. | ||
| # Purpose: give this example a buildable template path for #645, without | ||
| # adding a new language/runtime stack. | ||
| # | ||
| # Markers baked into the image: | ||
| # - ENV TOOL_ALLOWLIST_SANDBOX=1 | ||
| # - /etc/cube-sandbox/tool-allowlist.txt (demo allowlist file) | ||
| # | ||
| # The allowlist file body must stay aligned with allowlist.DEFAULT_ALLOWED_BINARIES. | ||
| # Check with: python verify_local.py | ||
| # | ||
| # Build (from this directory): | ||
| # docker build -t agent-tool-allowlist-sandbox:latest . | ||
| # | ||
| # Register as a Cube template (same flags as code-sandbox-quickstart): | ||
| # cubemastercli tpl create-from-image \ | ||
| # --image <your-registry>/agent-tool-allowlist-sandbox:latest \ | ||
| # --writable-layer-size 1G \ | ||
| # --expose-port 49999 \ | ||
| # --expose-port 49983 \ | ||
| # --probe 49999 | ||
| # | ||
| # Base image registries (same as examples/code-sandbox-quickstart/README.md): | ||
| # CN: cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest | ||
| # INT: cube-sandbox-int.tencentcloudcr.com/cube-sandbox/sandbox-code:latest | ||
|
|
||
| ARG SANDBOX_CODE_IMAGE=cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest | ||
| FROM ${SANDBOX_CODE_IMAGE} | ||
|
|
||
| ENV TOOL_ALLOWLIST_SANDBOX=1 | ||
|
|
||
| # Demo allowlist file inside the guest (informational; host-side gate remains | ||
| # the enforcement point for this example — see README Limitations). | ||
| # Names are sorted to match allowlist_sync.allowlist_file_body(). | ||
| RUN mkdir -p /etc/cube-sandbox \ | ||
| && printf '%s\n' \ | ||
| '# Agent tool argv allowlist (demo; host gate is authoritative)' \ | ||
| 'cat' \ | ||
| 'echo' \ | ||
| 'head' \ | ||
| 'ls' \ | ||
| 'pwd' \ | ||
| 'sha256sum' \ | ||
| 'uname' \ | ||
| 'wc' \ | ||
| > /etc/cube-sandbox/tool-allowlist.txt | ||
|
|
||
| # Ports inherited from sandbox-code / quickstart convention. | ||
| EXPOSE 49999 49983 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| # Agent Tool Allowlist Sandbox | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. README references specific test method names If these tests are renamed, the README becomes stale. Consider describing the concept rather than exact method identifiers. |
||
|
|
||
| [中文文档](README_zh.md) | ||
|
|
||
| Demonstrates argv allowlisting for agent tools **before** `Sandbox.create`: | ||
| allowlisted binaries run in a Cube Sandbox MicroVM; others fail on the host | ||
| (no sandbox on the deny path). | ||
|
|
||
| The gate is host-side (`assert_allowlisted`). It is not egress CIDR policy or | ||
| guest kernel enforcement. | ||
|
|
||
| **Use when:** the host may only forward a fixed tool set (`echo` / `ls` / | ||
| `cat`, …) and must reject shells / network tools early. Interpreters are an | ||
| explicit capability (`enable_code_execution=True`), not part of the default set. | ||
|
|
||
| **Not for:** full agent frameworks, or replacing | ||
| [`network-policy`](../network-policy). | ||
|
|
||
| ## 1. Prerequisites | ||
|
|
||
| - A running Cube Sandbox deployment ([dev environment](../../docs/guide/dev-environment.md)) | ||
| - Python 3.8+ | ||
| - Docker only if you use Path B | ||
|
|
||
| ```bash | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| ## 2. Quick Start | ||
|
|
||
| ### Step 1 — Create a template (Recommended) | ||
|
|
||
| ```bash | ||
| cubemastercli tpl create-from-image \ | ||
| --image cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest \ | ||
| --writable-layer-size 1G \ | ||
| --expose-port 49999 \ | ||
| --expose-port 49983 \ | ||
| --probe 49999 | ||
| ``` | ||
|
|
||
| Note the printed `template_id`. Outside CN, use | ||
| `cube-sandbox-int.tencentcloudcr.com/cube-sandbox/sandbox-code:latest`. | ||
|
|
||
| | Item | Suggestion | | ||
| |------|------------| | ||
| | Writable layer | `1G` | | ||
| | Ports | `49999`, `49983`; `--probe 49999` | | ||
|
|
||
| ### Step 2 — Configure environment | ||
|
|
||
| ```bash | ||
| cp .env.example .env | ||
| # set E2B_API_URL (e.g. http://127.0.0.1:13000) and CUBE_TEMPLATE_ID | ||
| ``` | ||
|
|
||
| ### Step 3 — Run | ||
|
|
||
| ```bash | ||
| python verify_local.py # unit + deny; no sandbox | ||
| python run_allowlisted.py # allow (needs *.cube.app DNS or run in dev VM) | ||
| python run_denied.py # deny on host; no sandbox | ||
| ``` | ||
|
|
||
| Allow (host gate passes, then create with `allow_internet_access=False` — | ||
| [`network-policy`](../network-policy) Mode 1 airgap; argv allow ≠ network): | ||
|
|
||
| ```text | ||
| egress: allow_internet_access=False (airgap; argv gate != network) | ||
| agent-tool-allowlist-ok | ||
| artifact: artifact-ok | ||
| ``` | ||
|
|
||
| Deny: | ||
|
|
||
| ```text | ||
| denied_as_expected: command not on tool allowlist: 'bash' ... | ||
| ``` | ||
|
|
||
| Evidence that deny never calls `Sandbox.create`: see the unit tests in | ||
| `test_allowlist.py` that cover host-gate-before-create ordering and that | ||
| `run_denied.py` has no `Sandbox.create` call (also covered by `verify_local.py`). | ||
|
|
||
| On a host without `*.cube.app` DNS, use `python run_allowlisted_sidecar.py` | ||
| instead of `run_allowlisted.py` (set proxy vars in `.env.example`; see | ||
| [`e2b-dev-sidecar`](../e2b-dev-sidecar)). Optional `verify_local` knobs: | ||
| `ALLOWLIST_IMAGE_TAG`, `ALLOWLIST_USE_SIDECAR` (see `.env.example`). | ||
|
|
||
| ## 3. Path B (optional) — build this example image | ||
|
|
||
| ```bash | ||
| docker build -t agent-tool-allowlist-sandbox:latest . | ||
| # optional: --build-arg SANDBOX_CODE_IMAGE=.../sandbox-code:latest | ||
|
|
||
| cubemastercli tpl create-from-image \ | ||
| --image agent-tool-allowlist-sandbox:latest \ | ||
| --writable-layer-size 1G \ | ||
| --expose-port 49999 \ | ||
| --expose-port 49983 \ | ||
| --probe 49999 | ||
| ``` | ||
|
|
||
| If CubeMaster cannot see a local tag, retag/push to a reachable registry first. | ||
|
|
||
| ## 4. Default allowlist | ||
|
|
||
| `allowlist.py` (`DEFAULT_ALLOWED_BINARIES`): `echo`, `uname`, `pwd`, `ls`, | ||
| `cat`, `head`, `wc`, `sha256sum`. Path-style binaries and shells such as | ||
| `bash` / `curl` are rejected. `python3` lives in `CODE_EXECUTION_BINARIES` and | ||
| is only added when `enable_code_execution=True`. | ||
|
|
||
| ## 5. Limitations | ||
|
|
||
| - This demo is **capability-style tool gating** on the first argv token — not | ||
| full parameter policy. Combining small tools / redirects is out of scope. | ||
| - Default policy **denies interpreter execution**. Enabling `python3` grants | ||
| arbitrary code execution inside the guest, not "one more binary". | ||
| Passing a custom `allowed_binaries` that includes `python3` also grants that | ||
| capability without `enable_code_execution=True`. | ||
| - Host-side gate only — callers that skip `assert_allowlisted` can still send | ||
| any command to the API. MicroVM isolation ≠ guest capability control. | ||
| - Mode 1 airgap blocks egress; it does **not** stop local misuse in the guest. | ||
| Network tools stay off the default argv list; use [`network-policy`](../network-policy) | ||
| for CIDR policy. | ||
| - In-image `/etc/cube-sandbox/tool-allowlist.txt` (Path B) is informational; | ||
| the host gate is authoritative for this demo. Production should set | ||
| capabilities explicitly (do not casually `| CODE_EXECUTION_BINARIES`). | ||
|
|
||
| ## 6. Directory | ||
|
|
||
| ```text | ||
| agent-tool-allowlist-sandbox/ | ||
| ├── README.md | ||
| ├── README_zh.md | ||
| ├── Dockerfile | ||
| ├── allowlist.py | ||
| ├── allowlist_sync.py | ||
| ├── verify_local.py | ||
| ├── run_allowlisted.py | ||
| ├── run_allowlisted_sidecar.py | ||
| ├── run_denied.py | ||
| ├── test_allowlist.py | ||
| ├── env_utils.py | ||
| ├── requirements.txt | ||
| └── .env.example | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| # Agent 工具白名单沙箱 | ||
|
|
||
| [English](README.md) | ||
|
|
||
| 演示在 `Sandbox.create` **之前**对 Agent 工具做 argv 白名单: | ||
| 白名单内命令在 Cube Sandbox MicroVM 中执行;非白名单在宿主机失败(拒绝路径不建沙箱)。 | ||
|
|
||
| 门控在宿主机(`assert_allowlisted`),不能替代出口 CIDR 或 guest 内核强制。 | ||
|
|
||
| **适用:** 调用方只允许转发固定工具集(`echo` / `ls` / `cat` 等),并尽早拒绝 | ||
| shell / 网络类工具。解释器是显式能力(`enable_code_execution=True`),不在默认集。 | ||
|
|
||
| **不适用:** 完整 Agent 框架,或替代 [`network-policy`](../network-policy)。 | ||
|
|
||
| ## 1. 前置条件 | ||
|
|
||
| - 已部署的 Cube Sandbox([开发环境](../../docs/zh/guide/dev-environment.md)) | ||
| - Python 3.8+ | ||
| - 仅 Path B 需要 Docker | ||
|
|
||
| ```bash | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| ## 2. Quick Start | ||
|
|
||
| ### Step 1 — 创建模板(推荐) | ||
|
|
||
| ```bash | ||
| cubemastercli tpl create-from-image \ | ||
| --image cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest \ | ||
| --writable-layer-size 1G \ | ||
| --expose-port 49999 \ | ||
| --expose-port 49983 \ | ||
| --probe 49999 | ||
| ``` | ||
|
|
||
| 记下 `template_id`。海外可用 | ||
| `cube-sandbox-int.tencentcloudcr.com/cube-sandbox/sandbox-code:latest`。 | ||
|
|
||
| | 项 | 建议 | | ||
| |----|------| | ||
| | 可写层 | `1G` | | ||
| | 端口 | `49999`、`49983`;`--probe 49999` | | ||
|
|
||
| ### Step 2 — 配置环境 | ||
|
|
||
| ```bash | ||
| cp .env.example .env | ||
| # 填写 E2B_API_URL(如 http://127.0.0.1:13000)与 CUBE_TEMPLATE_ID | ||
| ``` | ||
|
|
||
| ### Step 3 — 运行 | ||
|
|
||
| ```bash | ||
| python verify_local.py # 单测 + 拒绝;不需沙箱 | ||
| python run_allowlisted.py # 放行(需 *.cube.app DNS 或在开发虚机内) | ||
| python run_denied.py # 宿主机拒绝;不建沙箱 | ||
| ``` | ||
|
|
||
| 放行(宿主机门控通过后,`Sandbox.create` 带 | ||
| `allow_internet_access=False`——[`network-policy`](../network-policy) Mode 1 | ||
| 断网;argv 放行 ≠ 网络通): | ||
|
|
||
| ```text | ||
| egress: allow_internet_access=False (airgap; argv gate != network) | ||
| agent-tool-allowlist-ok | ||
| artifact: artifact-ok | ||
| ``` | ||
|
|
||
| 拒绝: | ||
|
|
||
| ```text | ||
| denied_as_expected: command not on tool allowlist: 'bash' ... | ||
| ``` | ||
|
|
||
| 拒绝路径零 `Sandbox.create` 的证据:见 `test_allowlist.py` 中覆盖 | ||
| 「门控先于 create」以及「`run_denied.py` 无 `Sandbox.create` 调用」的用例 | ||
| (`verify_local.py` 会跑到)。 | ||
|
|
||
| 宿主机无 `*.cube.app` DNS 时,用 `python run_allowlisted_sidecar.py` 替代 | ||
| `run_allowlisted.py`(代理变量见 `.env.example`;另见 | ||
| [`e2b-dev-sidecar`](../e2b-dev-sidecar))。`verify_local` 可选环境变量: | ||
| `ALLOWLIST_IMAGE_TAG`、`ALLOWLIST_USE_SIDECAR`(见 `.env.example`)。 | ||
|
|
||
| ## 3. Path B(可选)— 构建本示例镜像 | ||
|
|
||
| ```bash | ||
| docker build -t agent-tool-allowlist-sandbox:latest . | ||
| # 可选: --build-arg SANDBOX_CODE_IMAGE=.../sandbox-code:latest | ||
|
|
||
| cubemastercli tpl create-from-image \ | ||
| --image agent-tool-allowlist-sandbox:latest \ | ||
| --writable-layer-size 1G \ | ||
| --expose-port 49999 \ | ||
| --expose-port 49983 \ | ||
| --probe 49999 | ||
| ``` | ||
|
|
||
| 若 CubeMaster 看不到本地 tag,先打标签推到可拉取的仓库。 | ||
|
|
||
| ## 4. 默认白名单 | ||
|
|
||
| `allowlist.py`(`DEFAULT_ALLOWED_BINARIES`):`echo`、`uname`、`pwd`、`ls`、 | ||
| `cat`、`head`、`wc`、`sha256sum`。路径形式二进制以及 `bash` / `curl` 等会被拒绝。 | ||
| `python3` 在 `CODE_EXECUTION_BINARIES` 中,仅当 `enable_code_execution=True` 时并入。 | ||
|
|
||
| ## 5. 限制 | ||
|
|
||
| - 本示例是基于**首个 argv token** 的能力式工具门控,不是完整参数策略;小工具组合 / | ||
| 重定向等不在范围内。 | ||
| - 默认**拒绝解释器**。打开 `python3` 等于授予 guest 内任意代码执行,不是「多一个二进制」。 | ||
| 若自定义 `allowed_binaries` 直接包含 `python3`,即使未设 `enable_code_execution=True` | ||
| 也会获得同等能力。 | ||
| - 仅宿主机门控——跳过 `assert_allowlisted` 仍可向 API 发任意命令。MicroVM 隔离 ≠ | ||
| guest 内能力控制。 | ||
| - Mode 1 断网只挡出站,**不**防 guest 本地滥用。网络类工具不在默认 argv 名单;CIDR | ||
| 见 [`network-policy`](../network-policy)。 | ||
| - Path B 的 `/etc/cube-sandbox/tool-allowlist.txt` 仅为信息标记;生产应显式配置能力, | ||
| 勿随意 `| CODE_EXECUTION_BINARIES`。 | ||
|
|
||
| ## 6. 目录结构 | ||
|
|
||
| ```text | ||
| agent-tool-allowlist-sandbox/ | ||
| ├── README.md | ||
| ├── README_zh.md | ||
| ├── Dockerfile | ||
| ├── allowlist.py | ||
| ├── allowlist_sync.py | ||
| ├── verify_local.py | ||
| ├── run_allowlisted.py | ||
| ├── run_allowlisted_sidecar.py | ||
| ├── run_denied.py | ||
| ├── test_allowlist.py | ||
| ├── env_utils.py | ||
| ├── requirements.txt | ||
| └── .env.example | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: consider placing this entry near other agent-tooling examples
The "Agent Tool Allowlist Sandbox" is an agent-tooling example (alongside OpenClaw, OpenAI Agents SDK, OpenAI Agents + Code Interpreter). Appending it at the end of the table separates it from peers that users browsing agent integrations are most likely scanning. Consider inserting it after the "OpenAI Agents + Code Interpreter" row (or after "OpenAI Agents SDK Integration") to keep the agent-tooling cluster together. The same organizational note applies to
docs/zh/guide/tutorials/examples.md.