DeepSeek Harness 插件

drscrewdriver/dsh-perm-gate

Star 数 ★ 1 下载量(近 30 天) 956 分类 安全与权限 收录于 2026-09-10 npm dsh-perm-gate

P0–P4 确定性优先权限门控,含 Permissive 档位、学习沉淀与审批历史 UI;凭据/受保护路径硬拒绝,内部只读工具自动放行。

安装

# npm 包(预构建)

dsh plugin --profile web add dsh-perm-gate

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWEDERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yamlallowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

兼容性说明: v2.0.0 自带 ja / ko 字典,但官方 DSH 的 LocaleRuntime 只暴露 zh / enLOCALE_IDS = ["zh", "en"])。在原版 DSH 上选择 ja / ko 会报 locale "<id>" is not registered。请使用更新了 LOCALE_IDS (locale-settings.ts)与 LOCALES 标签(client/index.ts)的 DSH fork 并重新构建。

▼ DSH 版本适配

两个 DSH 版本线从两个长期分支分别维护,各有一套版本号系列、engines.dsh 和 npm 分发标签(发布布局):

DSH 版本 分支 版本号 npm 标签
0.1.0-rc.7 ~ 0.1.1-rc.x legacy 1.x @legacy
0.1.2-alpha.1+(含 0.1.5-rc.2) main 2.x @latest / @dsh-0.1.2@2.x 是范围)

版本序列号跟的是 DSH 线1.x = DSH ≤ 0.1.1,2.x = DSH 0.1.2+),两条大版本互 相隔离:锁在 ^1.x 的安装绝不会解析到 2.x,反之亦然。engines.dsh 表达同样的 分界,但 DSH 从不读取它——真正把旧 DSH 钉在 1.x 上的是版本范围与 dist-tag。

@deepseek-ai/dsh-client-runtime0.1.2-alpha.1 中已被移除——不仅仅是更名。 legacy 线仍通过它访问 ctx.slotsmain@deepseek-ai/dsh-client-ui-renderer/client 获得相同的声明。两处版本敏感 接缝通过能力探测处理,而非版本号检查:(1)设置注册使用 register,两线 都存在(installSection 是新增项,不是替代);(2)effectivePolicy 在两 线上都是 user-approval 服务的私有方法,因此通过 typeof 探测读取,缺失 或抛错时降级为「策略未知」。

版本 2.0.0 —— 变更见 Changelog

一个单一自足、确定性优先、fail-closed 的 DeepSeek Harness 权限门插件。

对每个工具调用按固定优先级链裁决:

阶段 决策 含义
P0 deny 确定性硬拒:凭据材料 / 受保护路径改写 / 危险 shell
P1 allow 精确、有界的会话放行 grant
P2 deny/allow/ask 静态规则链:黑名单优先,其次 allow,再 ask
P3 allow/deny/ask 可选 LLM 语义分类器(默认关闭
P4 ask 官方 approval seam

严格 fail-closed:P0 永不因 grant / 规则 / 分类器 / 人工而放行。

特性

  • 命令白/黑名单 — 基于 argv 分解匹配(非裸字符串),递归下钻 sh -c/bash -c、识别管道、重定向目标、递归/强制(rm -rf)。
  • deny 优先 — 命中黑名单即拒绝,胜过任何 allow。
  • 会话放行 — 精确的 (工具, 规范化 fingerprint) grant,带 TTL + maxUses;换目标绝不复用。子代理继承但不可自授。
  • 纯函数规则引擎 — glob/regex 编译 + ReDoS 上限、坏规则 loud fail、按源内容哈希缓存。
  • 审计 — 每次决策写为 {ignorable:true} 事件并带 callId;模型可见理由与记录一致。
  • 自动审查档位(机器值 permissive)——一个独立审批模式(区别于只读、完全权限与白名单档),既不是"自动审批",也不授予泛化权限。前端只暴露一个开关permissive),后台四个审批策略可组合、由插件设置决定——仍对 P0 保持 fail-closed。权限下拉框与设置行都按产品名「自动审查」显示,且不带图标。
  • 沙箱提权自动答复trustEscalation)— 沙箱提权是从 shell / pwsh / edit 工具体内部tools/pre-execute 之后)发出的,所以门禁从未见过它,一个它自动放行的调用仍会弹出确认。开启后,门禁以 callId 精确匹配已放行调用并直接答复。

安装

需要先安装 DeepSeek Harness

dsh plugin --profile web add dsh-perm-gate

完整的安装、升级、迁移与排查步骤见中文安装指南(另有 English / 日本語 / 한국어)。

配置

cordis.yml

- id: dsh-perm-gate
  name: dsh-perm-gate
  config:
    rulesFile: ./permissions.yaml   # 可选;默认 $DSH_HOME/perm-gate/rules.yml
    dshHome: $DSH_HOME
    defaultAction: ask
    gatePresets: [permissive]       # 门禁生效的档位(默认值)

