dsh-approval-gate
DeepSeek Harness 自动审批门控插件 v3:最小人工介入,只把必须人工确认的操作转人工(fail-safe)。
当会话的权限预设为 auto-approve(自动审批(Flash))时,每次审批请求(沙箱越界)按管道判定:
DENY(不可逆危险词)→ 白名单(确定性规则)→ denyRules(裁决拒绝升级)→ flash(SAFE / 硬类别 / 中立确认)→ 学习沉淀
- ① DENY 层:
rm -rf/drop table/force push/ 格式化等不可逆危险词命中 → 转人工(最高优先,fail-safe) - ② 白名单层:命中规则 → 直接放行(确定性,不过 LLM)。默认规则
{mode:"workspace-write"}—— 工作区写入(可回补)自动放行;也支持tool/mode/category/contains组合规则(含学习沉淀的规则) - ③ denyRules 层:此前用户裁决拒绝过的「工具+模式+类别」→ 永久转人工(不会自动放行用户明确拒绝过的操作)
- ④ flash 判定(仅越界请求):输出
SAFE或RISKY:<category>SAFE→ 自动放行- 硬风险类别(
deletion删除 /credential凭据 /remote远程生产 /system系统路径 /bulk批量不可回补)→ 直接转人工(必须人工确认,不计数、不学习) neutral(中立,无硬风险特征)→ 人工确认制:前 N-1 次转人工确认,第 N 次起自动放行
- ⑤ 学习沉淀(neutral 类别,N=3 时:前 2 次人工确认,之后进入阈值状态)
- 阈值前:一律人工确认,批准 → 计数 +1 并记录操作样本(指纹 + 操作背景/目的);拒绝 → 升级 denyRules
- 阈值后(计数 ≥ N-1)三种分流:
- 指纹确定性命中(本次操作在确认样本中)→ 自动放行 + 沉淀
{tool, mode, category, contains}规则 - 指纹未命中但有确认样本 → 把本次操作的背景/目的 + 用户确认过的样本交给 flash 第三方同类验证:判
SAME(与已确认样本同类)→ 自动放行(有指纹则沉淀);判DIFFERENT/验证失败 → 人工确认 - 无确认样本 → 人工确认
- 指纹确定性命中(本次操作在确认样本中)→ 自动放行 + 沉淀
- 用户拒绝 → 升级进 denyRules(带指纹;提取不到指纹则拦全部同类,拒绝从严)
- 取消/不可用 → 不计数(用户未表态,下次仍人工确认)
- 硬类别/DENY/验证失败永远人工,同类验证只作用于 neutral 阈值状态
安装
# 方式一:npm 安装(推荐)
dsh plugin --profile web add dsh-approval-gate
# 方式二:GitHub 安装
dsh plugin --profile web add "github:moon09300731/dsh-approval-gate#main"
⚠️ 安装后必须手动配置权限预设(关键步骤)
插件无法向权限预设表添加选项(预设表在配置构造时冻结),需要手动在 profile 的 cordis.patch.yml 中补一条 preset:
编辑 ~/.dsh/profiles/web/cordis.patch.yml,追加(或合并进已有的 permission 行——loader 的 patch 会整体替换目标行的 config,若已有该行必须重述全部预设):
- id: permission
name: '@deepseek-ai/dsh-permission-presets'
config:
presets:
read-only:
sandbox: read-only
approval: ask
workspace-write:
sandbox: workspace-write
approval: ask
danger-full-access:
sandbox: danger-full-access
approval: never
auto-approve:
sandbox: workspace-write
approval: ask
name: 自动审批(Flash)
description: 多级判定:工作区写入自动放行,危险操作转人工审批。
重启 dsh web 后,权限下拉菜单会出现「自动审批(Flash)」选项。
配置(可选)
数据文件统一放在 $DSH_HOME/auto-approve/(默认 ~/.dsh/auto-approve/):
| 文件 | 说明 |
|---|---|
allowlist.json |
白名单/黑名单/阈值配置(首次运行自动生成默认值,旧版自动迁移) |
learning.json |
学习状态(自动维护,跨会话持久化) |
audit.log |
审计日志(追加式) |
allowlist.json 结构(v3):
{
"version": 3,
"denyKeywords": ["rm -rf", "drop table", "force push", "格式化"],
"allowRules": [
{ "mode": "workspace-write", "description": "工作区写入自动放行" },
{ "tool": "bash", "mode": "workspace-write", "contains": "git add", "description": "特定工具+模式+关键词" }
],
"denyRules": [],
"hardCategories": ["deletion", "credential", "remote", "system", "bulk"],
"riskyThreshold": 3,
"judgeTimeoutMs": 20000,
"learning": { "enabled": true }
}
denyKeywords:命中即转人工(不可逆危险操作)allowRules:每条规则tool/mode/category/contains均满足才放行(缺省表示任意)。学习沉淀的规则也会写入这里denyRules:用户裁决拒绝后自动写入,命中即转人工(不学习)hardCategories:flash 判 RISKY 且命中这些类别 → 直接转人工(不计数、不学习)riskyThreshold:中立类别的人工确认阈值(默认 3)——同一「工具+模式+类别」被人工确认 N-1 次后,第 N 次起自动放行并沉淀规则judgeTimeoutMs:单次 flash 判断超时(默认 20000ms,超时自动重试 1 次,仍超时转人工)
使用
在会话的权限下拉(/permission 弹窗或设置页)选中**「自动审批(Flash)」**,该会话即启用自动审批;其他会话不受影响(按会话预设门控)。
人工审查 UI(v0.4.0+)
每次命令被自动放行时,提供两处审查入口(严格按 DSH 设计语言,--dsw-alias-* tokens):
- ✅ 实时提示条:输入框上方独立一行(
conversation.input.dock,order=30,排在 todo/goal/queue 之下、不随流式对话滚动)。自动放行时出现绿色 ✅ 提示:工具 + 操作摘要 + 判定路径标签(白名单规则 / Flash 判定安全 / 沉淀规则 / 已确认操作 / Flash 同类验证),8 秒自动收起,可手动关闭;无事件时完全不占位 - 「审批」历史视图:会话视图切换条「轨迹」右侧的「审批」tab(
conversation.view,order=20)。展示当前会话所有自动放行动作的时间线:✅ + 时间 + 工具 + 原因(justification)+ 涉及文件标签 + 判定路径徽标
数据链路:host 每次自动放行时追加结构化事件到 ~/.dsh/auto-approve/events.jsonl(含 sessionId/tool/mode/reason/justification/verdict/files),浏览器通过 GET /api/auto-approve/events?sessionId=&since= 轮询(2s 增量 / 视图 5s 全量)。
安全设计
- DENY 层最高优先:不可逆危险词命中即转人工,不消耗模型调用、无误判
- 硬风险类别永远人工:
deletion/credential/remote/system/bulk不计数、不学习、不可被沉淀规则覆盖 - 学习规则带类别 + 操作指纹:沉淀的是
{tool, mode, category, contains}(contains = 用户确认过的操作指纹),只放行同一指纹的操作;指纹未命中时由 flash 语义级同类验证(基于用户确认样本判断操作意图是否同类),判 DIFFERENT/验证失败一律人工;拒绝过的操作升级 denyRules(带指纹,提取不到则拦全部同类),永不自动放行 - fail-safe:flash 调用失败、超时(20s×2 次尝试)、输出无法解析 → 一律按中立降级或转人工,绝不自动放行硬风险
- 可回补优先:
workspace-write(写工作区)默认放行,越界才走 flash - 按会话门控:只有显式选中「自动审批(Flash)」预设的会话才介入
- 只预判、不执行:插件只返回允许/转人工决策,不修改审批流程的其他环节
警告:自动审批会显著降低人工介入频率。仅供可信环境使用,涉及生产数据、远程系统、支付扣费等高风险场景请保持
ask预设。
技术说明
- 挂载于
approval/request瀑布最前(prepend: true,先于 web answerer 接单) - 门控:
permissionPresets.current(session.events) === 'auto-approve' - DSH 审批触发点是沙箱越界,
reason固定为escalate sandbox to <mode>: <justification>,mode仅workspace-write/danger-full-access两级 - flash 判定:
reasoningEffort: 'off'+maxTokens: 64,输出SAFE或RISKY:<category> - 超时兜底:
AbortController传入llm.stream的 signal(可取消底层请求),Promise.race+ctx.timeout(judgeTimeoutMs),超时 abort 并重试 1 次 - 学习闭环:通过 waterfall 的
next()返回值捕获人工裁决结果(allowed-once沉淀 /rejected升级)
License
MIT
No comments yet. Be the first to write one.