Saltar al contenido principal
I

dsh-approval-gate

iamnewhands/dsh-approval-gate

Fork mantenido de dsh-approval-gate. Si una operación neutral alcanza el umbral de confirmaciones y el juez no está disponible, se aprueba automáticamente en vez de volver a pedir intervención humana. Las explicaciones para quien aprueba se generan en chino a partir del modo sandbox, comando y rutas reales. También deniega de forma determinista la exfiltración de credenciales y la destrucción de rutas del sistema, enmascara la entrada del juez, ofrece cadena de modelos jueces, permisos por fingerprint y vista de aprobación con diff unificado y reversión con un clic.

Instalar

dsh plugin --profile web add github:iamnewhands/dsh-approval-gate

README

简体中文 | English

dsh-approval-gate

DeepSeek Harness 自动审批门控 —— 最小人工介入,安全自动放行、危险转人工(fail-safe)。

判定模型预判每次沙箱越界:常规操作自动放行,硬风险操作(删除 / 凭据 / 远程 / 系统 / 批量)永远转人工确认;学习沉淀只针对你确认过的操作,并提供界面化人工审查入口。

判定管道:硬拒(凭据 / 系统路径,判定模型无权推翻)→ 硬事实人工 → 危险词 → 危险动作围栏(v0.9.7)→ 敏感路径永远人工(v0.9.8)→ DSH 配置自动放行 → 白名单(v0.9.8 按命令锚定)→ 定域放行(v0.9.7)→ 工作区外一律人工(v0.9.8)→ denyRules → 脱敏 → 判定(JSON 硬类别优先 → allow/ask/deny)→ 学习沉淀。

来源:本项目是 moon09300731/dsh-approval-gate 的 fork, 在其基础上修复了若干缺陷并扩展了多机规则共享。原作者版权与 MIT 许可见 LICENSE。 本仓库(IamNewHands/dsh-approval-gate)为维护中的版本。 其中 5 项能力移植自 NanmiCoder/dsh-auto-mode(MIT),见下文「吸收自 dsh-auto-mode」。

