中文EN

dsh-plugin-content-policy

security已测通过npmMIT 條件偏離

Preventive content policy for DeepSeek Harness tool results: rewrite matched text with regex rules, or drop/truncate unpredictable payloads by field path before they are normalised, rendered, or persisted. The upstream counterpart to dsh-plugin-redact.

📦 体积
0.19 MB · 小巧
🔌 需要联网
未声明
✅ 沙箱测试
已通过
🏷️ 已发布版本
2 个

這個插件適合誰

  • 用 DSH 寫代碼、需要 Git 整合的開發者
下载量 / Downloads
0
依赖体积 / node_modules
0.19 MB
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

安装

dsh plugin --profile web add dsh-plugin-content-policy

沙箱测试结果

條件偏離 —— 本結果在 DSHIO/T 21 v0.9 條件下產生(內存 1g、CPU 1.5、T4 超時 60s,未記鏡像 digest)。偏離條款:5.1.3(内存 768MB)、5.1.3(CPU 1 核)、5.1.6(T4 超时 90s)、5.1.2(镜像 digest)。按 DSHIO/T 21 §8.2,該判定不得與標準條件結果比較,不得用作認證依據。
阶段结果
T0 静态检查—
T1 安装✓
T2 列装✓
T3 挂载✓
T4 启动—

四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。

README

dsh-plugin-content-policy

预防式内容策略:在 DSH 的工具结果被规范化、落盘、进入下一次 provider 请求之前改写它。

它是 dsh-plugin-redact(事后补救:原地脱敏已经写进 session.vN.jsonl.zstd 的日志)的事前对应物:

redact 擦掉已经留下的东西,本插件让不该留下的东西根本没机会留下。

两条互补的策略,挂在同一条接缝上(tools/execute),顺序固定为 先 strip、后正则:

策略 · 配置 · 认识内容吗? · 适用场景

内容改写 · rules[] · 认识:你给字面量/正则,命中即替换 · 你已经知道要挡什么(手机号、密钥、内部域名…)

结构最小化 · strip[](+ stripDefaults) · 不认识:只按字段路径整段丢弃/截断 · 事先无法枚举的载荷(公开检索回来的任意段落),对策是"让它根本不进来"


1. 为什么必须发生在 append 之前

一次 session.append('tool/result', …) 有两个后果,而且它们是同一份数据:

后果 · 证据

它成为持久日志里的一行 · dsh-agent-loop/lib/index.js:703-712(session.append("tool/result", { turn, step, message, …result.meta }))

它是将来每一次请求里那条工具结果消息 · dsh-session/lib/index.js:216:deriveEventMessage 对 tool/result 直接 return event.data.message;请求由 session.deriveMessages() 折叠同一批事件得到

所以"事后脱敏"永远慢一步:内容在写入的那一刻就已经同时进了日志和(下一次请求的)上下文。

本插件把自己插在 tools/execute 瀑布里 —— 那是结果被规范化之前唯一的改写点。

尤其要注意两条通道:web_search 把同一段 snippet 同时放进渲染文本(content)和

presentationMeta(持久化 meta)。只换 content 会漏掉 meta,见接缝表第 6、7 行。


2. 接缝表(每条都对着 shipped 源码核过)

# · 接缝 · 源码位置 · 本插件怎么用

1 · tools/execute 瀑布 · 声明:dsh-tools/lib/types/index.d.ts:49 · 主接缝:包装器返回值会被注册表重新规范化

2 · 返回值规范化 · dsh-tools/lib/index.js:3213-3214(waterfall('tools/execute', …) → normalizeDispatchResult) · 我们返回的对象就是下游 tools/post-execute 看到的 result

3 · 同一性快路径 · dsh-tools/lib/index.js:3448(canonicalResults.get(result) === exec.token ⇒ 原样返回) · 无改动时按引用返回原结果 ⇒ 零开销、不二次渲染

