工具哨兵 · dsh-sentinel
让 Agent 的每一次工具调用都有据可查,也为最危险的那一次按下保险丝。
dsh-sentinel 是给 DeepSeek Harness(DSH)做的工具调用审计与安全拦截插件。它挂在 Host 的工具管线上,在调用真正执行前判断"这次调用要做什么",并把结果同时写进本地审计日志、盾牌徽标和展开面板;在拦截模式下,灾难性的 shell 命令和受保护路径写入会被直接拒绝,模型收到的是一段可解释的拒绝理由。
它解决的是另一个问题:你不在电脑前时,Agent 到底动过什么、有没有动到不该动的地方。
仓库:https://github.com/yanliao66/dsh-sentinel
与已安装插件的关系
| 已装插件 | 它负责 | 本插件不做 |
|---|---|---|
dsh-pins(记忆钉) |
跨会话偏好/约定,注入系统提示 | 不存笔记、不改系统提示中的偏好 |
任务板 task-board |
定时、后台、看板式任务执行 | 不调度、不创建会话 |
dsh-better-sidebar |
文件树、编辑器、变更视图 | 不编辑文件、不读工作区树 |
dsh-usage / 小鲸鱼挂件 |
token、余额、花费 | 不统计 token、不查余额 |
dsh-pet / 壁纸 / 市场 / 浏览器 / 视觉 |
桌面宠物、外观、插件市场、浏览器、识图 | 都不是本插件的领域 |
在本 profile 已安装的插件集合里,没有第二个插件做工具调用的审计、风险判定或策略拦截。本插件也不与它们共用数据文件。
三种模式
| 模式 | 行为 | 适用 |
|---|---|---|
audit 审计 |
全部记录,从不阻止 | 先观察 Agent 的工作方式,收集自己的规则 |
enforce 拦截(默认) |
阻止高危命中:根目录删除、格式化磁盘、关机重启、远程脚本直执行、关闭安全防护、写入系统/密钥/Profile 路径等 | 日常最稳妥的默认值 |
strict 严格 |
在高危之外再阻止中危命中:递归删除、git reset --hard、强制推送、提权、结束进程、DROP TABLE 等 |
给无人值守的长任务加一道更紧的锁 |
模式是用户权限:只能在面板里切换,或者改 settings.json;Agent 的 sentinel 工具没有切换入口。切换即时生效,只影响之后的调用。
内置规则
高危(enforce 起阻止):
shell.root-delete:rm -rf /、rm -rf ~、Remove-Item -Recurse C:\、rd /s C:\这类删除根/主目录/系统盘shell.no-preserve-root:--no-preserve-rootshell.fork-bomb:(){ :|:& };:shell.disk-format:mkfs、diskpart、dd ... of=/dev/sd*、format C:、vssadmin delete shadows、cipher /wshell.boot-config:bcdedit、bootrecshell.power:shutdown、Stop-Computer、Restart-Computer、reboot等shell.remote-exec:curl ... | sh、iwr ... | iex、iex(New-Object Net.WebClient)shell.security-disable:Set-MpPreference -Disable*、关闭防火墙、Set-ExecutionPolicy Bypassshell.hklm-delete:reg delete HKLM ... /fshell.root-permissions:chmod -R 777 /、chown -R ... /path.protected-write:写入系统目录、.ssh/.aws/.gnupg/.kube/config、~/.dsh/credentials、~/.dsh/profiles、任何.git/内部路径,以及本插件自己的数据目录(Agent 不能改自己的模式和审计日志)shell.sentinel-self-edit:用 shell 重定向/删除方式改动dsh-sentinel/settings.json或当天的events-*.jsonltool.sentinel-admin:用plugin_manager停用或移除监视器本身(用户可以在 GUI 里手动操作,Agent 不行)
中危(strict 起阻止,始终记录):
shell.recursive-delete(递归删除)、shell.git-destructive(reset --hard / clean -fdx / 强推 / 删分支)、shell.privilege(sudo、runas、takeown、icacls /grant)、shell.process-kill(taskkill /F、Stop-Process -Force、sc delete/stop、net user)、shell.sql-destructive(DROP/TRUNCATE DATABASE/TABLE/SCHEMA)、shell.registry-write、shell.secret-exfil、shell.history-clear
规则是启发式匹配(大小写不敏感的正则),刻意写得保守:只命中形式明确的命令,不尝试解析完整 shell。内置规则可逐条关闭;还可以在面板里添加自定义规则(≤40 条,最长 200 字符,拒绝 (a+)+ 这类可能拖死工具管线的嵌套量词,正则非法会被拒绝并给出原因)。
面板
- 输入框工具行:盾牌按钮。徽标显示今日拦截数(没有拦截时显示高危数),颜色随模式变化。
- 点开面板:
- 顶部:模式切换与当前模式说明;
- 四张卡:今日调用 / 今日高危 / 已拦截 / 失败;
事件:最近的审计行,可按全部 / 高危 / 已拦截筛选,可刷新;显示工具、目标、风险、耗时、错误与拦截状态;规则:内置规则逐条开关,自定义规则增删;测试:对一条 shell 命令或写入路径做试运行检测,只匹配规则,不执行命令、不写文件;- 底部:数据目录、设置 revision、双击确认的"清空今日记录"(归档当天 JSONL,不删历史)。
Agent 工具 sentinel
只读,不会改变模式或规则:
| action | 用途 |
|---|---|
status |
当前模式、今日/累计计数、规则启用数、数据目录、revision |
check |
对 command 或 path 做试运行检测,返回风险、命中规则与当前模式下的决定 |
events |
最近的审计行,可用 limit / risk / blocked / session 过滤 |
rules |
当前启用的规则清单 |
当一次调用被拦截时,模型收到的是这段拒绝理由:
Blocked by dsh-sentinel (mode=enforce): shell.disk-format [high] 格式化或重写磁盘.
Target: mkfs.ext4 /dev/sda1. Nothing was executed. Do not retry this call ...
在 enforce / strict 模式下,插件还会向系统提示贡献一小段说明,告诉模型"被拦住时不要重试、不要绕开、不要改监视器,先解释再问用户";audit 模式下这段说明整体消失,不占 token。
数据与隐私
- 目录:
$DSH_HOME/dsh-sentinel/,可用行配置dataDir改 settings.json:模式、关闭的规则、自定义规则、额外保护路径,写入用 tmp + rename 原子替换events-YYYY-MM-DD.jsonl:每次已结算的工具调用一行;被拦截的调用在 guard 判定时就写一行,保证即使结果通知丢失也有记录- 每行含:时间、会话 id、工具名、目标预览(命令或路径,截断到 240 字符)、风险、命中规则、是否拦截、耗时、错误、参数预览
- 不会写文件内容:
write的content、edit的old_string/new_string一律不落盘,只记路径;参数预览最多 2 个字段 - 凭据预览会打码:
Bearer …、sk-…、api_key=…、--password …等在写入日志前替换为***;规则匹配仍使用原始命令 - 数据目录自身受保护:Agent 的
write/edit工具不能改dsh-sentinel/settings.json或审计文件;用 shell 重定向/删除这些文件会命中shell.sentinel-self-edit。模式与规则只能由用户在面板或 API 修改 - 保留期默认 30 天,启动时清理更早的日文件;内存环形缓冲最多 2000 条
- HTTP API 只接受本机回环请求,拒绝
X-Forwarded-For、Sec-Fetch-Site: cross-site、外部Host/Origin;插件不发起任何网络请求 - 日志是本机明文:有文件读权限的人都能看到;它不是加密审计,也不替代操作系统的权限与沙箱
安装、配置、卸载
从 GitHub 安装
git clone https://github.com/yanliao66/dsh-sentinel.git
然后在 DSH GUI 的「插件」页用 install_bundle 指向 clone 下来的目录(plugin_manager → install_bundle,target 填该目录的绝对路径)。装好后应看到 工具哨兵 / Tool Sentinel 一行,带盾牌图标;输入框工具行出现盾牌按钮。
配置
cordis.patch.yml 里的一行配置是部署默认值,面板保存的用户选择永远优先:
- id: dsh-sentinel
config:
mode: enforce # audit | enforce | strict
retentionDays: 30 # 日文件保留天数
captureArgs: true # 是否记录参数预览(不记文件内容)
maxMemoryEvents: 2000 # 内存环形缓冲
回滚:GUI「插件」页移除,或删除 profile package.json 里的依赖与 bundles 行后重新安装;数据目录保留,可手工删除。
限制(如实说明)
- 规则是启发式:可能误报(例如脚本正文里出现
shutdown字样)也可能漏报;它是一道保险丝,不是完备的安全边界。 - 只观察经由 Host 工具管线的调用;一个 shell 命令内部再派生出的删除/提权不会逐条检查,只看这条命令的文本;内联脚本(如
node -e写文件)也可能绕过文本规则。它是保险丝,不是权限边界。 - 相对路径无法解析出工作区绝对路径,因此只对绝对路径、
~、$HOME、%USERPROFILE%等写法和路径中的.git段生效。 - guard 是同步、fail-open 的:插件自身出错时放行并记一条 warn,不阻塞 Agent。
- 不替代沙箱、审批策略或系统权限;它拦的是"明显不该由 Agent 自己做的事"。
代码结构
| 文件 | 职责 |
|---|---|
index.js |
Host 半边:guard 注册、tools/result 观察、服务、HTTP 路由、sentinel 工具、系统提示段落 |
policy.js |
纯策略层:规则表、路径保护、自定义规则校验、模式判定、统计(可单测) |
audit.js |
本地审计存储:JSONL 追加、环形缓冲、保留期清理、当天归档(可单测) |
client.js |
浏览器半边:工具行盾牌、shell.overlay 面板、双语字典、主题 token 样式 |
test/ |
29 个用例:规则/路径/设置校验/统计/打码 + 假 Cordis 上下文跑完整 Host 装配 + 最小 React 垫片把浏览器半边的三个页签都渲染一遍 |
git clone https://github.com/yanliao66/dsh-sentinel.git
cd dsh-sentinel
node --test test/
许可
MIT。
No comments yet. Be the first to write one.