✨ 特性

  • 💾 全量导出 / 导入(v0.9.13):设置页「备份与迁移」卡片把本机的规则与判定参数整份导出成一个 JSON(白名单 / 永久人工 / 危险词 / 硬类别 / 阈值与超时 / 定域与区外开关 / 裁判模型 / 学习进度),拷到另一台机器导入即可同步开始使用。导入可选合并(并集,本机规则保留,幂等)或覆盖(按设置包替换);「判定参数与裁判模型」可单独关掉;「会话规则提升为全局」专治跨机器会话 id 对不上、会话规则永不生效。导入前自动备份(import-backup-*.json,可整份回滚),被拒绝的导入不写盘。导出包只认白名单字段、不含机器路径,也不碰 profile 的 cordis.patch.yml(权限预设仍走「一键配置」)
  • ⚡ 模型风险预判:每次沙箱越界由判定模型给出严格 JSON 裁决(allow / ask / deny),可回补操作自动放行
  • 🎛️ 裁判模型可选(v0.9.2):设置页「裁判模型 · 与主力模型解耦」卡片直接下拉选择判定模型(路由 + 模型,首项「跟随 agent 默认模型」),不用手改 allowlist.json;模型目录不可用时降级为手填输入框。判定模型选错是「每次审批都转人工」的常见真因(多步工具循环型模型在判定超时内跑不完)
  • 🛑 确定性硬拒(吸收):凭据外泄与根/系统路径销毁基于真实路径与凭据事实直接拒绝(不弹窗),判定模型无权推翻;home 根与 DSH 配置档的例外仍转人工
  • 🗂️ DSH 配置自动放行(v0.9.5):$DSH_HOME 下的 profile / 插件 / 依赖改动(cordis.patch.yml、package.json、pnpm-workspace.yaml、skills/、node_modules/ …)不再弹人工——实测最近 7 天 36 次人工里有 20 次是这类。两道例外仍转人工:审批门自身的数据目录 $DSH_HOME/auto-approve/(改它等于放行自己)与凭据类文件名(api-key / token / secret / credential / .env / id_rsa / *.pem / *.key)。本档排在危险词之后,命中不可逆危险词仍先转人工。(v0.9.1 那条「DSH_HOME 写入永远人工」已被本版反转,理由与残余风险见 CHANGELOG)
  • 🎯 按命令锚定 + 工作区外一律人工 + 敏感路径永远人工(v0.9.8):规则的 contains/keywords 改为只按真实事实(命令 + 真实目标)匹配 —— 说明措辞不再授予权限(实测 30 天 897 条自动放行里 30 条命令里根本没有规则词,例如 gh run view 被 contains:"github" 放行)。指纹来源同步锚定(追认 / 沉淀 / 学习都取自命令),追认的 contains 改为目录级,同一目录换个文件名不用重新审批。工作区外一律人工(outside / mixed → 人工,unknown 不拦),排在白名单之后,所以你手写的区外规则(%APPDATA%\Rime 等)仍然生效;$DSH_HOME 的命令类维护(pnpm --dir … install、改 pin)由 DSH 配置档补口继续自动放行(实测保住 54 条)。敏感路径形态永远人工:.ssh / .aws / id_rsa / credentials* / .env* / *.pem / *.key / .git-credentials / Cookies / Login Data / 审批门自身数据目录 —— 工作区内的 .env 同样命中,而 src/credential/transport.ts 这类源码文件不误报。实测:人工提示 147 → 178 次/30 天(+21%),换来 30 条真误放行被修掉 + 2 条凭据路径永远人工。两个开关(定域放行 / 工作区外一律人工)都可一键回退
  • 🚧 危险动作围栏 + 定域放行(v0.9.7):工作区内的操作按定域直接放行(事件记 verdict: scope,判定器零调用),同时在工作区内也拦下六类动作并转人工:网络下载(curl / wget / iwr / Invoke-RestMethod / gh release download …,URL 全为本机时豁免)、动态执行(iex / -EncodedCommand / FromBase64String / | bash …)、依赖安装(pnpm / npm / pip install / docker pull …,指向 $DSH_HOME 时豁免)、持久化(schtasks / reg add / New-Service / Set-ExecutionPolicy …)、递归删除(Remove-Item -Recurse / rm -rf / git clean …;单文件清理不拦)、可执行产物(写 .exe / .dll / .ps1 / .bat / .git/hooks/ / .github/workflows/ …)。围栏排在白名单与学习之前——已沉淀的 contains 宽规则盖不过它,否则一次追认就能把「下载」永久放行。拦截原因进事件与卡片(字段表格新增「拦截原因」行)。实测 30 天:围栏命中 23 次(其中 13 次原本自动放行),定域放行省下 23 次人工提示,净少 10 次。设置页可一键关闭定域放行。诚实交代:围栏是文本特征匹配,能被刻意混淆绕过,它挡的是「模型被诱导」,不是定向攻击
  • 🧭 目标定域(v0.9.6):审批记录新增「目标位置」行(工作区内 / 工作区外 / 跨工作区内外 / 无法定域),与「影响范围」(沙箱模式)分开成两行。命令类工具的绝对路径不再丢失(实测 628 条带命令的真实事件里 458 条原本提不出任何绝对路径),说明措辞里的相对片段(origin/main、IamNewHands/repo、.git/objects)不再冒充目标;引号内含空格的路径完整保留,/d/...(Git-Bash 写法)折算到 D:;系统程序位置(bash.exe)与 /dev/null 不算数据目标。只读目标只进 targets,不进 files —— 否则 Get-Content ~/.ssh/id_rsa 会把私钥复制进审批门自己的快照目录。.. 穿越与「一个绝对路径都没有」一律记为 无法定域(fail-closed)。判定模型同时拿到这些真实路径,不再只凭措辞猜。本版不改动确定性裁决逻辑(硬拒 / 危险词 / 白名单 / 学习一行未动),但判定模型的输入变了,因此判定层对命令类调用的裁决可能与以前不同
  • 🔬 危险词按边界匹配(v0.9.1):关键词命中要求词/标志边界,git push --force-with-lease(带租约的安全强制推送)与 docker rmi 不再被当成 push --force / docker rm;真正的 push --force 仍照旧转人工
  • 🔐 审批作用域可选(v0.9.4):追认时可指定仅本次 / 本会话 / 全局(默认本会话;「仅本次」不写规则,只放行重试的那一次);设置页的「新审批沉淀的作用域」决定人工确认后自动沉淀写在哪个范围。学习计数按 会话|工具|模式|类别 隔离,任一会话都无法靠反复触发养出影响其他会话的规则。你手写的规则、仓库种子、内置默认规则,以及本次升级前沉淀的旧规则都是全局生效;会话规则可在白名单卡片一键「提升为全局」。denyRules(你拒绝过的操作)有意保持全局:拒绝侧跨会话只会多弹一次人工,不会放行任何东西
  • 🧱 来源校验补 scheme 与端口(v0.9.3):来源必须与请求自身的 Host 逐字同源(scheme + host + port),javascript: / data: / null 来源一律拒绝;只有「请求 Host 是回环地址且来源是回环别名」才允许跨端口(127.0.0.1 / localhost / [::1])。DNS rebinding 的字面同源页面靠凭据围栏拦截(见 GUIDE)
  • 🔒 判定输入脱敏(吸收):密钥与大块正文在送判定模型前被抹除/截断,避免密钥随判定请求出站
  • 🛡️ 硬风险永远人工:删除、凭据、远程/生产、系统路径、批量不可回补五类操作直接转人工,不计数、不学习、不可追认;这是一道对称安全闸——无论判定模型给 allow 还是 deny,命中硬类别一律转人工(v0.7.0 修正:此前 deny 会抢先静默拒绝,使硬类别配置失效)
  • 🎯 确认制学习:同一会话内,同一操作人工确认 N 次后,第 N+1 次起自动放行;沉淀规则携带操作指纹,只放行你确认过的操作,作用域按设置页的「新审批沉淀的作用域」写(本会话 / 全局)
  • 🧠 语义同类验证:措辞变化但意图相同的操作,由判定模型对照你的确认样本语义判断,不再依赖关键词
  • ♻️ 判定器失败兜底(吸收,v0.8.0 语义修正):判定器不可用第一次就转人工(不再静默拒绝——判定器挂了不等于你的操作有害);失败原因(超时/上游报错/正文为空)写进审计与审批记录;批准后沉淀带指纹的放行规则,同类调用不再过判定器。阈值 judgeFailureLimit(默认 1,设为 >1 回到旧的"先静默拒绝"节奏)
  • 🔗 判定模型候选链(v0.8.0):主判定模型 → 会话默认模型 → 内置兜底;单通道抖动(502/超时)不再等于判定器整体不可用
  • 🧮 学习兑现优先于判定器(v0.8.2):确认计数已满阈值(riskyThreshold)的 neutral 操作,在判定器不可用时直接按已完成的确认放行,不再因为判定器抖动而反复弹人工审批。硬拒 / 硬事实 / 危险词 / 白名单仍排在判定之前,硬风险类别照旧每次人工确认
  • 🧾 提权提示永远写清命令与目标(v0.8.3):提权说明固定包含「命令 / 目标路径」两行,host 没给就写明 host未提供;danger-full-access 追加「不限定路径,本次授权覆盖整机」,避免被误读成单路径授权。命令按 callId 严格命中失败时回溯最近同名调用并标注来源(仅影响给人看的说明,不参与硬拒/规则/快照判定)
  • 🩺 会话事件读取根因修复(v0.8.4):此前一律读 session.events,而 DSH 的 Session 只有 snapshotEvents() / ownEvents() —— 结构化参数、确定性硬拒层、判定模型的用户授权来源三处因此长期失效。现按 snapshotEvents() → ownEvents() → events 依次取事件。行为变化:写入 C:\Windows\...、~/.ssh 等受保护位置的调用会直接硬拒且不弹窗;危险词层能看到真实命令,命中危险词的操作更常转人工
  • 🧹 没有命令的工具不再写命令行(v0.8.5):只有命令类工具(pwsh / bash / terminal-bash 等)才输出「命令」行,write / edit 只显示目标路径,文件类审批不会再挂一句毫无信息量的 命令:host未提供
  • 📊 审批说明改成字段表格(v0.9.0):审批记录行内渲染操作类型 / 操作路径 / 影响范围 / 执行命令 / 模型说明五个字段——操作类型做命令级判定(Remove-Item/rm/format/git reset --hard → 删除,git … push/gh release/npm publish/scp → 推送发布,write → 新增写入,edit → 修改),影响范围按沙箱模式给后果(整机 / 工作区 / 只读);删除红、新增绿、修改蓝、推送发布琥珀。宿主审批卡的纯文本也改为字段分行(操作:… / 路径:… / 影响:… / 命令:… / 原因:…),不再是一整段散文;顶部提示条用一行摘要。事件新增 facts 字段承载结构化事实(老事件由事件 API 按已记录事实现算补上,不回写文件),缺 facts 时照旧回退文本渲染
  • 🔢 「审批」tab 显示条数(v0.9.0):顶部 tab 文案变成 审批 (12),数字是本会话「审批」视图真正列出的记录数(等待人工的记录只活在提示条里,不计入),不打开 tab 也能一眼看出有没有新记录
  • 💬 提示层减负(吸收):预设激活期间向会话注入 <auto_approve_policy>,从源头减少需要判定的越界请求
  • 🔧 配置热更新:allowlist.json 修改即时生效,无需重启
  • ✅ 人工审查 UI:自动放行时输入框上方出现绿色提示;「审批」视图(轨迹右侧)展示当前会话完整放行时间线,静默拒绝单独标红
  • 🈶 审批说明中文化(v0.8.1):审批卡片与「审批」视图的说明一律中文——原文是英文或带宿主英文前缀(escalate sandbox to …)时,用真实事实(目标沙箱模式、真实命令、真实目标路径)生成中文说明并交代后果(可写范围 / 能否回滚 / 是否影响工作区外);命令与路径原样保留,模型原文作附注追加。事件新增 zh 字段承载中文说明,justification 原文仍留档
  • 🔔 拒绝提示条常驻(v0.7.0+):静默拒绝与人工拒绝的提示条不再几秒消失,而是一直挂在对话框上方(带「查看审批记录」/「重新审批通过」按钮),直到你切到「审批」tab 才收起;已读位置本地持久化,刷新不丢也不重复打扰。追认过的拒绝已放行,既不计入待处理,也不会再弹红色提示条(v0.7.1)
  • ↩️ 追认被拒操作(v0.7.0+):审批记录里的静默拒绝可一键「重新审批通过」——写入带操作指纹的自动放行规则并投递重试指令让 AI 重跑。围栏:确定性硬拒档与硬风险类别不可追认(给按钮就是假承诺)
  • 📄 文件改动对比与撤销(v0.5.0+):审批涉及的文件可点击查看 unified diff——变动行带上下 5 行上下文、多处修改按 hunk 分区并以「N unmodified lines」分隔条折叠、绿加红删灰上下文、双行号;一键「撤销此改动」投递指令让 AI 按快照恢复文件
  • 🗂️ 会话级快照管理(v0.5.0+):快照按事件归属会话,审批视图按当前会话统计;清理支持「仅清本会话」与「清空全部」两档,避免误删其他会话未查看的 diff 记录

