🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

沙盒测试器 Sutera-Diffusus/dsh-sandbox-tester

DeepSeek Harnessv0.0.1
Sutera-Diffusus78 天前有提交已提供中文文档扫描:含敏感能力

在隔离进程里试跑插件改动,崩了也不伤本体

29.6/100
综合分
4
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:npm 同名包「dsh-sandbox」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Sutera-Diffusus/dsh-sandbox-tester
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · security
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 78 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

npm 同名包「dsh-sandbox」归属 dushaobindoudou/dsh-plugin,装到的可能不是本插件

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-sandbox @ 0.0.1
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/9/22 02:04:44

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 70 处,展示前 51 条)
  • 读取本地文件
    lib/registry.js:47
    text = await readFile(REGISTRY_PATH, 'utf8')
  • 写入本地文件
    lib/registry.js:77
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    lib/registry.js:79
    await writeFile(tmp, JSON.stringify(doc, null, 2) + '\n', 'utf8')
  • 写入本地文件
    lib/registry.js:80
    await rename(tmp, REGISTRY_PATH)
  • 执行外部命令固定命令
    lib/proctree.js:140
    const child = spawn('node', [bin, 'web', '--port', String(meta.port)], {
  • 读取本地文件
    install.mjs:60
    const text = readFileSync(join(target, 'DeepSeekHarness-Launcher.cfg'), 'utf8')
  • 删除本地文件
    install.mjs:90
    unlinkSync(link)
  • 读取本地文件
    install.mjs:91
    } else if (existsSync(link)) {
  • 写入本地文件
    install.mjs:94
    mkdirSync(dirname(link), { recursive: true })
  • 删除本地文件
    install.mjs:104
    unlinkSync(link)
  • 读取本地文件
    install.mjs:113
    if (!existsSync(manifestPath)) {
  • 读取本地文件
    install.mjs:116
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
  • 写入本地文件
    install.mjs:130
    writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n')
  • 读取本地文件
    install.mjs:146
    if (!existsSync(APIPROXY)) {
  • 读取本地文件
    install.mjs:149
    const text = readFileSync(APIPROXY, 'utf8')
  • 写入本地文件
    install.mjs:158
    copyFileSync(APIPROXY, APIPROXY_BAK)
  • 写入本地文件
    install.mjs:162
    writeFileSync(APIPROXY, next, 'utf8')
  • 写入本地文件
    install.mjs:169
    copyFileSync(APIPROXY_BAK, APIPROXY)
  • 读取本地文件
    lib/merge-gate.js:105
    if (!existsSync(bodyAbs)) {
  • 读取本地文件
    lib/merge-gate.js:143
    const text = readFileSync(file, 'utf8')
  • 执行外部命令来自配置/变量
    lib/merge-gate.js:154
    const child = spawn(process.execPath, ['--check', file], {
  • 读取本地文件
    lib/merge-gate.js:188
    isNew: !existsSync(t.bodyAbs),
  • 读取本地文件
    lib/merge-gate.js:277
    if (!existsSync(t.srcAbs)) {
  • 写入本地文件
    lib/merge-gate.js:323
    await mkdir(plan.backupDir, { recursive: true })
  • 写入本地文件
    lib/merge-gate.js:327
    await mkdir(dirname(f.backup), { recursive: true })
  • 写入本地文件
    lib/merge-gate.js:328
    await copyFile(f.body, f.backup)
  • 写入本地文件
    lib/merge-gate.js:335
    await mkdir(dirname(f.body), { recursive: true })
  • 写入本地文件
    lib/merge-gate.js:336
    await copyFile(f.srcAbs, f.body)
  • 写入本地文件
    lib/merge-gate.js:341
    try { await copyFile(f.backup, f.body) } catch { }
  • 删除本地文件
    lib/merge-gate.js:344
    try { await rm(p, { force: true }) } catch { }
  • 读取本地文件
    lib/tools-lifecycle.js:92
    const pkg = JSON.parse(readFileSync(join(BODY_PROGRAM_SRC, 'node_modules', '@deepseek-ai', 'dsh', 'package.json'), 'utf8'))
  • 执行外部命令固定命令
    lib/tools-lifecycle.js:106
    execFile('robocopy', args, { windowsHide: true, maxBuffer: 16 * 1024 * 1024 }, (error, stdout, stderr) => {
  • 写入本地文件
    lib/tools-lifecycle.js:125
    await mkdir(dst, { recursive: true })
  • 读取本地文件
    lib/tools-lifecycle.js:128
    entries = await readdir(src, { withFileTypes: true })
  • 写入本地文件
    lib/tools-lifecycle.js:148
    await copyFile(s, d)
  • 读取本地文件
    lib/tools-lifecycle.js:295
    if (existsSync(sandboxDir(name))) {
  • 读取本地文件
    lib/tools-lifecycle.js:298
    if (!existsSync(BODY_PROGRAM_SRC)) {
  • 写入本地文件
    lib/tools-lifecycle.js:306
    await mkdir(programDir(name), { recursive: true })
  • 写入本地文件
    lib/tools-lifecycle.js:307
    await mkdir(sandboxHome(name), { recursive: true })
  • 读取本地文件
    lib/tools-lifecycle.js:316
    if (existsSync(srcPkg)) {
  • 写入本地文件
    lib/tools-lifecycle.js:318
    await copyFile(srcPkg, join(programDir(name), 'package.json'))
  • 读取本地文件
    lib/tools-lifecycle.js:327
    if (!existsSync(binJs)) {
  • 写入本地文件
    lib/tools-lifecycle.js:337
    await writeFile(join(sandboxDir(name), 'meta.json'), JSON.stringify(meta, null, 2) + '\n')
  • 删除本地文件递归
    lib/tools-lifecycle.js:379
    await rm(sandboxDir(name), { recursive: true, force: true })
  • 删除本地文件
    lib/tools-lifecycle.js:457
    await rm(abs, { force: true })
  • 删除本地文件递归
    lib/tools-lifecycle.js:520
    await rm(sandboxDir(name), { recursive: true, force: true })
  • 删除本地文件递归
    lib/tools-lifecycle.js:574
    await rm(sandboxDir(candidate.name), { recursive: true, force: true })
  • 发起网络请求
    lib/tools-runhealth.js:51
    const res = await fetch(url, { signal: ctrl.signal })
  • 读取本地文件
    lib/tools-runhealth.js:136
    if (p && existsSync(p)) return p
  • 读取本地文件
    lib/tools-runhealth.js:144
    const text = await readFile(path, 'utf8')
  • 执行外部命令来自配置/变量
    lib/tools-runhealth.js:179
    const child = spawn(process.execPath, [script, String(meta.port), String(meta.name || '')], {
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 进程隔离测试场

DSH 沙箱测试器:为 DeepSeek Harness 提供进程隔离的测试场

README

由 DeepSeek 最新模型翻译生成
dsh-sandbox-tester DSH 沙盒测试器——为 DeepSeek Harness 打造的进程级隔离测试场。 开发者正在面对什么 在 DSH 上开发插件、打补丁、做测试时,你面对的是这样一个现实:所有插件都运行在同一个宿主进程里。改坏一行代码,死循环会卡死整个主进程,未捕获异常会崩掉整个应用;测试脚本一个手滑,误杀进程、误删数据,连聊天记录都可能一起陪葬。然后就是那个熟悉的循环:页面打不开 → 重启 Launcher → 切换间隙报连接失败和 400 → 再重启……改坏一次代码,一晚上就没了。 于是,有了沙盒测试器 把每一次开发/测试改动,先关进一个完全隔离的沙盒实例(独立进程 + 独立数据 + 独立端口)里跑:沙盒里随便崩、随便死循环、随便误操作,最坏的结果也只是沙盒进程自己倒下,本体 3080 全程无恙。改动想回到本体,还必须通过机器强制的合回门禁(目标白名单 + 逐文件语法校验 + bundle 校验 + 备份/回滚清单),带着坏状态偷渡?门都没有。 沙盒里随便作,本体永不翻车。
展开完整文档(README 剩余 1 节)
dsh-sandbox-tester

DSH 沙盒测试器——为 DeepSeek Harness 打造的进程级隔离测试场。

开发者正在面对什么

在 DSH 上开发插件、打补丁、做测试时,你面对的是这样一个现实:所有插件都运行在同一个宿主进程里。改坏一行代码,死循环会卡死整个主进程,未捕获异常会崩掉整个应用;测试脚本一个手滑,误杀进程、误删数据,连聊天记录都可能一起陪葬。然后就是那个熟悉的循环:页面打不开 → 重启 Launcher → 切换间隙报连接失败和 400 → 再重启……改坏一次代码,一晚上就没了。

于是,有了沙盒测试器

把每一次开发/测试改动,先关进一个完全隔离的沙盒实例(独立进程 + 独立数据 + 独立端口)里跑:沙盒里随便崩、随便死循环、随便误操作,最坏的结果也只是沙盒进程自己倒下,本体 3080 全程无恙。改动想回到本体,还必须通过机器强制的合回门禁(目标白名单 + 逐文件语法校验 + bundle 校验 + 备份/回滚清单),带着坏状态偷渡?门都没有。

沙盒里随便作,本体永不翻车。

License
Version
DSH

目录

- 特性
- 架构
- 安装要求
- 安装教程
- 使用说明
- 合回门禁
- 数据与隐私
- 项目结构
- 开发与测试
- 故障排查
- License

特性

🧪 进程级隔离沙盒

- sandbox_create 从本体程序目录复制出独立沙盒(默认裁剪,fullCopy: true 全量);
- 沙盒 = 独立程序副本 + 全新 DSH_HOME + 自动分配独立端口(3182 起,冲突自动 +1);
- 沙盒由 node bin.js web --port 直接拉起,崩溃只死沙盒进程;
- 实证:沙盒内注入坏补丁/强杀沙盒进程,本体 3080 全程 HTTP 200。

🛠️ 9 个原生工具

| 工具 | 用途 |
| sandbox_list | 列出全部沙盒(状态/端口/年龄/最近报告) |
| sandbox_create | 创建沙盒(裁剪或全量复制、指定端口) |
| sandbox_inject | 把待测插件/补丁打进沙盒(自动备份 + 回滚清单,路径越界即拒绝) |
| sandbox_run | 预检本体 → 拉起沙盒 → 轮询健康 → 可选一键 QA |
| sandbox_health | 端口 + HTTP + 关键 bundle 检查,产出报告 |
| sandbox_stop | 停止沙盒(进程树校验:永不会误伤 3080) |
| sandbox_destroy | 销毁沙盒(需 confirm: true,目录与注册表全清) |
| sandbox_merge | 门禁式合回(见下文) |
| sandbox_prune | 清理孤儿/超龄沙盒(默认 48h 标记,dryRun 预览) |

🚧 合回门禁(机器强制,不可绕过)

目标白名单(11 个补丁面文件 + 显式新增)→ 逐文件 node --check → bundle 校验 → 备份计划 + 回滚清单 → 默认 dryRun 只校验出报告;真实写入需 DSH_SANDBOX_MERGE_ALLOW=1 且失败即自动回滚。

🌐 一键 QA(真实浏览器)

sandbox_run qa: true 接跑 CDP 9223 驱动的 headless Edge:首页 200、/plugins/dsh-sandbox/client.js 200、设置页真实渲染「测试沙盒」区段、控制台无未捕获异常,产出结构化报告。

⚙️ 设置页管理

DSH 设置 → 测试沙盒:沙盒卡片(状态徽标/报告徽标/端口/年龄/操作按钮)、新建表单、48h 超龄提示、一键清理、合回门禁摘要卡。

架构

设计原则:编排/执行平面分离

dsh-sandbox 遵循编排平面与执行平面分离(orchestration–execution separation)原则:编排平面驻留于本体进程(信任域 T0),只承担调度、校验与生命周期管理;一切不可信的插件与补丁都在执行平面——独立沙盒进程(不可信域 T1)——中运行。两个平面之间唯一的交互通道是受操作系统强制约束的进程边界,不存在任何共享内存或共享数据目录。

分层架构

┌─────────────────────────────── 编排平面(本体进程 · 信任域 T0)───────────────────────────────┐ │ L4 客户端层 client/client.js — 设置页「测试沙盒」区段(卡片管理 / 报告徽标 / 门禁摘要) │ │ │ │ L3 工具层 9 个原生工具:list · create · inject · run · health · stop · destroy · │ │ merge · prune │ │ · 统一参数 schema 校验;merge 为门禁式事务(见隔离不变量 I5) │ │ │ │ L2 服务层 registry — 沙盒注册表(原子写:tmp + rename) │text │ 端口池(探测分配,冲突自动递增,3182 起) │ │ proctree — 进程树管理(终止前反查 3080 归属,含本体即拒绝) │ │ │ │ L1 配置层 settings 命名空间 sandbox(SANDBOX_ROOT / PORT_START / AGE_HOURS) │ ├─────────────────────────────────────────────────────────────────────────────────────────────┤ │ ▲ 受控接口:spawn(强制注入独立 env)· taskkill(进程树校验)· HTTP 轮询 · report.json 回传 │ │ │ 信任边界 = 操作系统进程隔离(无共享内存,无共享数据目录) │ ├─────────────────────────────────────────────────────────────────────────────────────────────┤ │ 执行平面(沙盒进程 · 不可信域 T1) │ │ 独立程序副本 ─ 独立 DSH_HOME ─ 独立端口(3182+)─ 待测插件 / 补丁 │ │ 故障域 F 完全独立:死循环 / 未捕获异常 / 资源耗尽 / 误操作均被限制在 F 内 │ └─────────────────────────────────────────────────────────────────────────────────────────────┘

隔离不变量(架构正确性判据)

| # | 不变量 | 强制机制 |
| I1 | 进程隔离 | 沙盒由 spawn 独立拉起;沙盒崩溃/被强杀,本体进程不受任何影响 |
| I2 | 数据隔离 | 启动时强制注入独立 DSH_HOME;沙盒对本体数据目录零引用 |
| I3 | 端口隔离 | 端口池自动分配(3182 起),与本体 3080、固定副本 3181 永不冲突 |
| I4 | 终止安全 | sandbox_stop 在 taskkill 前反查 3080 监听 PID,目标进程树包含本体即拒绝执行 |
| I5 | 写入门禁 | merge 执行目标白名单 + 逐文件语法判定 + bundle 校验;默认 dryRun 只出报告,真实写入需显式开关且失败自动回滚 |

生命周期状态机 text creating ──▶ stopped ⇄ running ──▶ destroyed │ ▲
└──(48h 未运行或进程已死)──▶ prune 回收

完整的门禁决策树、一键 QA 交互时序与事故对照见 FLOW.md。

安装要求

| 项目 | 要求 |
| 操作系统 | Windows 10 / 11 |
| Node.js | 18+(执行安装脚本需要) |
| DeepSeek Harness | 0.1.0-rc.6 或同系列版本 |
| 磁盘 | 每个沙盒默认裁剪复制约 270 MB(node_modules) |

安装脚本会修改 DSH 安装目录中两处文件(profile manifest、apiproxy 白名单,均先备份),建议安装前关闭 DSH 页面。

安装教程

第 1 步:获取插件

方式 A:下载 Release(推荐):打开 Releases,下载最新版 zip 并解压。

方式 B:克隆仓库 powershell
git clone https://github.com/Sutera-Diffusus/dsh-sandbox-tester.git
cd dsh-sandbox-tester

第 2 步:确认 DSH 安装目录

DSH 安装目录通常包含 DeepSeekHarness-Launcher.exe 和 node_modules。可通过启动器配置确认: powershell Get-Content "D:\Deepseek harness\DeepSeekHarness-Launcher.cfg"

其中 workDir 字段指向安装目录,下文以 代替(本文示例路径 D:\Deepseek harness 为作者环境,请按实际替换)。脚本会从目标目录的 DeepSeekHarness-Launcher.cfg 自动解析其 DSH_HOME。

第 3 步:执行安装脚本 powershell
node install.mjs --target ""

幂等四步接线(重复执行安全):

1. bundle 行合入 profile manifest(dsh-sandbox + file: 依赖);
2. node_modules junction(profile 链接 + 内置包扁平回退);
3. apiproxy 设置白名单加 sandbox(先备份 .dsh-sandbox-bak);
4. 客户端插件挂载校验(/plugins/dsh-sandbox/client.js 可达)。

第 4 步:重启 DSH 并验证

1. 重启 DSH(服务与页面);
2. 打开设置页 → 应出现「测试沙盒」区段;
3. 新建会话,让 Agent 调用 sandbox_list → 9 个工具已注册。

卸载 powershell
node install.mjs --target "" --uninstall

使用说明在会话中使用工具

直接对 Agent 说,例如:

- 「用测试沙盒验证这个补丁:先 sandbox_create,再 sandbox_inject 打进去,sandbox_run 起来,健康检查过了再 sandbox_merge」
- 「sandbox_list 看看现在有哪些沙盒,把超龄的清掉」

设置面板

路径:DSH 设置 → 测试沙盒。

| 分组 | 内容 |
| 沙盒卡片 | 名称 / 状态(运行中·已停止·已销毁)/ 最近报告(通过·失败 + 摘录)/ 端口 / 年龄 / 启动·停止·健康检查·销毁 |
| 新建沙盒 | 名称 + 可选端口 + 完整复制开关 |
| 维护 | 48h 超龄标记、一键清理孤儿沙盒、合回门禁摘要 |

合回门禁

sandbox_merge(name, targets, dryRun=true)
├─ ① 目标白名单(11 补丁面 + 显式新增,越界即拒) ├─ ② 逐文件 node --check ├─ ③ bundle 校验 ├─ ④ 备份计划 + 回滚清单(不执行) └─ ⑤ dryRun=true → 只出报告;dryRun=false 需 DSH_SANDBOX_MERGE_ALLOW=1,失败即回滚

合回成功后自动同步 D:\DeepseekHarness_Backup(DSH 启动守卫 bin-guard 的回滚源)。

数据与隐私

- 沙盒注册表写入 D:\ai-temp\dsh-sandbox-registry.json,沙盒实体在 D:\DeepseekHarness_Sandboxes\(可在设置中改);
- 不读取、不上传任何用户凭据或会话数据;
- 除复制本体程序目录(只读)外,插件不对本体做任何写入;
- 无遥测、无外部网络请求(一键 QA 仅连本机 127.0.0.1)。

项目结构

dsh-sandbox/
├─ lib/
│ ├─ index.js # 宿主插件主入口(服务组装 + 9 工具注册 + settings 命名空间) │ ├─ registry.js # 沙盒注册表(原子写)与共享常量 │ ├─ ports.js # 端口池(探测 + 自动分配) │ ├─ proctree.js # 进程树管理(3080 保护 + 拉起/停止/存活判定) │ ├─ tools-lifecycle.js # list/create/inject/stop/destroy/prune │ ├─ tools-runhealth.js # run/health │ └─ merge-gate.js # 合回门禁 ├─ client/ │ └─ client.js # 设置页「测试沙盒」区段 ├─ test/ │ ├─ smoke.mjs # 单元冒烟(24 项) │ ├─ e2e.mjs # 端到端对抗(创建→启动→杀进程→坏补丁→销毁,13 项) │ └─ qa-cdp.mjs # 一键 QA(CDP 9223 真实浏览器,4 项) ├─ skills/dsh-sandbox/ # Agent 技能(SKILL.md) ├─ cordis.patch.yml # bundle 接入(loader entry: test-sandbox) ├─ install.mjs # 安装/卸载(幂等) ├─ DESIGN.md # 设计规格(含评审结论) ├─ FLOW.md # 工作流程图(Mermaid) ├─ LICENSE / README.md / CHANGELOG.md / SECURITY.md / CONTRIBUTING.md

开发与测试

单元冒烟(24 项,不启动任何进程)
node test/smoke.mjs

端到端对抗(真实复制 270MB 创建沙盒;需本体 3080 在运行以做无损对照)
node test/e2e.mjs

一键 QA(需 headless Edge CDP 9223 + 目标实例)
node test/qa-cdp.mjs

开发建议:在独立 DSH 测试副本上开发验证,避免污染主安装;本仓库开发期间遵循的隔离政策见 CONTRIBUTING。

故障排查

| 现象 | 处理 |
| 副本/本体启动报 duplicate loader entry id: sandbox | 你的组合里混入了旧版 cordis.patch.yml;确认使用 test-sandbox entry(本仓库已修复) |
| 设置页没有「测试沙盒」区段 | 安装后需重启 DSH;确认 apiproxy 白名单含 sandbox(install.mjs 会打印) |
| 沙盒启动失败 | 看沙盒 stderr;首启需完成引导,QA 脚本已自动处理(预置 workspace) |
| 销毁沙盒报错 | confirm 必须为 true;运行中的沙盒先 sandbox_stop |

License

MIT
预览分享卡片长什么样 ↓Sutera-Diffusus/dsh-sandbox-tester
分享 · DeepSeek Harness Hub
Sutera-Diffusus/dsh-sandbox-tester

在隔离进程里试跑插件改动,崩了也不伤本体

回到顶部