DeepSeek Harness Hub
← 返回列表

工具调用安全门禁ddtcorex/dsh-maestro-guard

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
⚠ 装前注意

@ddtcorex/dsh-maestro-guard

基本兼容但装前注意:未发布到 npm registry,仅可从源码安装 · 最近上游提交 2026/9/17 · 已提供中文文档

DeepSeek Harness 的仅主机安全门禁:审批存储、密钥脱敏、权限策略、瀑布式预执行集成。

综合分
30.7
GitHub 分
30.7
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add ddtcorex/dsh-maestro-guard
未发布到 npm registry,仅可从源码安装,改用 GitHub 源安装
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查⚠ 装前注意

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

npm 包@ddtcorex/dsh-maestro-guard(未发布到 npm,仅可源码安装)
Node 引擎未声明 engines.node
dsh CLI 依赖未声明 dsh 版本约束
入口文件main/exports/bin 已声明

未发布到 npm registry,仅可从源码安装

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/19 10:26:41

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

@ddtcorex/dsh-maestro-guard

DeepSeek Harness 的仅宿主安全门禁:一个 Cordis 行(dsh-maestro-guard)监听
tools/pre-execute 瀑布流,并在每次工具调用运行前对其进行裁决。

属于 Maestro Harness 套件(dsh-maestro-)的一部分。Cordis 补丁行 id:dsh-maestro-guard。

需主动启用,且在发布前有意不包含在元捆绑包的一行命令中:
使用 dsh plugin add @ddtcorex/dsh-maestro-guard 显式添加。

它提供什么

每次调用都运行相同的五步流水线:

parse → classify → decide → journal → act