🔌 吸收自 dsh-auto-mode

以下 5 项移植自 NanmiCoder/dsh-auto-mode(MIT License),按本仓库的判定管道语义改写并补充了回归测试:

能力说明
确定性硬拒src/paths.mjs + hardDenyFacts():路径事实熔断(文件系统根 / 系统与凭据关键路径 / Windows 设备命名空间 / 保留设备名)+ 凭据外泄判定,分「直接拒绝」与「转人工」两档
判定输入脱敏src/sanitize.mjs:私钥/令牌/Bearer/key=value → [redacted-secret];密钥类字段整字段抹除;大块正文只留长度;深度 3 / 数组 25 / 对象 50
结构化裁决协议src/classifier.mjs:严格 JSON {decision, reason, category},替代原文本 SAFE / RISKY:<类别>;任何格式偏差抛错并 fail-safe
连续失败计数按会话计数;judgeFailureLimit 默认 1(第一次失败即转人工,v0.8.0 修正),设为 >1 则前 N-1 次静默拒绝、第 N 次转人工;成功即清零。失败原因(超时/上游报错/正文为空)记入审计与事件
动态系统提示systemPrompt.context 注入 <auto_approve_policy>,仅在本预设激活时输出

差异:上游挂在工具管道(ctx.tools.guard + tools/pre-execute)且只做一次性判定、无跨会话学习;本仓库挂在 approval/request,保留确认制学习、操作指纹、同类语义验证与快照撤销。

