全部插件

DSH / BUNDLE / CLIENT-UI

dsh-write-protect

v0.3.0azazo1 / dsh-write-protecta0cf9fabe0

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

dsh-write-protect

源码级技术说明DSH sandbox extension: keep declared workspace subpaths (e.g. .git) read-only, honor a read-only rules file at the workspace root, grant extra writable roots under workspace-write, and let the model request session-scoped write access; enforced for sandboxed CLI commands and the write/edit tools. 为 DSH 沙箱增加工作区子路径只读保护 (例如 .git), 支持工作区根下的只读规则文件, 可在 workspace-write 下声明额外可写根, 并允许模型申请本会话的可写授权; 命令沙箱与 write/edit 工具都生效.展开完整技术说明收起技术说明
DSH sandbox extension: keep declared workspace subpaths (e.g. .git) read-only, honor a read-only rules file at the workspace root, grant extra writable roots under workspace-write, and let the model request session-scoped write access; enforced for sandboxed CLI commands and the write/edit tools. 为 DSH 沙箱增加工作区子路径只读保护 (例如 .git), 支持工作区根下的只读规则文件, 可在 workspace-write 下声明额外可写根, 并允许模型申请本会话的可写授权; 命令沙箱与 write/edit 工具都生效.

README / ZH

插件文档

目录摘要

DSH sandbox extension: keep declared workspace subpaths (e.g. .git) read-only, honor a read-only rules file at the workspace root, grant extra writable roots under workspace-write, and let the model request session-scoped write access; enforced for sandboxed CLI commands and the write/edit tools. 为 DSH 沙箱增加工作区子路径只读保护 (例如 .git), 支持工作区根下的只读规则文件, 可在 workspace-write 下声明额外可写根, 并允许模型申请本会话的可写授权; 命令沙箱与 write/edit 工具都生效.

dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。

在 GitHub 阅读完整 README

LIMITATIONS

已知限制

