dsh-isolation-gate:DSH 目录访问管制门禁

前言

DeepSeek Harness(DSH)在处理本地文件和命令时,需要明确哪些目录受控、受控到什么程度。已有的权限插件多按「工具 / 命令 / 参数」立规则,而本插件按「目录」立对象:哪些目录属于禁区、现在给什么级别、谁改的、agent 自己怎么查。

它的核心是管理面:一屏开关、分组批量切、审计可查、agent 自查。

它是什么

dsh-isolation-gate 是给 DSH 的隔离区授权台插件,由 huanlin-labs 维护,分类为 admin-security。

它不是又一个 allow/deny 规则引擎,也不是沙箱本身。规则引擎回答「这次调用准不准」,门禁回答「这个目录开不开」。两者可以叠着用,不冲突。

核心功能

三级权限

  • deny:默认禁,任何访问都会被拦
  • read:只读,不能写
  • full:可读写删

受管对象

两类受管对象:

  1. 名字:D 根一级目录名,如 Zcode
  2. 任意绝对路径:如 <drive-root>\Zcode、E:\资料\合作档案\某项目

默认禁 + 名单制

只有名单里的对象受管;未列出的不归它管;新增对象一律先按「禁」处理。

一屏开关

每个对象一个分段控件(禁 / 只读 / 可读写删),点了即落盘,重启后保持。

分组

「harness 隔离」「跨家合作」这类命名组;组头一键切三档;组只存在状态文件里,名单仍是”一行一对象”。

两个拦截点

  1. 受管辖通道 bin/gate.mjs
  2. 宿主工具执行门 ctx.tools.guard()(2026-10-21 新增)

两条路都调用同一个 checkAccess,所以面板、CLI、工具门不会说两套话。

审计

~/.dsh/dsh-isolation-gate/access-log.jsonl:只记时间/对象/级别/操作/允许与否/理由,不记文件内容。

agent 自查

node bin/gate.mjs status —— 模型/脚本可以直接读策略,不用猜。

安装

dsh plugin --profile desktop add dsh-isolation-gate

桌面版也可以走「插件」页的添加插件,填包名或本地路径。

改装配需要重启 dsh。开关本身不需要重启:改级别、改名单都是即时落盘。

默认配置

配置项 默认值 说明
statePath <data-root>/isolation-gate/state.json 状态唯一真身
rosterPath <data-root>/isolation-gate/roster.txt 名单(一行一对象)
backupDir <backup-dir> 改名单前备份
root <drive-root>\ 列”一层目录”的根
auditPath ~\.dsh\dsh-isolation-gate\access-log.jsonl 审计日志
toolGate true 关掉就只剩通道层

状态文件(v3)

状态文件格式如下:

{
  "version": 3,
  "defaultLevel": "deny",
  "groups": { "harness 隔离": { "note": "", "updatedAt": "…" } },
  "objects": {
    "Zcode": { "level": "deny", "note": "", "group": "harness 隔离", "updatedAt": "…" },
    "E:\\资料\\合作档案\\某项目": { "level": "read", "note": "", "group": "", "updatedAt": "…" }
  },
  "profiles": { "严格交付": { "mode": "allowlist", "allow": [{ "path": "E:\\资料\\库", "level": "read" }], "network": "deny", "unknownTool": "deny" } },
  "sessionOverrides": { "<sessionId>": "严格交付" }
}

旧格式仍可读:v1 的 harnesses: { key: { level } } 与 v2 的 objects 读入时自动收敛成 v3。文件缺失 = 全禁;坏 JSON = 全禁且不覆盖原文件。

判定语义

  1. 给路径时先算真身路径(目标 realpath,或”最深已存在祖先 realpath + 剩余片段”)
  2. 在路径对象里找最长前缀命中(按路径段比较、忽略大小写)
  3. 没命中路径对象 ⇒ 退回”盘根一级目录名”匹配名字对象
  4. 都不中 ⇒ 不属受管对象,本通道放行(它只管辖名单内的东西)
  5. 名单缺失 / 读坏 ⇒ 一律拒绝(fail-closed),不是”放行一切”

工具执行门

ctx.tools.guard 覆盖:read / read_image / grep / glob / write / edit / str_replace_editor / apply_patch / mkdir / move / copy / delete / bash / pwsh / …

  • shell 命令会做词法分解:cd + 相对路径、重定向、管道、bash -c "…" 都会跟进去
  • 未知命令只要命令文本里出现受管绝对路径,就按写处理(只在 full 放行)
  • 判定自身抛错 ⇒ fail-closed(按拒绝处理)
  • bin/gate.mjs 自身的调用豁免工具门(它自己会判定,否则会双重拦截)

CLI(agent / 脚本用)