4 · 成功结果从 value 重新派生 content · dsh-tools/lib/index.js:3458 → :3422(createSuccessResult → tool.output.render(exec.arguments, value)) · 我们改写 value,content 由注册表自己重算

5 · 成功结果从 value 重新派生 meta · dsh-tools/lib/index.js:3428-3436(presentationMeta(exec.arguments, value)) · 同上:meta 也自动跟着 value 变

6 · 只换 content 会留下旧 meta · dsh-tools/lib/index.js:3401-3405({...result, content} 展开保留 meta) · 这是本插件改写 value 而不是 content 的原因

7 · meta 会被持久化 · dsh-agent-loop/lib/index.js:708(...result.meta !== void 0 ? { meta: result.meta } : {}) · 只换 content ⇒ 命中文本仍随 meta 落盘

8 · 同一段文本双通道的真实例子 · dsh-tool-web/lib/index.js:62-79(snippet 进 content)与 :103-124(同一 snippet 进 presentationMeta) · web_search 是最典型的"只擦 content 不够"案例

9 · 失败结果不能替换 value · dsh-tools/lib/index.js:3392(tools/post-execute cannot replace the value of a failed result) · 失败结果只能重建 content;strip 对它不生效

10 · 失败结果的 content/meta 逐字复制 · dsh-tools/lib/index.js:3449-3455 · 返回自己的 { isError: true, error, content } 并省略 meta ⇒ meta 被丢弃

11 · 失败结果持久化时的约束 · dsh-session/lib/index.js:241-248(error 存在时要求 message.content[0].isError === true) · 由 createToolResultMessage 依据 result.isError 生成,天然满足

12 · 参数在工具体运行前就已落盘 · dsh-agent-loop/lib/index.js:586(appendToolCall)早于 :588(prepare/dispatch) · 所以"阻断"不能阻止参数入库,只能阻止执行(见第 6 节)

13 · tools/pre-execute 的 {kind:'deny'} · dsh-tools/lib/index.js:3116-3139 · block 规则:命中参数即拒绝,工具体不运行

14 · ctx.tools.guard(fn) · dsh-tools/lib/types/index.d.ts:620(单调守卫) · 未使用:瀑布的 deny 已经终止派发;理由见第 7 节

15 · tools/ptc-dispatch-log 瀑布 · 声明:dsh-tools/lib/types/index.d.ts:75;消费:dsh-tools/lib/index.js:1235-1251 · 兜底改写 run_code 子调用的日志副本 content

16 · 输出 schema 的受支持子集 · dsh-tools/lib/index.js:33-47(type/oneOf/properties/required/additionalProperties/items/enum/const + 注解)、:195-206 · 只有 enum/const 能固定一个字符串;也没有 minLength/maxLength(这是 maxChars 截断安全的前提)

17 · Cordis 的 Config 契约 · cordis/lib/index.js:955-960(runtime.Config["~standard"].validate(config))、:1630(Config: plugin.Config) · 导出的 Config 必须实现 Standard Schema

18 · patch 覆盖是整体替换 · dsh-app-boot/lib/index.js:70-105(target[key] = value) · 覆盖 config 时要把字段写全(第 4 节)

19 · 真空操作默认的约定 · dsh-spill-policy/lib/index.js:104(if (maxInlineBytes === void 0) return) · 未配置 rules 且未配置 strip ⇒ 一个监听器都不注册

20 · 工具输出 schema 是编译后的 · dsh-tools/lib/index.js:846-847(defineTool 调 valueSchemaSpecToJsonSchema)→ :594-603(属性级 required: true 变成对象级 required: [...] 数组) · 所以"哪个键是必需的"可以从 ctx.tools.get(name).output.schema.required 直接判定

21 · 缺 required 字段 ⇒ 值非法 · dsh-tools/lib/index.js:454-455(missing required property "…")、:466-467(additionalProperties: false 的多余键) · strip 拒绝删除 required 键的依据