- **Windows 上 bash 挡不住, 也放不宽**: write / edit 能挡保护路径、能放行额外根; bash / pwsh 两者都不行. Windows 沙箱只能把整个工作区设成可写或不可写. 这条差别同时写进模型可见的系统提示词与 `request_writable_path` 的工具描述 (只在 Windows 宿主上追加), 免得模型把"命令跑通了"当成"模式没命中". - **broker 加固只在 macOS 生效; WSL 互操作加固只在 WSL + bwrap 生效**: 官方 macOS profile 的 `(allow default)` 让 `open` 能把命令交给 launchd 在沙箱外跑, 本插件追加的拒绝形式堵住这条路. WSL 上对应的代理通道是 PE 互操作, 由 `hardenWsl` 堵住. 两边都只收紧不放宽. Linux 的网络命名空间仍未隔离, 沙箱内仍可连宿主守护进程 (Docker socket, ssh-agent 一类) 让外面代劳, 这类问题本插件不处理. - **工作区或额外可写根是整块 Windows 盘时**: tmpfs `/mnt` 之后会把那条路径重新 bind 回去, PE 文件重新可见, 但仍没有 `/run/WSL` 套接字. 真正要在沙箱内用 Windows 程序, 请关掉 `hardenWsl`. - **`hardenWsl` 会连带藏掉 `/mnt/wsl`**: WSLg 与 Docker Desktop 的跨发行版挂载都在那里, 沙箱内会看不见. - **Linux 没有 bwrap, 落到 Landlock 时**: 没法单独保护子路径, 也没法藏 WSL 互操作入口, 命令按官方沙箱跑并告警一次; 额外可写根可以加 `--rw`. write / edit 两者都生效. - **完全放开沙箱时** (`danger-full-access`): 本插件整体不介入 —— bash 不进沙箱, write / edit 的保护路径与规则文件判定也跳过. 该模式是用户显式选择的"不设限", 保护只在 `read-only` 与 `workspace-write` 下生效. - **Linux bwrap 要求路径真实存在**: 通配扫出来的保护路径如果当时还不在磁盘上, 会跳过这条只读挂载并告警. 需要无条件保护的工作区根路径请用字面条目 (如 `/.git`); 字面条目即使还不存在, write / edit 也会拒绝. - **命令侧的枚举窗口 (macOS 字面条目除外)**: Linux bwrap / Landlock 与 macOS 上的通配条目只能按枚举出来的路径保护. 有 watcher 时, 变化之后的下一条命令就会吃到新清单; watcher 不可用时退回时间兜底 (最多 `watchTtlMaxMs`, 默认 30 秒). macOS 上的**字面条目**没有这个窗口 (按正则拒绝, 见上节), 因此 `git init` 也建不出 `.git`. 已经要保护的目录不会再往里扫, 里面的匹配项不再单独列出; 被 `!` 放行的目录还会继续找. 目录符号链接不跟随, 避免扫到工作区外. write / edit 不受这条限制: 它直接按模式判定. - **正则拒绝只覆盖字面条目, 且遇到 `!` 就整体放弃**: 含 `*` `?` `[` 或 `\` 的条目仍走枚举清单; 文本里只要出现 `!` 取反, 命令侧就退回纯枚举 (纯 deny 表达不了 last-match-wins). 目录标记条目在正则通道上不区分目标是文件还是目录, 同名文件也会被一并挡住, 属于收紧. - **尾部 `/**` 按那个目录本身保护**: 和保护其下全部后代等价, 同时避免枚举全部后代, 代价是该目录自己也写不了. - **规则文件的条目同样受缓存窗口影响**: 规则文件内容按 1 秒 TTL 重读, 改完最迟 1 秒后按新内容判定; 新增的匹配路径要等下一次枚举 (监听报变化后立即重算, 没有事件时最迟 `watchTtlMaxMs`, 默认 30 秒) 才会进命令沙箱的清单, write / edit 侧立刻按新条目判定. - **授权是会话级内存态**: `request_writable_path` 得到的授权, 以及会话面板里手动加的临时可写根, 都不跨会话, 也不写配置文件; 撤回只是删掉这条内存记录, 不产生任何持久状态. 需要长期生效的额外可写根请写插件页配置或 patch. - **撤回通知依赖该会话有活着的 agent**: 投递对象是会话的 agent runtime; 该会话当前没有活动 agent 时授权照常撤回, 但通知投不出去, 面板会把这件事如实写出来 (不假装模型已经知道). - **授权在 bwrap 上要求路径真实存在**: 命令侧要把授权子树 bind 回可写, bwrap 要求挂载源存在; 还不存在的授权路径在命令侧要等它被创建出来 (write / edit 与 Seatbelt 不受这条限制). - **Landlock 上没有命令侧的授权**: 纯 allow-list 无法表达"父目录只读, 其中一棵子树可写", 强行加 `--rw` 会连上方一起放开, 因此这种 runner 下授权只作用于 write / edit (告警一次). - **Landlock 上也没有命令侧的读拒绝**: 同一个 allow-list 结构在放行的父目录里挖不掉一棵子树, 因此读拒绝在这个 runner 上只作用于读工具, 命令仍读得到, 会告警一次. 它同时挡住读拒绝的授权那一路 (读本来就没被挡). - **Windows 上读拒绝只挡工具侧**: 官方 Windows 沙箱只能把整个工作区设成可写或不可写, 没有子路径的读拒绝形态 (与写保护的限制同源). - **读拒绝的枚举窗口与写保护相同**: bwrap 的 `tmpfs` 与 Seatbelt 的通配条目都按枚举出来的路径生效, 新出现的匹配路径要等下一次展开 (watcher 立即重算, 没有事件时最迟 `watchTtlMaxMs`). macOS 上的**字面条目**同样走正则通道, 没有这个窗口. - **读拒绝拦不住别的东西读**: 它只管本插件覆盖的那几条通道 (读工具与 `bash` / `pwsh` 沙箱). 别的插件或工具自己开文件读 (MCP 工具, 浏览器, 远端会话一类) 不在这条围栏里. - **读拒绝挡住的是内容, 也顺带挡住执行**: macOS 上 `(deny file-read*)` 会连 `exec` 一起挡住 (执行也要求读), 这是收紧. - 指向保护目录内部的符号链接会被拒绝, 指向外部的不受影响.