node bin/gate.mjs status                       # 全部级别
node bin/gate.mjs policy                       # 紧凑策略行(可塞进提示词)
node bin/gate.mjs check  --name Zcode --op read
node bin/gate.mjs check  --path "<drive-root>\Zcode\某文件" --op delete
node bin/gate.mjs traverse --path "<drive-root>\Zcode"
node bin/gate.mjs read   --path "<drive-root>\Zcode\某文件"
node bin/gate.mjs write  --path "<drive-root>\Zcode\某文件" --text "内容"
node bin/gate.mjs delete --path "<drive-root>\Zcode\某文件"   # 删前自动备份到回收站
node bin/gate.mjs rmdir  --path "<drive-root>\Zcode\空目录"   # 只删空目录(不递归)
node bin/gate.mjs log    --limit 20

退出码:0 放行 / 成功 · 3 被拒(拒绝文案在 stderr)· 2 用错或环境错误。

护栏:判定在 I/O 之前;只删文件不删目录;删除前自动备份,备份失败即中止;名单不可用一律拒绝。

HTTP 路由(宿主半 · 本机同源)

方法 路径 作用
GET /__dsh-isolation-gate/ping 身份 + 路由清单 + 能力(toolGate / picker)
GET /__dsh-isolation-gate/state 全量状态(名单 / 级别 / 分组 / 差异 / 审计 / 策略行)
POST /__dsh-isolation-gate/level { name, level } 改一个对象
POST /__dsh-isolation-gate/roster { action:'add'\|'remove', name } 名单增删
POST /__dsh-isolation-gate/group-level { group, level } 组级一键切
POST /__dsh-isolation-gate/group { action:'assign'\|'delete', name?, group }
POST /__dsh-isolation-gate/prune 清理孤儿键
POST /__dsh-isolation-gate/pick 调原生目录选择器(无则 400,面板自动走退路)
POST /__dsh-isolation-gate/toolcheck { tool, args } 工具门干跑(不执行工具)
POST /__dsh-isolation-gate/check { name?\|path?, op } 判定(不读内容)
GET /__dsh-isolation-gate/log?limit= 最近审计

带外部 Origin 的请求一律 403;错误方法 405;坏 JSON / 非法级别 400。

让模型自己管门禁(v1.1+)

插件注册 7 个模型可直接调用的工具,DSH 不必等人点面板:

工具 作用 权限
gate_status 看默认级别、受管对象、待批数、授权窗口 只读
gate_check 预判某目标某操作会被放行还是拦下 只读
gate_log 读最近审计记录 只读
gate_requests 看自己提交的待批申请 只读
gate_add 把目录/名字纳入受管,固定为「禁」 只收紧
gate_set_level 改级别;放宽必须带户主授权窗口 收紧可直做
gate_request 提交「想放宽」的待批申请 + 理由 申请

不对称规则:模型能读、能加、能收紧,不能自己放宽——放宽只有两条路:

  1. 提交 gate_request → 户主在「门禁」面板看到待批卡片 → 批准才生效;
  2. 户主主动点「授权 AI 放宽 30 分钟」→ 窗口期内模型可直接放宽,到期自动收回。

没有任何「批准」工具,模型无法自己开门。所有工具调用都进审计日志。

对模型说一句就能用:

用 gate_status 看看现在什么被禁;确认 D:\仓库\合作档案 还是禁的话,帮我提个只读申请,理由写”核对合作档案里的结论”。

与其它插件的分工

插件 它管什么 与本插件
dsh-house-guard(本机内建) 体系资产:固定几个受保护路径,只有白名单管家会话可写 目的不同、对象不重叠;两边都拒则拒(更严者胜)
PerryLink/dsh-permission-rules 规则引擎:allow/deny/ask + 工具参数/shell/网络 互补:它没有「只读」这一档;我们的面板不写它的 YAML,不依赖它
cherrchen/dsh-plugin-multi-root-workspace 给工作区加附加根(只读/读写),靠内核沙箱执行 互补:它是”扩权”,我们是”划禁区”;它强在拦截强度,我们强在管理面与分组
azazo1/dsh-write-protect 工作区内只读保护 + 额外可写根 互补;Windows 上它的 bash 侧有明确缺口

本插件不声明任何 @deepseek-ai/dsh* peer 依赖 —— dsh 升级不会因”版本豁免失效”被静默禁用。

稳定性承诺

从 1.0 起,下面这些只增不破;要破坏会走 2.0 并附迁移说明:

面 承诺
状态文件 磁盘格式 v3;v1 / v2 一读入时自动收敛成 v3;级别不丢;profiles / sessionOverrides 缺省为空;下一次写盘才落成 v3
工具门 覆盖范围只增不破;ctx.tools.guard 在 v1.1+ 注册;未知命令按写处理(只在 full 放行)

适用场景

适合需要明确「哪些目录受控、受控到什么程度」的 DSH 使用者:团队协作、跨家合作、交付场景。

插件以当前 dsh 进程权限运行。安装前应检查源码与许可证(MIT)。

结语

dsh-isolation-gate 提供了一个按目录管理的访问控制平面,默认禁、名单制、分组批量切、审计可查、agent 自查。它与规则引擎类插件互补,不依赖任何 dsh 内置 peer 依赖。

目录页 · GitHub

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