1. parse — 读取调用的已执行表面:shell 工具的命令文本、文件工具的
路径字段。命令是被解析的,而非正则匹配:一个 shell 感知的分词器/分段器
在引号之外的运算符处将其切分,解开那些只改变谁来运行它的包装器(env VAR=…、sudo、nohup、time、command、busybox),并将 shell
包装器(bash -c 、bash -s、bash "、
cp "" /tmp/x、curl -T "" … 以及写入形式的 cp /tmp/x "" 都与其
未加引号的形式一样会询问。

语料库中的行 carried: interpreter inline program pushing a protected branch、carried:
node -e inline program tagging a release、carried: quoted data mentioning a release 以及
protected path: quoted … 这些行固定了这些决策——包括那个刻意的故障关闭权衡:一个提及受保护路径的解释器内联程序会再次询问。
guard.tamper 是唯一一条判断原始片段文本而非解析后形态的规则,
而且即便在那里,也只有 EDIT 才算数。一个总是写入其目标的动词(rm、mv、cp、ln、
truncate、shred、dd、tee、install、chmod、chown、patch、sponge、unlink、
rmdir、ed,外加 sed -i / perl -i)若提及一个 guard 路径则拒绝,写入
重定向(>, >>, 2>, &>, >|)若其 TARGET 是这样一个路径也同样拒绝——以绝对路径、~、$HOME 或
${HOME} 的写法。双用途动词按其 WRITE SHAPE 判断,而非按其名称,否则
它们的读取形式会变成不可申诉的拒绝:curl -o  …、wget -O  …、
一个 rsync/scp DESTINATION、不带只读开关的 vi/vim/nano 以及 patch 会拒绝,而
curl -I 、wget -O - 、rsync --list-only  /tmp/、
scp -r host: /tmp/、vi -R  和 nano -v  则放行。这种
变更也不必是该片段自身的动词:解析器未解包的包装器所运行的内容(nice、timeout、flock、ssh、watch)、find 动作标志所运行的内容、一个
-c 脚本所包含的内容,以及 xargs 从 PIPED 进它的片段中所取的内容,全都算数,
因为每一个都是同一编辑在下一层的到达。
一个变更 WORD 只在命令可以出现的地方被读取——对于该包装器类是整个 argv,
对于以提及开头的片段是 find 动作标志之后的 token——因此 less -p rm 、
ag rm  和 docker rm  仍是它们本来的读取和非编辑,而
tail  && xargs rm -rf /tmp/junk 不能跨过 && 借用该路径,而
cat  | grep x | xargs rm -f 仍会沿着管道追踪到删除命令。对
同一路径的 READ(cat、tail、head、grep、less)不是篡改,会放行到
普通规则,这正是使 guard 自身的拒绝文本("see the guard journal")
可遵循的原因。有三条限制是被记录而非隐含的:一个解释器内联程序
(python3 -c "… open(p,'w') …")是数据,一个围绕变更动词的 UNKNOWN runner
(my-custom-runner rm -f )不会被读取,因为没有什么能把它与一个参数仅仅拼写出 rm 的工具区分开,而一个 -c 脚本链只被读取两层深度(第三
层不被读取)。
2. classify — 将调用映射到一个稳定的规则 id(见下文),通过命令的 cd / git -C 解析出该命令所针对的仓库分支。
3. decide — 确定层级:即分类所得的层级,除非 domains.guard.rules 中携带的某条目与规则的内置默认值不同。仅仅复述默认值的条目是表格在自我重复,而非用户选择——若遵从这些条目,就会使每一处 classify 级别的细化(--dry-run 发布属于 journal,而非 ask)都变得不可达。
4. journal — 为每个决策追加一条脱敏记录。
5. act — 执行该调用或返回拒绝决策。

规则 id

规则 id 就是契约——配置覆盖、日志条目和审批理由都以它们为键。共有 11 个:

| 规则 id | 默认层级 | 触发条件 |
| --- | --- | --- |
| git.push.protected | ask | 针对受保护分支的推送:显式命名受保护分支的 refspec、通过目标仓库已检出分支解析出的 HEAD/无 refspec、--all/--mirror(它们会推送所有本地分支),或无法解析的分支(故障关闭) |
| git.merge.protected | journal | gh pr merge(记录而非拦截) |
| git.tag.release | ask | 发布/语义化版本标签推送(refs/tags/ refspec、裸 vX.Y.Z 或 --tags) |
| git.push.force | ask | 强制推送(--force、--force-with-lease、-f、+refspec) |
| gh.release.create | ask | gh release create / gh release publish |
| gh.protection.delete | ask | 针对分支保护的 gh api … DELETE |
| pkg.publish | ask | 包管理器发布(npm / pnpm / yarn) |
| secret.access | ask | 访问受保护的凭据路径——任何文件工具(读或写),其路径字段为受保护路径,或解析出的片段中 COMMAND 为访问动词且其 argv 包含该路径(仅提及的动词如 grep/ls/printf 永远不算访问,消息或正文中的访问动词不是命令,heredoc 正文永远不是 argv) |
| fs.write.outside | ask | 在会话工作目录之外的文件工具写入(操作系统临时目录豁免,当 spillReads 开启时运行时溢出目录也豁免) |
| net.exec.remote | ask | 将远程脚本管道传入 shell(curl … \| sh、source  :: ):

Approval required
git.push.protected :: git push origin master
Allow once   /   Reject

Allow 会运行那一次调用(日志中为 outcome: granted)并返回 next(),因此任何其他 pre-execute 监听器仍会运行;下一次 git push origin master 会再次询问——不存在长期授权。Reject 会向 agent 返回拒绝,并记录 outcome: rejected,这正是 maestro_guard_status 随后显示的内容。完全无法弹出的提示就是上述故障关闭的 unavailable 结果,绝不会是静默允许。

日志

~/.dsh/dsh-maestro-guard/journal.jsonl —— 每个决策一行 JSON,权限模式 0600。机密类别(注册表令牌、环境变量赋值、认证头、私钥)会在 Journal.append 这一咽喉点被脱敏,因此持久化条目的每个字符串字段都会被脱敏,且没有任何
调用点可以写入一个未脱敏的值;已执行的调用永远不会被重写。一个遗留的
pending.json 票据文件在首次启动时退役为 legacy-pending.json。

普通(allow)决策从不单独进入日志:它们在内存中计数,并作为一个周期性的 counters 聚合行持久化,因此它们不处于决策路径上。

轮转和保留独立运行:在启动时,如果实时文件的上次写入早于今天,守卫会轮转它,然后每天轮转一次,将其归档为 journal-YYYY-MM-DD.jsonl,并修剪落在两个保留窗口(retainFiles 和 retainDays)之外的归档文件。因此,实时文件保持有界,并且这些旋钮在从不重启的主机上真正生效——轮转是基于时间的,而不是大小触发,并且 Journal.rotate() 仍然可以按需调用。

工具

守卫注册三个宿主工具。所有工具相对于守卫都是只读的:

- maestro_guard_status — 最近约 20 条决策、生效的规则层级,以及
日志路径/状态。
- maestro_guard_stats — 最近约 1000 条日志条目的折叠计数器:byRule、
byTier、byOutcome,以及 ask 审批延迟百分位数(p50 / p90 / max)。
byRule/byTier 仅折叠规则属于封闭规则 id 之一的行,因此守卫自身的
簿记行(counters、config-legacy、guard.migration、policy.deny)不会出现
为决策;byOutcome 统计每一行。
- maestro_full_scan — 按需全量扫描。

没有审批工具:ask 由 DSH 自己的提示来应答,因此任何代理都无法授予自己
受保护的操作。

配置 — domains.guard(schema v2)

在共享的 Maestro 设置存储中:

| 键 | 含义 |
| --- | --- |
| rules | 按规则 id 的层级覆盖(按 id 合并到默认值上)。与规则内置默认值相等的条目不是覆盖——除非某个条目与默认值不同,否则生效层级就是分类得到的层级 |
| protectedBranches | 被视为受保护的分支名称(默认 master、main) |
| protectedPaths | 当任何文件工具以这些路径为目标时触发 secret.access 的凭据路径 |
| guardPaths | 守卫自身的配置/密钥路径(guard.tamper):设置文件、profile 行补丁、挂载守卫的 profile package.json,以及日志 + legacy-pending.json |
| journal | enabled、allowCounters,以及保留窗口 retainFiles(14)/ retainDays(30);不是正整数的窗口会回退到内置值(小数值过去会被向下取整为 0 并修剪每个归档) |
| workingDirContainment | enabled(默认 true)开启/关闭 fs.write.outside 规则;spillReads(默认 true)使运行时溢出目录免于该规则——设为 false 也会对溢出目录写入进行门控 |

journal 块在启动时读取一次(它决定日志是否写入,以及
哪些保留默认值会被轮换使用),因此更改它需要重启宿主。其他所有键,
包括 workingDirContainment,都属于每次调用时读取的配置,会在下一次
工具调用时生效。缺失、不可读或写入一半的配置会回退到内置默认值——
保护在精度上降级,但覆盖范围绝不降级。

旧版键(为 schema v1 编写)在读取时会被向前转换,转换后的键每次启动
记录一次日志:

| 旧版键 | 映射到 |
| --- | --- |
| gitProtection.enabled: false | 三条 git 规则(git.push.protected、git.tag.release、git.push.force)变为 journal |
| gitProtection.branches | protectedBranches |
| publishBlocked: false | pkg.publish 变为 journal |
| cwdContainment: false | fs.write.outside 变为 journal |
| credentialPaths | 添加到 protectedPaths(绝不替换它) |

显式的 v2 rules 条目优先于生成同一规则 id 的旧版布尔值。

必须保持同步的部署文件

ask 层级只有在会话实际弹出提示时才会生效,而有两个部署文件承载了这一点
(两者都不随本包发布):

- web 配置文件组合中的 permission 行
(~/.dsh/profiles/web/cordis.patch.yml)——其 presets 表必须定义
danger-full-access 且 approval: ask(带提示的完全访问模式沿用
现有的预设值,从而保留选择器内置的盾牌图标、产品标签和风险确认);
- ~/.dsh/settings.yaml 中的 permission.defaultPreset——必须指定
danger-full-access,这样新会话会弹出提示,而不是在 approval: never
预设下运行。

只改其中一个而不改另一个,会导致每次 ask 都被拒绝(故障关闭,但不可用)。
回滚:将 permission.defaultPreset 设回 danger-full-access,移除
permission 行补丁,重启。

实时验证是一项记录在案的、有意的推迟——而非疏忽。 规范将
在 :3080 上的 CDP 探测(提示出现并带有渲染的原因;Allow 会运行;Reject 会阻止;
never 会话被拒绝并给出可操作的提示信息;后台子代理故障关闭)标记为
“完成”前的必需项。人工推迟了会将此构建放入运行中宿主的 dsh web 重启,
因此已部署的宿主仍是 0.2.3。配置文件通过 link: 安装此包,且 lib/
已经构建,所以任何无关的 dsh web 重启都会将未经验证的 0.3.0 部署到
一个实时的审批提示上——在此验证运行之前,该构建在生产环境中未经验证。

仅宿主:无客户端 bundle;DSH 类型来自本地结构化声明
(src/host/augment.d.ts)。

开发

pnpm install
pnpm verify   # tsc --noEmit
pnpm test     # vitest run
pnpm build    # tsc -> lib/

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群