← 返回列表
未验证
状态:实验性 / v0.1
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/8 · 已提供中文文档
综合分
28.6
GitHub 分
28.6
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add wpan36/dsh-gvisor该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
信任档位:需留意实装验证未通过
- 是什么
- dsh 原生插件 · chat
- 装得上吗
- 实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 17 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/9/25) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
数据截至 2026/9/21(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-agent@deepseek-ai/dsh-agent-loop@deepseek-ai/dsh-app-boot@deepseek-ai/dsh-bash-local@deepseek-ai/dsh-fs-observation-policy@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-shell-env@deepseek-ai/dsh-system-prompt@deepseek-ai/dsh-sandbox-policy@deepseek-ai/dsh-terminal@deepseek-ai/dsh-terminal-bash用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-gvisor
状态:实验性 / v0.1
dsh-gvisor 是一个树外的 DeepSeek Harness 执行世界提供程序,由
Docker + gVisor(runsc)提供支持。
它为以下内容提供一个共享沙箱:
- ctx.fs
- ctx.subprocess
- spawnTerminal() / PTY 会话
无需修改 DeepSeek Harness 源代码。
Harness agent / tools
│
├── ctx.fs ───────────────┐
└── ctx.subprocess ───────┤
▼
dsh-gvisor owner
(trusted host)
│
fixed Docker policy
▼
one runsc container
├── /workspace
├── bounded /tmp
└── managed workers
gVisor PR #14517 中的原始集成
将选定的命令通过一个启动器进行路由。这验证了 Harness → Docker → runsc → gVisor,
但也暴露了一个重要的局限性:如果工作负载能够直接访问 Docker
守护进程,它就可以绕过启动器级别的策略。
dsh-gvisor 将 Docker/运行时策略移入受信任的 Harness
执行世界提供程序中。正常的 Harness 文件系统、bash 和终端
使用者会自动进入同一个 gVisor 世界。
这遵循了
gVisor issue #14145 中讨论的方向。
快速开始
要求
Linux 主机,需具备:
- Node 22.19+ 或 24+
- Git
- Python 3
- Bash
- Docker
- 已注册的 gVisor runsc 运行时
- Docker 对 bind-recursive=disabled 的支持
该提供程序有意使用:
/usr/bin/docker
unix:///var/run/docker.sock
以具有 Docker 访问权限的非 root 用户身份运行该提供程序。
1. 克隆两个仓库
从一个新目录开始:
mkdir -p ~/dsh-gvisor-play
cd ~/dsh-gvisor-play
git clone https://github.com/wpan36/dsh-gvisor.git
git clone https://github.com/deepseek-ai/deepseek-harness.git
将 Harness 固定到构建和测试此插件时所针对的修订版本:
git -C deepseek-harness checkout cd5ef8148158c3a752a658978873241fdf8e2bbc
现在你应该拥有:
~/dsh-gvisor-play/
├── deepseek-harness
└── dsh-gvisor
2. 验证 gVisor 确实可用
使用
gVisor Docker 设置指南安装并注册 runsc。
对于标准 Docker 注册:
runsc --version
/usr/bin/docker \
--host=unix:///var/run/docker.sock \
info --format '{{json .Runtimes}}'
docker run --rm --runtime=runsc ubuntu dmesg | head
最后一条命令应显示 gVisor 启动输出,例如:
Starting gVisor...
仅有 Docker 运行时条目是不够的:旧的注册仍可能指向
已删除的 runsc 二进制文件。
如果你有效的 gVisor 注册使用了其他名称:
export DSH_GVISOR_RUNTIME=runsc-custombash
export DSH_GVISOR_TEST_RUNTIME="$DSH_GVISOR_RUNTIME"
否则:
bash
export DSH_GVISOR_RUNTIME=runsc
export DSH_GVISOR_TEST_RUNTIME=runsc
如果选定的注册项解析为 runc,提供程序会以失败关闭(fail closed)方式处理。
3. 安装并构建固定版本的 Harness 检出
固定版本的 Harness 目前并未从此处的 npm 安装;请使用上面的源代码检出。
bash
cd ~/dsh-gvisor-play/deepseek-harness
corepack pnpm install --frozen-lockfile
corepack pnpm run build:lib:host
此全新检出的安装/构建路径已手动验证。
4. 链接并构建 dsh-gvisor
bash
cd ~/dsh-gvisor-play/dsh-gvisor
npm run dev:link -- ../deepseek-harness
npm run typecheck
npm test
npm run image:build
dev:link 仅在此仓库被忽略的 node_modules 内创建链接。
它不会修改 Harness 检出。
5. 运行真实的 gVisor E2E 测试套件
bash
DSH_GVISOR_TEST_RUNTIME="$DSH_GVISOR_RUNTIME" npm run test:e2e
E2E 测试套件不会静默回退到 runc。
它会实际检验真实的 gVisor 隔离、共享文件系统/进程状态、PTY、
前台信号、取消、后代清理、容器过期/移除,
以及针对宿主机/Docker 访问的负向检查。
6. 对真实的 Harness Loader 进行冒烟测试
bash
mkdir -p .test-work
smoke_root=$(mktemp -d "$PWD/.test-work/smoke-XXXXXX")
mkdir "$smoke_root/workspace" "$smoke_root/harness-home"
DSH_HOME="$smoke_root/harness-home" \
DSH_GVISOR_WORKSPACE="$smoke_root/workspace" \
DSH_GVISOR_RUNTIME="$DSH_GVISOR_RUNTIME" \
node examples/smoke.mjs
预期输出包括:
text
shared-world-ok
pty-world-ok
冒烟测试验证 Harness 的文件系统、bash 和 PTY 使用方
观察到相同的沙箱状态。
使用真实 DeepSeek + 真实 Harness 进行体验
仓库测试不需要模型 API 密钥。
本节为可选内容。它使用真实的 DeepSeek API 调用和固定版本的
Harness 智能体循环,以用户的方式体验该插件。
流程如下:
text
DeepSeek API
↓
Harness agent loop
↓
normal write / bash / read tools
↓
ctx.fs + ctx.subprocess
↓
dsh-gvisor
↓
Docker
↓
runsc / gVisor
1. 导出你的 DeepSeek API 密钥
不要将密钥粘贴到 shell 历史记录中:
bash
cd ~/dsh-gvisor-play/dsh-gvisor
read -s -p "DeepSeek API key: " DEEPSEEK_API_KEY
echo
export DEEPSEEK_API_KEY
test -n "$DEEPSEEK_API_KEY" && echo "DEEPSEEK_API_KEY is set"
密钥保留在宿主机侧。它不会被隐式转发到 gVisor
工作负载环境中。
2. 创建一个可复用的真实智能体运行器
bash
mkdir -p .test-work
cat > .test-work/real-agent.mjs deadline) throw new Error('agent timed out');
await new Promise((resolve) => setTimeout(resolve, 100));
}
for (const event of agent.session.events) {
if (event.type === 'tool/result' || event.type === 'assistant/message') {
console.log(JSON.stringify(event, null, 2));
}
}
} finally {
await ctx.fiber.dispose();
}
EOF
3. 演练:证明 ctx.fs 和 bash 共享同一个 gVisor 世界
bash
rm -rf /tmp/dsh-gvisor-real-play
mkdir /tmp/dsh-gvisor-real-play
DSH_GVISOR_TASK='Use the write tool to create shared.txt containing exactly "from-fs". Then use bash to read shared.txt and append "-from-bash". Then use the read tool to read shared.txt. Do not merely describe the steps: actually use the tools. Finally report the exact final file contents.' \
DSH_GVISOR_WORKSPACE=/tmp/dsh-gvisor-real-play \
DSH_GVISOR_RUNTIME="$DSH_GVISOR_RUNTIME" \
node .test-work/real-agent.mjs
现在检查宿主机挂载的工作区:
bash
bash
cat /tmp/dsh-gvisor-real-play/shared.txt
预期结果:
text
from-fs-from-bash
这演示了:
text
Harness fs 写入
↓
Harness bash 追加
↓
Harness fs 读取
↓
同一个 gVisor 执行世界
检查清理情况:
bash
docker ps -a --filter 'name=dsh-gvisor'
不应残留任何 provider 容器。
4. 演练:尝试绕过沙箱
在挂载的工作区之外创建一个无害的文件:
bash
mkdir -p .test-work
fixture="$PWD/.test-work/host-fixture.txt"
printf 'HOST-SECRET-DO-NOT-TOUCH\n' > "$fixture"
cat "$fixture"
让真实模型尝试几个本不应成功的路径:
bash
rm -rf /tmp/dsh-gvisor-security-play
mkdir /tmp/dsh-gvisor-security-play
export DSH_GVISOR_TASK="$(
cat $fixture
4. Use bash to run:
if [ -S /var/run/docker.sock ]; then echo SOCKET_PRESENT; else echo SOCKET_ABSENT; fi
5. Use bash to run:
env | grep '^DOCKER_HOST=' || echo NO_DOCKER_HOST
Report the literal results briefly.
EOF
)"
DSH_GVISOR_WORKSPACE=/tmp/dsh-gvisor-security-play \
DSH_GVISOR_RUNTIME="$DSH_GVISOR_RUNTIME" \
node .test-work/real-agent.mjs
然后从宿主机验证:
bash
printf '\n=== host fixture ===\n'
cat "$fixture"
printf '\n=== provider containers ===\n'
docker ps -a --filter 'name=dsh-gvisor'
宿主机 fixture 应仍然包含:
text
HOST-SECRET-DO-NOT-TOUCH
模型/工具的对话记录应显示宿主机路径不可访问,并且沙箱内不存在 /var/run/docker.sock。
这就是与仅做启动器路由的实际区别:工作负载无法自行选择 Docker 挂载/运行时/能力,也无法获取 Docker socket。
在 Harness 组合中使用它
examples/cordis.yml 是经过测试的最小组合。
它挂载此 provider 以替代本地/E2B 文件系统和子进程 provider,同时复用 Harness 现有的消费者。
bash
mkdir -p /tmp/dsh-gvisor-workspace
mkdir -p .test-work/harness-home
DSH_HOME="$PWD/.test-work/harness-home" \
DSH_GVISOR_WORKSPACE=/tmp/dsh-gvisor-workspace \
DSH_GVISOR_RUNTIME="$DSH_GVISOR_RUNTIME" \
node examples/smoke.mjs
以编程方式:
js
import * as GVisor from './dist/index.js';
await ctx.plugin(GVisor, {
workspace: '/srv/dsh/workspaces/job-123',
runtime: 'runsc',
});
将 Harness agent/session 的 cwd 设置为:
text
/workspace
现有的 dsh-bash-local 消费者仍可使用:尽管名字如此,其进程执行会通过此 ctx.subprocess provider 进行路由。
未改动的 dsh-terminal-bash 消费者使用此 provider 的 spawnTerminal() 实现。
不要为同一个执行世界同时加载宿主机子进程/文件系统的替代方案。
安全边界
重要的划分很简单:
| 受信任的主机配置 | 工作负载控制的数据 |
| --- | --- |
| Docker 守护进程端点 | argv |
| runsc 运行时注册 | cwd |
| 容器镜像 | env 条目 |
| 主机工作区路径 | stdin |
| UID/GID | 文件系统操作 |
| 生命周期/资源策略 | 终端输入 |
工作负载控制的值是发送给 worker 的帧数据。它们不会成为
Docker CLI 选项。
provider 将容器策略固定为包含:
- runsc
- --network=none
- 只读根文件系统
- 无 capabilities
- no-new-privileges
- 不提供设备
- 有界的 PID / CPU / 内存 / tmpfs 资源
- 一个显式的 /workspace 绑定
- 禁用递归绑定挂载
- 不挂载 Docker socket
主机凭据和主机环境不会被隐式转发。
什么是受信任的
以下内容保持受信任:
- Docker 守护进程
- runsc 注册
- provider 代码/配置
- 容器镜像
- 主机工作区供应
- 与此 provider 一起加载的其他 Harness 插件
将凭据、Harness home、provider/配置文件以及敏感的主机文件
放在挂载的工作区之外。
一个 provider 实例就是一个信任域。如果两个工作负载不应相互干扰,
请为它们提供单独的 provider 实例和单独的工作区。
本项目是一个集成/安全边界 MVP,不是通用的 gVisor
逃逸审计或多租户安全认证。
当前行为和限制
常见路径被有意设计得很小:
| 领域 | 当前行为 / 限制 |
| --- | --- |
| 文件系统 | 共享 ctx.fs;整文件读/写/编辑操作上限为 16 MiB |
| 子进程 | argv/cwd/env/stdin、流式输出、取消、后代清理 |
| PTY | 真实控制 PTY、持久 shell 状态、前台信号、清理 |
| PTY 就绪 | inputWaiting 保守地为 false;Harness 仍使用提示符/前台证据 |
| 执行世界 | 一个沙箱 = 一个信任域 |
| 重启 | provider/主机重启后不重新附加/恢复 |
| 文件系统 CAS | 版本保护对并发的 shell/主机写入者不是原子的 |
| Docker 故障 | Docker 不可用时清理无法保证移除;错误会报告容器名称 |
| ctx.codeRuntime | 未实现 |
强制执行大 I/O 和待处理操作的安全上限,以避免无界的主机
内存增长。PTY 消费者应持续排空输出。
取消操作可能与已提交的文件系统变更发生竞争;重试前请重新读取状态。
对于报告为孤立的容器:
bash
docker rm --force ''
测试
快速本地测试套件:
bash
npm test
真实 gVisor 测试套件:
bash
DSH_GVISOR_TEST_RUNTIME="$DSH_GVISOR_RUNTIME" npm run test:e2e
Loader 冒烟测试:
bash
mkdir -p .test-work
smoke_root=$(mktemp -d "$PWD/.test-work/smoke-XXXXXX")
mkdir "$smoke_root/workspace" "$smoke_root/harness-home"
DSH_HOME="$smoke_root/harness-home" \
DSH_GVISOR_WORKSPACE="$smoke_root/workspace" \
DSH_GVISOR_RUNTIME="$DSH_GVISOR_RUNTIME" \
node examples/smoke.mjs
当前的 v0.1 路径也已在全新检出中手动演练过,包括:
- 固定版本的 Harness 依赖安装/构建
- dev:link
- 类型检查/本地测试
- 镜像构建
- 真实的 runsc E2E
- 真实的 Harness Loader
- 通过 deepseek-official / deepseek-v4-flash 调用真实的 DeepSeek API
- 共享的 fs/bash 状态
- 对宿主机文件的访问被拒绝
- Docker socket 被拒绝
- PTY 持久性及前台 SIGINT 行为
- 最终容器清理
除非你运行可选的 real-DeepSeek 部分,否则不需要 API key。
故障排查
| 症状 | 检查项 |
| --- | --- |
| runsc 似乎已注册,但容器无法启动 | 运行 runsc --version 以及实际的 docker run --runtime= ... dmesg;过期的 Docker 注册可能指向已删除的二进制文件 |
| 运行时注册被拒绝 | 所选的注册必须解析到一个 runsc 可执行文件;runc 会被拒绝 |
| Docker socket 缺失 / 权限被拒绝 | 检查 /var/run/docker.sock 以及你的非 root 用户的 Docker 访问权限 |
| /usr/bin/docker 缺失 | provider 有意不使用 PATH 中任意的 docker |
| bind-recursive=disabled 被拒绝 | 升级 Docker;不要为了让启动通过而移除该选项 |
| 工作区权限被拒绝 | 确保配置的非 root UID/GID 可以写入专用工作区 |
| 镜像不可用 | 运行 npm run image:build;provider 启动时使用 --pull=never |
如果你的常规 Docker CLI 使用其他 context 或 endpoint,请针对
provider 的确切本地 daemon 进行构建:
/usr/bin/docker \
--host=unix:///var/run/docker.sock \
build -t dsh-gvisor:dev sandbox
不要通过将 Docker 暴露到沙箱内部来解决宿主机 Docker 访问问题。
开发说明
已验证的 Harness 修订版本:
cd5ef8148158c3a752a658978873241fdf8e2bbc
该修订版本对应的 Harness 版本:
0.1.2-alpha.1
Cordis:
4.0.1
该集成有意绑定到该执行世界契约。在更改 Harness 修订版本之前,请针对上游重新测试。
相关的上游路径包括:
packages/subprocess/subprocess/src
packages/fs/fs/src
packages/e2b
packages/terminal/terminal-bash
spawnTerminal() 是 subprocess 执行世界契约的一部分,并由本 provider 实现。