@dnalec/dsh-auto-approve
自动审批 / 自动审核需要审批的工具调用:先用关键词分桶做零上下文红线匹配,再交由审核模型判类别与风险等级, 按命中行与等级那一格决定自动允许、自动拒绝或转人工;判定没跑成固定转人工,自动拒绝会把原因回传给模型。
安装
dsh plugin --profile web add @dnalec/dsh-auto-approve
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
dsh-auto-approve
[English](README.md) | 中文
DeepSeek Harness 插件:用关键词和审核模型(类别 + 风险等级)自动允许或拒绝工具调用。每个类别按 low / medium / high 三档各配一个动作,完全由你决定。拿不准就交给原来的网页审批框。
安装
dsh plugin --profile web add github:DNAlec/dsh-auto-approve
打 tag 发布后也可从 npm 安装:
dsh plugin --profile web add @dnalec/dsh-auto-approve
需要可复现的版本时在末尾加#vX.Y.Z(tag 与package.json的版本一致,发布流程会校验)。
重启 dsh web。首次启动会把「自动审批」权限预设写进当前 profile 的 cordis.patch.yml;写失败时日志会指出文件和原因。
设置
设置页 → 自动审批。页面上每处只留一行提示,规则在这里说全:
1. 自动审批模式 — 工作区内不审批(workspace-write,推荐),或工作区也走判定(read-only)。点选即写入;然后重启 dsh web,再重新选择「自动审批」或开新会话。
2. 关键词 — 三个桶:拒绝 / 人工 / 允许。匹配工具名、命令、路径、工作目录,以及自定义工具(MCP 等)那些不认识名字的参数值;看不见写入内容、代码正文与数字/布尔开关({content:"rm -rf /"}、{recursive:true} 只能靠审核模型判)。拒绝/人工词也匹配工具名;允许词不匹配工具名,也不匹配会话目录名——避免把 bash/write 整类放行。
3. 审核表 — 一行 = 英文 id + 说明(写清「什么情况下选这个 id」)+ 三格动作(low / medium / high → 动作,等级 id 在页面上原样显示)。审核模型只看 id 与说明,动作由程序按 (行, 等级) 查格执行;other 不能删除,但说明与三格都可改。id 会显示在审批历史里。
4. 风险等级 — 三档说明都会送进提示词。等级认不出时按哪一档(默认 high)决定查「那一行的哪一格」,所以它同时决定后果:兜底 high 直接拒绝、medium 转人工、low 自动放行。
5. 审核模型 — 模型、思考强度、审核超时、送审内容上限、输出预算(token),以及超过送审上限 / 撞收集护栏时转人工还是直接拒绝(参数没采集到永远直接拒绝,不可配,见「怎么判定」)。同一张卡片里还有审核提示词:用 {{criteria}} 插入当前审核表、{{levels}} 插入风险等级说明,删掉占位符时会把对应定义附在末尾;可改,恢复默认写回所选语言的出厂模板并把语言切过去。
输出预算(judge.maxTokens,默认 8192,区间 256–32768)是审核模型首轮一次能写多长(推理 token 与正文共享这个上限)。给少了会出事:模型默认就在思考,本地实测每次推理 3.7k–8.3k 字符(≈2–5k token),早先 1024 的档位必然被推理吃光 → 正文为空 → 插件换成大预算重试一次,等于每次判定白跑一次模型调用(延迟翻倍,20s 超时更紧);2026-09-14 那次「每次判定都转人工」的故障就是这条链走到极端(当时重试只给 2048,两次都被吃光)。maxTokens 是上限不是预扣——不思考的路由写完就停,给足空间不会变慢,只会省掉那次注定失败的首轮。它只对会推理的路由生效(没配档位但路由报告有推理能力也算);不推理的路由固定 256。判不出来的现场在设置页「测试判定」与审计里可见。
6. 模型转人工(默认关闭)— 开启后自动拒绝会带上原因,并允许模型把某次操作转成人工审批;工具名可改(重启生效),提示语言可选中英。注意开启意味着审批框变成模型能主动叫醒你的通道——包括它正被不可信内容驱动的时候。
7. 会话权限选 自动审批。
恢复默认按钮各带语言(审核表、等级说明、提示词各有中英两份),选中即写入 config,并同时决定框架、卡片文案与理由的语言。
升级说明:审核表一行从「一个 action」变成「三格 action」,老文件的 action 会自动播种到三格;action 字段会在下次写盘时消失。出厂三格自 v22 起改成「等级刻度」:所有行统一 low 允许 / medium 人工 / high 拒绝——这是相对旧版的行为变更(旧版风险行三格全拒绝、safe 三格全允许、other 三格全人工),升级后请复核默认行为与兜底档。只有你自己拉开过格子的行不会被迁移改动。other 不再是特殊行——不可删除,但说明与三格都可改,它承接「输出认不出」。审核提示词模板加了 {{levels}} 与第三行输出;自定义模板没要求输出等级时,等级一律按「等级认不出时按」那一档执行(默认 high)。
自 v23 起两处出厂文案消歧(同样只刷新仍是出厂原文的行与档位,你改过的一个字不动):system 行补上「/tmp、/var/tmp 这类临时目录下的临时产物按实际操作判,不因路径落在 /var 就选本行」;low 档说明从「本次工作区或临时产物」收紧为「只落在本次工作区内(含工作区里的临时产物)」。原因是旧文案与 medium 的「工作区外文件、缓存」直接重叠——实测同一个「工作区外写一个临时文件」既被判过 low(自动放行)也被判过 medium(转人工)。另外审核模型首轮输出预算从 1024 提到 8192(可在设置页调),详见「设置」第 5 条。
怎么判定
仅当会话预设是「自动审批」时介入。workspace-write 下,工作区内写入不会进审批。danger-full-access 走同一条管道。
管道:拒绝关键词 →「参数没采集到」永远直接拒绝(不给人工框:那是插件侧采集故障,会告诉模型重新发起同一次调用)→ 人工关键词 →「看得见吗」闸门(撞收集护栏 / 超过送审上限:按「审核模型」卡片里选的动作,默认转人工)→ 允许关键词 → 审核模型(类别 + 等级)→ 按 (行, 等级) 查三格动作。顺序有两层含义:用户显式写的拒绝/人工词对「闸门里的调用」同样生效;但允许词不能放行它们(放行必须在看清之后才成立)。类别认不出(输出认不出)走兜底行 other 的三格;判定压根没跑成(空输出、超时、调用失败、没有可用路由、插件异常)固定转人工,不看 other 怎么配;请求被取消不产生判定。没有「内容多少」的闸门:只要没超上限,卡片上有什么就原样交审核模型判——空参数、只有 description/workdir、纯数字/布尔开关都照常送审;「没有可审的操作内容」这道开关已整套删除(见 CHANGELOG)。自定义工具(MCP 等)参数名不在已知字段里不算缺参:参数连键名(含 params.command 这类嵌套路径)一起送审核模型,也进关键词干草,参数照实记在审批记录里。数字/布尔参数也算内容:{recursive: true, force: true} 这类开关会上卡片、交审核模型判,不再被当成「没给参数」。
送审内容要么完整、要么不问模型:卡片不做任何字段裁剪、也没有条数上限;量的是整条请求(系统提示词 + 卡片)与设置页的送审内容上限(默认 20000 字符,区间 8192–1000000;下限必须覆盖英文出厂框架 ~5.8k 字符,否则每次判定都送不进模型)。超过就按设置页审核模型卡片里「超过送审上限 / 撞收集护栏」选的动作处理——选「拒绝」时这类调用不弹框,拒绝原因按闭集说明回传给模型——并写一条日志与审计行(request=<实际>>预算,撞到收集护栏记 oversize=collect>8388608),不会静默转人工。审核模型永远不会拿到被切了一半的操作;事件里的 argsOmitted 只是存档层的省略,不代表当时送审过残缺内容。
1. 关键词(同一条调用命中多个桶时取 拒绝 > 人工 > 允许;允许桶只在闸门之后生效)。匹配工具名、命令、路径和工作目录、请求方给的 reason 文本(只会多拦,不会少拦),以及自定义工具那些不认识名字的参数值(否则 {cmd: 'rm -rf /'} 这类调用会绕过红线);允许桶只认命令/路径/工作目录,参数名认不出时绝不自动放行。关键词看不到写入内容、代码正文与数字/布尔开关({content:"rm -rf /"}、{recursive:true} 这类只能靠审核模型判)——它只承接「零上下文就确定灾难」的红线,别当成万能拦截器,也别因此把审核表写得太薄。允许词不匹配工具名,也不匹配会话目录名。出厂拒绝词只留三类「零上下文就确定灾难、不该让模型有发言权」的红线:① 清根 rm -rf /(写法连 rm -rf /*、sudo rm -rf / 一起覆盖);② 裸设备覆写与格式化(of=/dev/、mkfs、wipefs、Format-Volume、Clear-Disk、diskutil eraseDisk);③ 门控自身的配置(.dsh/auto-approve、auto-approve/allowlist、auto-approve/config.json、.dsh/profiles、.dsh/config.yml、cordis.patch.yml)与私钥/云端凭据(id_rsa/id_ed25519/id_ecdsa/id_dsa、.pem/.p12/.pfx/.jks、authorized_keys、.netrc、.git-credentials、.pypirc、~/.aws/credentials、~/.kube/config)。公钥不算(id_rsa.pub),dd 写 /dev/null 这类伪设备不算。
其余一律交给审核表按各行说明判:递归删除(rm -rf 家族、sudo rm、Remove-Item -Recurse -Force、rd /s /q)、chmod -R 777、git push --force、drop table/delete from、terraform destroy、docker system prune/volume rm、关机重启,以及 .env/.npmrc/docker config.json 这类工具会自己改写的凭据文件——可再生成的目录与常规操作放行,删用户数据/源码、破坏生产或远端历史拒绝,拿不准转人工。被移出出厂表的词都在 RETIRED_DEFAULT_KEYWORDS 里留档,想恢复硬拒加回 DEFAULT_DENY_KEYWORDS 即可;自己的词也可以放人工桶(弹网页框问你,默认留空)。点文件按路径字段放宽匹配:prod.env 命中,命令里的 process.env 不误伤。
2. 审核模型。一行只有 id + 说明:说明写「什么情况下选这个 id」,模型输出 id、风险等级和一句理由,动作由程序按 (行, 等级) 查三格执行。等级按「可回补性 + 影响范围」描述,与类别各自独立判断;模型没给等级、给了认不出的词、或自定义提示词没要求输出等级时,按设置页选的兜底档(默认 high)查格。审核模型看到与网页工具卡片相同的字段,外加自定义工具自己的参数名(MCP 的 cmd、嵌套的 params.command,按 参数 <键>: 值 追加在卡片末尾),并明确标记为不可信数据;模型理由与描述不算操作本体。类别必须唯一:剥掉卡片回显后,认得出的表内行只允许一条,出现两条互不相同的行(含「表内一条 + 认不出的标签行」)就按歧义失败关闭、落兜底行;等级同理,互相矛盾就作废、交给「等级认不出时按」那一档——回显不能决定放不放行。输出认不出时归到 other,不再直接转人工——它走的是 other 的三格。判定压根没跑成(超时、空输出、调用失败、没有可用路由、插件异常)是另一回事:这些不是模型的结论,固定转人工,不看 other 的三格。
默认审核表(id 是英文小写,会显示在审批历史里;说明与三格动作都可改;出厂每一行都用同一套三格:low 允许 / medium 人工 / high 拒绝——等级就是默认风险刻度;other 不能删除,但说明与三格都可改):
id · 什么情况下选它 · 出厂三格(low/medium/high)
deletion · 删除/清空/截断/不可逆覆盖用户数据、数据库、备份、历史、未提交内容(单文件源码编辑不算;能确认是本地/临时开发库的常规改动也不算) · 允许 / 人工 / 拒绝
credential · 改动密钥、token、证书私钥、.env、authorized_keys、kubeconfig、~/.aws、带 token 的 .npmrc、git/pypi 凭据 · 允许 / 人工 / 拒绝
remote
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:8,最后更新 2026-09-16