Back to home

Sutera-Diffusus

dsh-sandbox-tester

DSH sandbox tester: process-isolated testing ground for DeepSeek Harness

Stars
1
Language
JavaScript
Created
Aug 16, 2026
Updated
Aug 16, 2026

Introduction

dsh-sandbox-tester

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

开发者正在面对什么

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

于是,有了沙盒测试器

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

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

License Version DSH


目录


特性

🧪 进程级隔离沙盒

  • sandbox_create 从本体程序目录复制出独立沙盒(默认裁剪,fullCopy: true 全量);
  • 沙盒 = 独立程序副本 + 全新 DSH_HOME + 自动分配独立端口(3182 起,冲突自动 +1);
  • 沙盒由 node bin.js web --port <p> 直接拉起,崩溃只死沙盒进程;
  • 实证:沙盒内注入坏补丁/强杀沙盒进程,本体 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)                                    │
│                ports    — 端口池(探测分配,冲突自动递增,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 只出报告,真实写入需显式开关且失败自动回滚

生命周期状态机

creating ──▶ stopped ⇄ running ──▶ destroyed
                │                     ▲
                └──(48h 未运行或进程已死)──▶ prune 回收

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


安装要求

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

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

安装教程

第 1 步:获取插件

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

方式 B:克隆仓库

git clone https://github.com/Sutera-Diffusus/dsh-sandbox-tester.git
cd dsh-sandbox-tester

第 2 步:确认 DSH 安装目录

DSH 安装目录通常包含 DeepSeekHarness-Launcher.exenode_modules。可通过启动器配置确认:

Get-Content "D:\Deepseek harness\DeepSeekHarness-Launcher.cfg"

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

第 3 步:执行安装脚本

node install.mjs --target "<DSH_INSTALL_DIR>"

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

  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 个工具已注册。

卸载

node install.mjs --target "<DSH_INSTALL_DIR>" --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 <port>

开发建议:在独立 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