Skip to content

dsh-sandboxie-redirect

Verified

@lone-wolf-akela/dsh-sandboxie-redirect · v0.3.4 · MIT · Web UI

DSH bundle adding a copy-on-write permission preset: shell commands run inside a per-workspace Sandboxie box, so writes outside the workspace land in the box's copy while the real disk is untouched.

Install

dsh plugin add @lone-wolf-akela/dsh-sandboxie-redirect

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Tags

Creators

Readme

dsh-sandboxie-redirect

npm version CI license: MIT platform: Windows 10/11

English: README.md

给 DSH 增加第四种权限预设 「写时复制」 的 bundle:shell 命令跑在本工作区专属的 Sandboxie 沙盒里,工作区内的写入照常落到真实磁盘;工作区外的写入、修改、删除不会失败,但只落进该沙盒的副本。原有三个预设(只读 / 仅工作区 / 完全权限)行为不变。

┌─ 你的 DSH 会话 ───────────────────┐
│  文件策略:写时复制                │
│                                   │
│  shell 命令 ──▶ Sandboxie 沙盒 ───┼──▶ 工作区内写入   → 真实磁盘
│  (在沙盒内)   (每工作区一个)    ┼──▶ 其它位置写入   → 沙盒副本
│                                   │    其它位置删除   → 副本里只留删除标记
│  读/写/编辑 ──▶ 宿主进程(盒外)    ┼──▶ 规则不变:工作区内可写,区外拒绝
└───────────────────────────────────┘
  • 仅 Windows,且需要先装 Sandboxie-Plus(其服务须在运行)。
  • 接入方式是权限预设,不修改 DSH 应用本体。
  • 用途是防误写、可撤销、保持系统目录干净。不用于防御恶意程序——Sandboxie 不提供该保证,而插件与承载它的应用拥有同等权限。

术语

词 含义
真实磁盘 系统里实际存放文件的地方(例如 C:\Users\…)。
沙盒 / 盒 Sandboxie 创建的隔离环境;本插件为每个工作区创建一个。
副本 沙盒对"工作区外文件改动"的私有存储(位于沙盒根下),与真实文件分开。
盒内 / 盒外 写时复制下,shell 命令在盒内运行;DSH 应用本体与它的文件工具(读/写/编辑)在盒外。
合并视图 盒内命令读文件时,沙盒把副本内容叠加到真实文件上呈现。
SandMan Sandboxie-Plus 自带的图形管理界面,可查看、恢复、删除沙盒。

安装

前置条件:Sandboxie-Plus(源码)。安装后它的服务须在运行;本插件的所有沙盒都由 Sandboxie 创建与管理。

装在哪儿都行,不需要配置。 插件不假设 Sandboxie 在某个固定目录:它先读 Sandboxie 自己的注册表项(SbieSvc 服务的 ImagePath 最权威——能建沙盒的安装必然有它,其次是驱动服务与卸载项),再看 %ProgramFiles%\Sandboxie-Plus 等常规位置与 PATH,最后才按名字扫一遍常见父目录与各固定磁盘根目录,找含 SbieDll.dll 的文件夹。装在别的盘、用户目录、便携目录都可以。只有全部落空时才会报 "not installed",此时用 DSH_SBIE_DIR 直接指定(见环境变量)。

DSH 自己的安装目录同样不假定。 启动器要用的 koffi.node 是随 DSH 一起装在它 resources\app.asar.unpacked 里的,而启动器是普通 Node 进程(没有 process.resourcesPath)。插件会自己定位 DSH:先看运行启动器的那个 node(桌面应用自带的运行时就在安装目录里,这条路径本身就指回安装位置),再看安装器留下的卸载项,最后才是常规目录与 PATH。DSH 装在别的盘也能正常工作。

本包是 DSH 的 bundle(自带配置层),装进去就自动挂载,不需要手改 profile 文件。

# 装进某个 profile(不存在会创建),并自动加入该 profile 的 bundle 列表
dsh plugin --profile <profile> add @lone-wolf-akela/dsh-sandboxie-redirect

# 先不启动,核对配置层,再启动
dsh --profile <profile> --dump-config      # 应看到一行 "# == @lone-wolf-akela/dsh-sandboxie-redirect"
dsh --profile <profile>

也支持本地目录 / 离线 tarball:

dsh plugin --profile <profile> add C:\path\to\dsh-sandboxie-redirect   # 本地 checkout(link 方式)
dsh plugin --profile <profile> add .\lone-wolf-akela-dsh-sandboxie-redirect-0.3.1.tgz

哪个 profile 用哪条路? 正在运行的桌面应用独占的 profile(desktop)会被 CLI 拒绝操作(profile "desktop" is managed exclusively by the Electron application)。这种 profile 请在应用内装:设置 → 插件 → 添加 bundle,填上面的包名。其它 profile 用 CLI 即可。

装完重启客户端,在权限下拉里选择 ❐ Copy-on-write 写时复制。沙盒名称会在第一条 shell 命令之后出现在标题栏。

从"手工挂载"迁移

早期版本是"把目录拷到 ~/.dsh/plugins/dsh-sandboxie-redirect + 在 ~/.dsh/profiles/<profile>/cordis.patch.yml 里加行"。切到 bundle 通道前必须先删掉那些行:同一个 dsh.client 包有两个活动 loader 行会让启动直接失败("resolves from multiple active Loader sources")。要删的是:name 为绝对路径、以 lib\provider.mjs 结尾的那一行,以及本插件加的 sandbox、permission 两行。仓库里的 tools/install.mjs 仍然保留给手工通道使用,且必须在沙盒外运行。

功能

写时复制预设

位置 行为
工作区内的写入、修改、删除 直接作用于真实磁盘
工作区外的写入、修改 命令报成功,但改动只落在该工作区的副本里;真实磁盘不受影响
工作区外的删除 真实文件保留;副本中只记录删除标记

DSH 的文件工具(读/写/编辑)在盒外运行,仍按「仅工作区」判定:工作区内可写、区外拒绝。想读"沙盒视角"的文件,用 shell 命令读(见下文「读侧分歧」)。

该预设下,会话的策略文本会追加一段说明,告知模型本模式的行为与注意事项,不必让模型自己推断。

标题栏的沙箱名称

写时复制模式下,标题栏显示当前沙盒名称(如 dsh_able_willow,悬停可见副本根路径)。它只在两个条件同时满足时出现:该会话的预设是写时复制,且该工作区确已创建沙盒。因此第一条命令后才出现,切换预设或清理沙盒后消失。

权限下拉图标

「写时复制」在下拉与底部按钮中带有图标(复制双矩形),随主题配色。预设名以 ❐ 开头也是同一个原因:出厂下拉的图标来自一张封闭的 id→图标表,自定义预设没有图标,而名字是唯一一定渲染的表面。

sandbox_clear 工具

会话内可用 sandbox_clear 查看或清除本工作区的副本:mode: "inspect" 仅查看(文件数、占用),mode: "clear" 删除副本与配置。任何权限模式下都可用,且只能操作 Sandboxie 认定属于本工作区的沙盒。另有诊断用的 mode: "status":它报告本会话投影登记的状态,用来分辨"投影没被驱动"和"客户端没收到"——标题栏的沙箱名称不显示时先看它(0.3.3 起才真正可用)。

用户注意事项

  • sandbox_permissions 的参数描述不是为本预设写的。 那段文字由 DSH 统一生成、所有预设共用,读起来像"被拒之后的补救"——而写时复制下区外写入不会被拒(它会成功落进副本),所以既不会出现拒绝标记,也没有"被拒的命令"可重试。会话的策略文本会明确说明这一点:升权是"这一次调用直接作用于真实磁盘"的主动手段,不是失败的后续动作。
  • 读侧分歧(重要):同一个路径,不同工具看到的内容可能不同。
    • shell 命令在盒内运行,读到的是合并视图:如果之前有命令在工作区外写过该文件,命令看到的是副本里的版本。
    • DSH 的文件工具在盒外运行,读到的一直是真实磁盘上的版本。
    • 因此:验证"命令在工作区外写了什么"用 shell 命令读;验证"真实磁盘有没有被改动"用 DSH 的文件工具(或资源管理器)读。
  • 副本位置:普通路径在 <沙盒根>\drive\<盘符>\<路径>;用户目录下的路径在 <沙盒根>\user\current\<相对路径>。Sandboxie 自己配置的沙盒目录会被自动跟随(FileRootPath,盒级或 [GlobalSettings],含 %USER%/%SANDBOX% 展开);需要时可用 DSH_SBIE_ROOT 覆盖(见环境变量)。
  • 磁盘占用:副本不自动回收,会持续累积。
  • C:\Windows\Temp:修改其中已存在的文件可能被拒(Sandboxie 原生行为,非本插件所致);新建与删除不受影响。
  • 并发:同一工作区的并发命令共用一个沙盒,互相可见。
  • 升权:写时复制下,若某命令需要更大权限而发起升权,该次调用会整体在盒外运行;下一条命令回到盒内。升权不是"把某个文件变真"的手段。
  • 写回:副本改动默认不回灌真实磁盘。需要恢复时在 SandMan 中查看并恢复;sandbox_clear 只做删除,不做写回。
  • 卸载 bundle 只会移除预设与配置行,沙盒与副本仍留在磁盘上。想收回空间就先清理(sandbox_clear,或 --manage clean)。