22 · 非法 value ⇒ 整条调用变成终态错误 · dsh-tools/lib/index.js:3417-3418(validateJsonSchemaValue → throw new ToolOutputError)、:3226-3231(catch → toolErrorResult)、:2454-2458(INVALID_TOOL_OUTPUT) · 这就是"宁可响亮失败、也不静默产出非法值"的代价说明

23 · web_search 的 required 只有 3 个 · dsh-tool-web/lib/index.js:270-298:required 在编译后是 ['sources','truncated'],sources[].url 必需;content/title/snippet/publishedAt 可选;additionalProperties: false · stripDefaults 的两条规则据此选定(丢 sources.*.snippet 与 content)

24 · web_search 的两条投影都是纯函数 · dsh-tool-web/lib/index.js:62-79(formatSearchOutput,逐处 !== void 0 判断)、:103-124(projectSource + searchMetaFromValue) · 删掉可选字段后它们自然"看不见"该字段 ⇒ content 与 meta 同时干净

25 · ptc 日志副本只有 content 块 · dsh-tools/lib/index.js:1235-1242(shapeDispatchLog({… content: result.content})) · strip 在这条接缝上无从下手(没有 value)

26 · spill 策略只管纯文本结果 · dsh-spill-policy/lib/index.js:75-83(flattenPlainText:任何非 text 块 ⇒ undefined)、:156-172(tools/post-execute,prepend: true) · 它完全不碰 web_search 这类结构化结果;这正是 strip 要补的缺口

27 · spill 策略的落盘预览 · dsh-spill-policy/lib/index.js:88-101(头尾预览)、:114-150(存 spill 文件) · 全文仍以文件形式留在本地(ctx.spillStore),只是不进上下文

28 · 配置校验失败 = 加载期错误,不是运行期 · cordis/lib/index.js:955-961(resolveConfig 调 Config["~standard"].validate 并 throw new ValidationError)、:939-944(文案 = invalid config: + 每条 message (at path)) · 数值约束(maxScannedBytes / maxChars)因此放在 Config 里,报错点紧贴配置本身、且带字段路径

2.1 Config 的两条轨道:谁在生效,以及它们真正的差异

先说结论:用户实际拿到的是"兜底轨道"那一套。 插

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

嵌入徽章

两个徽章各用自己站的标识:左边是**标准**(DSHIO 发布),右边是**检测机构**(deepseekbase 检测)。每次展示都指向标准原文和检验报告。

DSHIO/T 10deepseekbase

Markdown(推荐,两个一起)

[![DSHIO/T 10](https://deepseekbase.com/badge/std.svg)](https://dshio.org/10/) [![deepseekbase](https://deepseekbase.com/badge/dsh-plugin-content-policy.svg)](https://deepseekbase.com/zh/plugins/dsh-plugin-content-policy/)

注意:这不是认证。DSHIO/T 32 认证规则尚未启用。

版本

npm 上共发布:2,最后更新 2026-09-12

链接

GitHub · Homepage · npm

常見問題

怎麼安裝 dsh-plugin-content-policy?
在 DSH 裡執行 dsh plugin --profile web add dsh-plugin-content-policy。如果你用的是 DSH Desktop,也可以在插件頁面直接貼套件名。
裝不上怎麼辦?
先確認 DSH 版本夠新(dsh --version),再看上面測試結果區的第一條錯誤。還不行就到 GitHub 倉庫提 issue。
怎麼卸載?
執行 dsh plugin --profile web remove dsh-plugin-content-policy。

同类插件

同類插件對比

插件下載沙箱判定體積
cc-safety-net111.9K✅ 通過2.1 MB
dsh-trust-check18.7K✅ 通過2.03 MB
dsh-perm-gate15.6K❌ 裝不上—
dsh-workspace-api-key9.1K✅ 通過0.2 MB
dsh-isolation-gate8.3K✅ 通過0.42 MB
dsh-auto-review6.4K✅ 通過16.91 MB
dsh-weiwen-law6.0K✅ 通過2.23 MB
@goodandready/dsh-time-machine5.5K✅ 通過13.73 MB