📸 界面速览

① 审批视图

审批视图

「审批」标签页(轨迹右侧)按时间倒序展示当前会话的自动放行与人工审批记录:每条记录含工具名(bash / edit)、判定标签(「自动放行 · Flash 判定安全」「人工通过」等)、时间与操作说明。顶部统计栏显示本会话的 diff 快照占用(2.9 KB · 3 条),并提供两个清理入口:「仅清本会话」(只删除当前会话的快照,不影响其他会话未查看的 diff)与 「清空全部」(二次确认后清空所有会话,防止误删)。

被静默拒绝的记录(红「已直接拒绝」)额外带一个 「重新审批通过」 按钮:点了就写入带操作指纹的自动放行规则,并向会话投递重试指令让 AI 重跑该操作。标题旁的 待处理 N 角标显示还有几条拒绝没追认。追认之后该行翻转为 「已追认放行 · …(曾直接拒绝)」 完成色,并从待处理计数中移除。确定性硬拒档(凭据外泄 / 系统路径销毁)与硬风险类别(删除 / 凭据 / 远程 / 系统 / 批量)不显示该按钮——前者白名单盖不过、后者必须每次人工确认,给按钮就是假承诺。

② 文件改动对比(diff)

diff 对话框

点击审批记录中的文件即可打开对比面板:以 unified diff 展示改动前后差异——新增行绿底(+)、删除行红底(-)、上下文行灰底;左侧显示原/新双行号;多处修改按 hunk 分区,块间以灰色「6 unmodified lines」分隔条折叠未变更区间。顶部统计 +2 / -2 行变更 · 20 行未变。底部 「撤销此改动」 一键向对话投递撤销指令,AI 将按审批前的快照恢复文件。

③ 设置 · 自动审批

设置-自动审批

设置页「自动审批」分区提供完整配置:初始化权限预设(一键写入 cordis.patch.yml 的 auto-approve 预设)、备份与迁移(全量导出 / 导入,v0.9.13)、当前判定管道总览(DENY → 白名单 → denyRules → Flash → 学习)、危险词黑名单(预置条目 + 自定义添加)、以及热更新说明(修改即时生效,无需重启)。

🚀 快速开始

dsh plugin --profile web add "github:IamNewHands/dsh-approval-gate#main"

npm 上的 dsh-approval-gate 是上游 0.5.0,不含本仓库修复,请勿按包名安装。

  1. 配置权限预设:在 ~/.dsh/profiles/web/cordis.patch.yml 添加 auto-approve 预设(详见指南)
  2. 重启 dsh web
  3. 选择预设:会话权限下拉选中「自动审批(Flash)」

📖 文档

📄 License

MIT

Plugins relacionados