手动管理沙盒

node bin\dsh-sbie-run.mjs --manage list                    # 列出受管沙盒
node bin\dsh-sbie-run.mjs --manage clean "<工作区>"         # 清理某工作区的沙盒
node bin\dsh-sbie-run.mjs --manage delete-box <沙盒名>      # 删除指定沙盒

--manage 必须在盒外运行(普通终端,或 danger-full-access 会话):盒内进程看不到沙盒列表。同样的操作也可以在 SandMan 里做。

环境变量

全部可选,都是"逃生阀"而非配置面。

变量 作用
DSH_SBIE_DIR Sandboxie 安装目录(含 SbieDll.dll 的那个文件夹)。通常不需要:上面的自动查找会先从注册表、常规位置与 PATH 里找。装在非常规目录且自动查找没命中时用它。
DSH_SBIE_NODE 跑启动器的 node.exe。插件会自动去找(桌面应用自带的运行时,其次 $DSH_HOME/dsh-runtimes),找不到时用它指定。
DSH_SBIE_ROOT 覆盖沙盒根。通常不需要:Sandboxie 配置的 FileRootPath 会被自动跟随。默认 %SystemDrive%\Sandbox\%USERNAME%。
DSH_SBIE_LOG_DIR 诊断日志目录。默认 $DSH_HOME/state/dsh-sandboxie-redirect。
DSH_SBIE_INI 要读取的 Sandboxie 配置文件。默认 %SystemDrive%\Windows\Sandboxie.ini。
DSH_SBIE_KOFFI / DSH_SBIE_KOFFI_ROOT 启动器要用的 koffi.node(或含它的目录)。通常不需要:DSH 的安装位置会被自动定位(见安装)。
DSH_SBIE_BOX / DSH_SANDBOX_ROOT 由插件在命令内注入;"我在哪个盒里"以它们为准,永远不要用工作区路径去推导盒名。

诊断文件:上述日志目录下的 provider.log、host.log、tool.log。host.log 上限 512 KB,只记状态迁移。

实现要点(简述)

  • bundle 层禁用原 sandbox 行(@deepseek-ai/dsh-sandbox-local)并插入本包的 provider,它继承原 provider:只把「写时复制」这一预设分流,其余模式一律委托原 ACL 路径。用 runnerCommand 做不到这件事——那会作用于所有模式。
  • 同一层把 copy-on-write 合并进 permission 的预设目录,保留之前各层贡献的条目。
  • shell 命令经 bin/dsh-sbie-run.mjs——一个持有 Sandboxie FFI 的纯 Node 子进程。Sandboxie 由服务创建进程并丢弃标准句柄,因此 stdio 走回环 TCP + 长度前缀帧回传。
  • 盒名由工作区路径确定性派生成词对(dsh_<形容词>_<名词>),不需要状态文件;冲突时按候选序列顺延,且只有当 Sandboxie 配置表明该工作区确实拥有某盒时才采用它。
  • 只有"加载 harness 包失败"是致命错误,此时注册的 provider 会失败关闭:拒绝执行命令,而不是不加限制地执行。

开发

环境准备与开发回路见 CONTRIBUTING.md,架构与踩过的坑见 AGENTS.md。常用命令:

npm test                         # 单元 + 标题栏投影 + bundle 层校验(不需要 DSH、不需要 Sandboxie)
npm run test:acceptance          # 验收:真沙盒、真重定向(须在盒外、Medium IL)
npm run pack:check               # 看发布的 tarball 里会有什么

安全问题见 SECURITY.md。

许可

MIT —— 见 LICENSE。