🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

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

DeepSeek Harnessv0.4.0
ddtcorex36 天前有提交已提供中文文档扫描:含敏感能力

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

30.7/100
综合分
1
GitHub 星标
31
npm 周下载
—/5
用户评分

数据截至 2026/9/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @ddtcorex/dsh-maestro-guard
npm 源 · @ddtcorex/dsh-maestro-guard 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · market
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/10/28·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 36 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

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

✓npm 包@ddtcorex/dsh-maestro-guard @ 0.4.0
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/5 08:37:26

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 44 处,展示前 44 条)
  • 执行外部命令固定命令
    lib/index.js:146
    return execSync('git branch --show-current', { cwd: dir, timeout: 800, encoding: 'utf-8' }).trim() || undefined;
  • 发起网络请求
    lib/index.js:212
    const outcome = await approval.request({
  • 写入本地文件
    lib/journal.js:109
    await mkdir(dirname(p), { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/journal.js:110
    await appendFile(p, line + '\n', { encoding: 'utf8', mode: 0o600 });
  • 写入本地文件
    lib/journal.js:111
    await chmod(p, 0o600);
  • 读取本地文件
    lib/journal.js:166
    const archives = (await readdir(dir)).map(parseArchive).filter((a) => a !== undefined).sort(byAge);
  • 读取本地文件
    lib/journal.js:179
    text = await readFile(p, 'utf8');
  • 写入本地文件
    lib/journal.js:222
    await mkdir(dir, { recursive: true, mode: 0o700 });
  • 读取本地文件
    lib/journal.js:226
    liveSize = (await stat(live)).size;
  • 写入本地文件
    lib/journal.js:236
    await rename(live, target);
  • 写入本地文件
    lib/journal.js:242
    await chmod(target, 0o600);
  • 读取本地文件
    lib/journal.js:251
    const archives = (await readdir(dir)).map(parseArchive).filter((a) => a !== undefined).sort(byAge);
  • 删除本地文件
    lib/journal.js:263
    await unlink(p);
  • 读取本地文件
    lib/journal.js:314
    mtimeMs = (await stat(journalPath(this.dshHome))).mtimeMs;
  • 读取本地文件
    lib/journal.js:353
    await stat(candidate);
  • 读取本地文件
    lib/migrate.js:19
    await stat(from);
  • 写入本地文件
    lib/migrate.js:25
    await mkdir(dir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    lib/migrate.js:26
    await rename(from, to);
  • 写入本地文件
    lib/migrate.js:27
    await chmod(to, 0o600);
  • 读取本地文件
    lib/full-scan-tool.js:22
    if (existsSync(cand))
  • 读取本地文件
    lib/full-scan-tool.js:40
    if (!existsSync(script)) {
  • 执行外部命令固定命令
    lib/full-scan-tool.js:46
    const r = spawnSync('node', [script, ...extra], { encoding: 'utf-8', timeout: 30000, cwd: resolve(root) });
  • 读取本地文件
    src/host/full-scan-tool.ts:22
    if (existsSync(cand)) return cand
  • 读取本地文件
    src/host/full-scan-tool.ts:38
    if (!existsSync(script)) {
  • 执行外部命令固定命令
    src/host/full-scan-tool.ts:44
    const r=spawnSync('node', [script, ...extra], {encoding:'utf-8', timeout: 30000, cwd: resolve(root)})
  • 执行外部命令固定命令
    src/host/index.ts:171
    return execSync('git branch --show-current', { cwd: dir, timeout: 800, encoding: 'utf-8' }).trim() || undefined
  • 发起网络请求
    src/host/index.ts:240
    const outcome = await approval.request({
  • 写入本地文件
    src/host/journal.ts:165
    await mkdir(dirname(p), { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/host/journal.ts:166
    await appendFile(p, line + '\n', { encoding: 'utf8', mode: 0o600 })
  • 写入本地文件
    src/host/journal.ts:167
    await chmod(p, 0o600)
  • 读取本地文件
    src/host/journal.ts:221
    const archives = (await readdir(dir)).map(parseArchive).filter((a): a is ArchiveRef => a !== undefined).sort(byAge)
  • 读取本地文件
    src/host/journal.ts:231
    text = await readFile(p, 'utf8')
  • 写入本地文件
    src/host/journal.ts:272
    await mkdir(dir, { recursive: true, mode: 0o700 })
  • 读取本地文件
    src/host/journal.ts:276
    liveSize = (await stat(live)).size
  • 写入本地文件
    src/host/journal.ts:285
    await rename(live, target)
  • 写入本地文件
    src/host/journal.ts:291
    await chmod(target, 0o600)
  • 读取本地文件
    src/host/journal.ts:299
    const archives = (await readdir(dir)).map(parseArchive).filter((a): a is ArchiveRef => a !== undefined).sort(byAge)
  • 删除本地文件
    src/host/journal.ts:309
    await unlink(p)
  • 读取本地文件
    src/host/journal.ts:357
    mtimeMs = (await stat(journalPath(this.dshHome))).mtimeMs
  • 读取本地文件
    src/host/journal.ts:394
    await stat(candidate)
  • 读取本地文件
    src/host/migrate.ts:20
    await stat(from)
  • 写入本地文件
    src/host/migrate.ts:25
    await mkdir(dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/host/migrate.ts:26
    await rename(from, to)
  • 写入本地文件
    src/host/migrate.ts:27
    await chmod(to, 0o600)
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 审批存储
  • 密钥脱敏
  • 权限策略

README

由 DeepSeek 最新模型翻译生成
@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 "" …
展开完整文档(README 剩余 1 节)
@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)指名了守卫路径就会拒绝,写入重定向(>、>>、2>、&>、>|)的目标是守卫路径时也会拒绝——以绝对路径、~、$HOME 或
${HOME} 的写法。双重用途动词按其写入形状判断,而不是按其名称判断,否则
它们的读取形式就会变成不可申诉的拒绝: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 从管道输入该片段的内容都算数,因为每一个都是同一编辑在下一层的到达。
变更 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)不是篡改,会放行到普通规则,这正是守卫自身的拒绝文本(“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 中携带的某个条目与该规则的内置默认值不同。仅仅复述默认值的条目是表格在自我重复,而非用户选择——若遵从这些条目,就会使所有分类层面的细化(--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 聚合行持久化,因此它们不会出现在决策路径上。

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

工具

guard 注册三个宿主工具。所有工具对 guard 而言都是只读的:

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

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

配置 — domains.guard(schema v2)

在共享的 Maestro 设置存储中:

| 键 | 含义 |
| rules | 按规则 id 的层级覆盖(按 id 合并到默认值上)。与规则内置默认值相等的条目不是覆盖——除非某个条目与默认值不同,否则生效层级就是分类得到的层级 |
| protectedBranches | 被视为受保护的分支名称(默认 master、main) |
| protectedPaths | 当任何文件工具以这些路径为目标时触发 secret.access 的凭据路径 |
| guardPaths | guard 自身的配置/密钥路径(guard.tamper):设置文件、profile 行补丁、挂载 guard 的 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 profile 组合中的 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。该 profile 通过 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
预览分享卡片长什么样 ↓ddtcorex/dsh-maestro-guard
分享 · DeepSeek Harness Hub
ddtcorex/dsh-maestro-guard

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

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部