规则示例:见 examples/permissions.example.yaml

自动审查档位(机器值 permissive

自动审查是权限下拉框里一个独立审批档,与只读 / 工作区内修改 / 完全权限 / 白名单平行。 它不是泛化的"自动审批"、也不授予泛化权限:只会在人类/LLM 接缝之前收窄或放宽决策, P0 硬拒绝始终单调且不可协商。

下拉框里的名字是宿主提供的产品名,不是逐语言的字典项:DSH 0.1.2 对插件档位在两个权限界面上 (通用设置默认档行、输入栏权限选择器)都原样渲染补丁里的 name:,只给三个内置档提供自己的本地化 标签,因此 cordis.patch.yml 直接写中文名,对所有会话一致。该档位不画图标——选择器的图标只按 三个内置值取。

cordis.yml

- id: dsh-perm-gate
  name: dsh-perm-gate
  config:
    rulesFile: ./permissions.yaml
    defaultAction: ask
    permissive: true            # 前端唯一的开关(启用独立档)
    permissiveStrategies:        # 后台策略,可组合
      trustAutoAllow: true       # 作用域内安全操作自动放行;危险/未知转 ask
      alwaysConfirm: false       # 一律逐次 ask;允许控件附带重复允许/迁白名单按钮
      trustEscalation: true      # 门禁已放行的调用,其自身的沙箱提权免确认
      llmAssist: false           # 先由 LLM 分类裁决;ask/无分类器时回退到人工

(llmAssist 的真实接收 LLM 在设置页填 classifierEndpoint / classifierModel,OpenAI 兼容的自定义 API 均可。设置页可选择接收来源:自定义 API(任何 OpenAI 兼容端点,内置小米 MiMo https://api.xiaomimimo.com/v1 等预设)或宿主模型组(复用 DSH 会话已配置的 llm 服务与当前模型组,可用 classifierProvider / classifierModel 覆盖);并提供健康测试按钮,一键验证接收 LLM 的连通性与延迟。)

trustAutoAllow 是中间档基线(rule-allow 自动放行)。alwaysConfirm 让每次越界都走审批面板,其 「允许控件」含两个扩展按钮:本会话重复允许该类(会话限次 grant,approveRepeat)与 允许所有类型(把命令词持久写进 permissions.yaml 的 allow 白名单,approveAllowEverywhere)。 llmAssist 调用配置的真实 LLM(任意 OpenAI 兼容 API)自动裁决 ask,结果不确定/出错时回退人工 接缝——始终 fail-closed。trustEscalation(档位开启时默认开)答复门禁已放行的调用在其工具体内 提出的 sandbox_permissions 提权;见下文。permissive 关闭时,门禁行为与之前完全一致。

沙箱提权:为何 safe 裁决仍会弹窗

一个工具调用可能触发两个独立的审批。门禁负责第一个——它的 ask,在 tools/pre-execute 瀑布上。第二个来自工具体内部的 approveEscalation,在 tools/execute 时刻,只要模型传了 sandbox_permissions + justification;此时 tools/pre-execute 已结算,门禁的放行从未到达它。 LLM 评定为 safe 且门禁自动放行的调用因此仍会弹出确认。

trustEscalation 填补这个缺口。门禁记住每个它正面向上放行的调用(以宿主 callId 为键,提权 请求会重复该值),并在本处自行答复 allowed-once。它仅在全部满足时适用:

  • 自动审查档位开启且 trustEscalation 开启;
  • 请求携带门禁放行的 callId,且工具名匹配;
  • 原因为已知的提权,指明 workspace-writedanger-full-access

其余所有情况——未知原因、不同的调用、门禁要求或拒绝的调用、approval: never 透传——都保持交给人 工,因此未来 DSH 措辞变更时 fail-closed。自动答复记录在事件流中 (verdict: "escalation-auto"mode: <目标模式>)。关闭开关可使沙箱放宽保持人工审批,其余 自动放行不变。

权限下拉里可选档位

cordis.patch.yml 在 DSH 的 permission.config.presets 里新增了 permissive preset (sandbox: workspace-writeapproval: ask、名称 自动审查),位于工作区内修改与 完全权限之间。DSH 的 bundle patch 对这个 map 是整表替换而非逐键合并,所以该文件还必须重述三个内置档 (read-only / workspace-write / danger-full-access,取自 @deepseek-ai/dsh-base/cordis.patch.yml);test/patch-presets.spec.ts 固定了这份键集合。因此会话权限 下拉里会出现「自动审查」这个独立可选审批档,而不是"auto-approval"档。

门禁只在 gatePresets 列出的档位里生效(默认 ['permissive'],即本插件新增的那一档)。在其余任何档位 (Read Only、Workspace Write、Full access、custom)里,门禁的判定流程完全不运行:不放行、不弹审批、 不拒绝、不执行 P0 硬拒绝、不做黑名单关键词拦截,也不写审计事件——该档位自己的策略说了算。这正是重点所在: danger-full-access 的定义就是"全权限、不弹审批",用 ask 去覆盖它毫无意义(该档 approval: never 会让审批接缝 在任何 answerer 运行之前直接返回 rejected,被转发的 ask 只能得到 the user rejected tool "...",面板根本不会 弹出),用硬拒绝去覆盖它则等于悄悄推翻用户选定的档位。gatePresets: ['*'] 可让门禁重新全局生效(含硬拒绝层); 在生效档位内,若会话生效的审批策略为 never,ask 仍会降级为放行。

在 UI 里可配置

该档位也可在运行时从 设置 → 插件 → 自动审查 调整(插件浏览器端渲染的 settings.plugins.tab 页面):一个开关切换 permissive,四个开关编辑后台 permissiveStrategies。host 端 live 读取该命名空间,改动对下一条工具调用即时生效,无需重启。 这是一个独立审批类,不是 DSH 的"auto-approval"档。

风险分级 llmAssist、裁决学习与事件流

开启 llmAssist 后,接收 LLM(自定义 OpenAI 兼容端点,或 DSH 宿主模型组——见上文)按结构化协议逐条评估 ask判定发生在门禁的 tools/pre-execute 瀑布内部、决策返回宿主之前safe 直接放行,审批面板根本不会出现;只有真正无法确定的判定才会弹到你面前。

  • safe → 自动放行(审计来源为 classifier),不弹面板。
  • risky + 硬风险类别deletioncredentialremotesystembulk)→ 自动拒绝、不弹面板;硬风险永不自动放行、也永不进入学习。
  • risky:neutral → 若开启 riskLearning(设置卡片内,默认关闭),人工批准且真实执行的 neutral 风险会按 tool|类别 计数;计数达到 riskThreshold(默认 3)且新调用的操作指纹(命令词 + 目标基名)命中已确认样本时,同一操作自动放行。不同目标永不复用该放行。开启学习沉淀(riskSediment,默认开)后,满阈值 key 的确认样本会成为确定性放行规则:指纹精确命中即直接放行、无需再过 LLM——即使关闭 llmAssist 也继续生效;沉淀规则在设置卡片中可见、可管理(终止学习 / 删除样本)。
  • 超时(riskTimeoutMs,默认 20s,重试 1 次)、传输失败与协议外输出均维持原 ask——门禁绝不猜测。

学习状态持久化在插件自有 JSON($DSH_HOME/perm-gate/learning.jsonlearningFile),不写入你的 YAML 规则文件。每次决策都会追加到 $DSH_HOME/perm-gate/events.jsonl(或 eventsFile),并经 GET /api/dsh-perm-gate/events?sessionId=&since= 提供;浏览器端轮询该接口,在输入框上方以提示条展示最新决策(ask 常驻至下一条事件),并在对话视图的「审批记录」页签按时间倒序列出本会话的全部判定。

每次决策涉及的文件都会在改动落地前快照(每事件 ≤5 个文件、单文件 ≤256 KB)到 $DSH_HOME/perm-gate/snapshots/;「审批记录」页签中每个文件 chip 可点开行级改动对比(GET /api/dsh-perm-gate/diff),并可撤销该改动——向会话投递恢复指令(POST /api/dsh-perm-gate/revert)。快照管理条支持按会话或全量清理(GET /api/dsh-perm-gate/snapshots-stats / POST /api/dsh-perm-gate/snapshots-clear)。

转人工的 ask 会被跟踪到人工给出答复为止:一个被动 approval/request 观察者记录封闭结果(allowed-once人工通过rejected人工拒绝cancelled人工取消unavailable → 拒绝,因为不存在审批通道);当观察者无法关联该 ask 时(缺 callId、无 approval 服务、上游监听者短路),由 tools/result 兜底结算同一个 ask。人工通过会显示通过后的学习进度(n/阈值),通知条也会为三种终态分别打标。

插件还内置一份预置黑名单关键词(继承自 dsh-approval-gate 的 DEFAULT_DENY_KEYWORDSrm -rfpush --forcedrop tablemkfsgit reset --harddocker system prune 等), 调用文本命中任一关键词(大小写不敏感子串)即直接拒绝,且先于白名单 / 授权 / LLM。黑名单在设置 卡片中按列表查看与增删(预置条目带标签,可一键恢复预置);未设置或为空时应用预置列表——黑名单 不会静默关闭。 该档位在权限选择器中不显示图标:选择器的图标只按三个内置值取,插件新增的档位是纯文字。

CLI(独立 dry-run)

dsh-perm-gate --rules permissions.yaml --tool bash --args '{"command":"pnpm install"}'
dsh-perm-gate --rules permissions.yaml --list

开发

npm run typecheck
npm test
npm run build

许可证

MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。