基于 ADR-103 的加密签名 Witness Manifest 维护指南:ruflo witness-curator 代理的实操与源码解析
【免费下载链接】ruflo🌊 The original agent meta-harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, RAG integration, and native Claude Code / Codex / Hermes and many more Integrated项目地址: https://gitcode.com/GitHub_Trending/cl/ruflo
导读
witness-curator 是 ruflo 项目中负责维护「加密签名修复清单(witness manifest)」的专职 Agent(定义于 plugins/ruflo-core/agents/witness-curator.md)。它依据 ADR-103 设计:每个已发布修复(fix)都以「SHA-256 哈希 + Ed25519 签名」的形式被记录,任何一次回归都能通过 append-only 时间历史精确追溯到引入它的那次 commit。读完本文,你将掌握如何在 ruflo 仓库(或任意引入该工具包的项目)中新增修复声明、签发并校验签名清单、查询回归时间线,以及如何把同样的门禁接入自己的 CI。
一、系统工作原理:什么是「Witness Manifest」
witness-curator 维护的核心产物是verification.md.json(在 ruflo 仓库中实际按操作系统分目录存放,见下文)。它按修复逐条列出:
{ "id": "F1", "desc": "hooks_metrics persistence", "file": "v3/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js", "sha256": "7568218d06d692ab82c5c7866ef37ae18bf621a228c175e01bc400a27fe3f2e9", "marker": "getIntelligenceStatsFromMemory", "markerVerified": true }即每个条目包含{ id, desc, file, sha256, marker, markerVerified }六要素:
| 字段 | 含义 |
|---|---|
id | 修复的唯一标识,可以是 issue 号(如#1867)、ADR 编号(如ADR-111)或内部编号(如F1) |
desc | 修复内容的一句话描述 |
file | 包含该修复的文件路径(仓库根目录相对路径) |
sha256 | 该文件当前内容的 SHA-256 摘要,用于检测文件是否被改动 |
marker | 证明修复确实存在的「特征子串」(distinctive marker substring) |
markerVerified | 签发时 marker 是否在文件中被找到 |
1.1 无私钥的确定性签名
整个 manifest 先做一次 SHA-256 哈希,再用 Ed25519 签名。签名密钥并非随机生成、也不作为私钥提交到仓库,而是从 git commit 派生:
seed = sha256(gitCommit + ':ruflo-witness/v1') publicKey = Ed25519.getPublicKey(seed) signature = Ed25519.sign(manifestHash, seed)这段逻辑在 plugins/ruflo-core/scripts/witness/lib.mjs 中实现。这带来一个关键特性:任何人只要知道 git commit,就能复现同一把公钥并验证签名,因此「有人偷偷改过清单」立刻能被发现——签名对不上即说明清单被手工编辑过。
1.2 时间历史:回归二分定位的基础
verification-history.jsonl是 append-only 日志,每次重新签发(regen)都会追加一条该时刻的清单快照(commit、issuedAt、分支、摘要以及每个修复的sha256与markerVerified)。正是这份快照序列,让「某个现在已回归的修复,最后一次通过是在哪个 commit」成为可回答的问题。
ruflo 仓库的落地布局(由 scripts/regen-witness.mjs 定义):每个操作系统一份独立清单与历史,放入按 OS 划分的认知容器目录:
verification/linux/manifest.md.json与verification/linux/history.jsonlverification/macos/…、verification/windows/…
这与lib.mjs中 osDir() 的映射(darwin→macos、win32→windows、其余→linux)一致,CI 上各平台 runner 各自签发自己的清单,共享的修复定义则放在verification/witness-fixes.json。
二、工具包全景:五个脚本的分工
工具包位于plugins/ruflo-core/scripts/witness/,全部为无依赖的 Node ESM 脚本,核心逻辑集中在可复用的lib.mjs:
| 脚本 | 职责 |
|---|---|
| init.mjs | 在任意仓库引导(bootstrap):生成空清单、空历史与witness-fixes.json模板 |
| regen.mjs | 合并旧条目与新增修复,刷新哈希/标记,签名并写入清单、追加历史 |
| history.mjs | 查询时间日志:summary、regressions、timeline、list 四个子命令 |
| verify.mjs | 校验签名 + 对照真实文件树核对每个 marker 与哈希 |
| lib.mjs | 共享纯函数(哈希、签名、历史解析、回归定位),可被其他脚本 import |
另有 perf.mjs 将性能验证(安装时长、CLI 启动、内存往返、witness 校验耗时)以同样的 JSONL 基线模式记录到verification/<os>/performance.jsonl,让「性能回归」也能像 marker 消失一样被捕获。
2.1 lib.mjs 的依赖解析策略
lib.mjs的两个惰性加载函数值得注意:
loadEd25519()会从调用方项目(含 pnpm 隔离布局下的v3/@claude-flow/cli、v3/@claude-flow/plugin-agent-federation等候选根)探测@noble/ed25519,找不到时抛出带探测路径的错误,并支持用环境变量WITNESS_ED25519_ROOT显式指定安装根;loadRvfNode()尝试加载@ruvector/rvf-node,成功则可用二进制 RVF 后端,否则回退到 JSONL。
也就是说,工具包在设计上是**项目无关(project-agnostic)**的:它不假设调用方一定是 ruflo,只要求你的项目里安装了@noble/ed25519(npm i @noble/ed25519)即可。
三、实战一:引导一个新仓库
在任意 git 仓库根目录执行:
node plugins/ruflo-core/scripts/witness/init.mjs [--root <path>]它会在目标根目录创建三个文件:
verification.md.json—— 空清单(schema 固定为ruflo-witness/v1,修复列表为空);verification-history.jsonl—— 空历史;witness-fixes.json—— 修复登记模板,内置一条占位示例:
{ "fixes": [ { "id": "EXAMPLE-1", "desc": "Replace this with your fix description", "file": "src/path/to/fixed-file.ts", "marker": "distinctive substring proving the fix is in the file" } ] }注意:若verification.md.json已存在且未传--force,init.mjs会拒绝覆盖(init.mjs)。引导完成后即可编辑witness-fixes.json并执行 regen。
四、实战二:发布新修复(Workflow: adding a fix)
当一条修复要随版本发布时,按以下五步操作:
步骤 1 —— 挑选特征 marker。找到包含修复的文件,选定一个独特且可证明修复存在的子串。反例是'function'这类通用词(会在无关代码中产生误报);正面范例可参考仓库真实的 verification/witness-fixes.json:
- 唯一的错误消息:
"protocolVersion = '2025-11-25'"(MCP 服务端协议版本修复,#1874-mcp); - 来自 diff 的特定模式:
"ctx.flags.file || ctx.args[0]"(CLI 标志优先级修复,#1859); - 引用 issue 的注释:
"#1927: Claude Code encodes"(Windows 路径编码修复,#1927)。
步骤 2 —— 登记条目。把{ id, desc, file, marker }追加到项目的witness-fixes.json的fixes数组中;若项目没有配置文件,也可直接写入regen.mjs的NEW_FIXES数组。
步骤 3 —— 先试跑。务必先以--dry-run确认所有 marker 都能在真实文件中命中:
node plugins/ruflo-core/scripts/witness/regen.mjs \ --manifest verification.md.json \ --history verification-history.jsonl \ --fixes witness-fixes.json \ --dry-run输出中应看到verified: N/N(全部通过)。ruflo 内部可简写为node scripts/regen-witness.mjs --dry-run。
步骤 4 —— 正式签发。去掉--dry-run重新执行,脚本将:刷新所有旧条目的哈希与标记 → 合并新条目 → 取当前 HEAD 派生签名 → 写清单 → 追加历史快照。输出形如:
gitCommit: b68ad4ccbad3… branch: fix/2721-plugin-hooks-windows issuedAt: 2026-07-18T23:40:26.482Z total fixes: 117 (was 116) verified: 117 missing: 0 new entries: #2721步骤 5 —— 原子提交。verification.md.json、verification-history.jsonl以及更新过的witness-fixes.json必须一起提交——它们是一个整体,分开提交会让历史快照与清单失配。
regen.mjs的完整参数表如下(regen.mjs):
| 参数 | 说明 |
|---|---|
--manifest <path> | 必填。签名清单输出路径 |
--history <path> | JSONL 历史文件,传则追加快照(省略则跳过) |
--fixes <path> | 新增修复 JSON,格式{ "fixes": [{ "id","desc","file","marker" }] } |
--releases <path> | 可选,{ pkg: version }映射,写入清单的releases字段 |
--root <path> | 项目根目录(默认当前目录) |
--dry-run | 只打印摘要、不落盘 |
五、实战三:调查一个回归(Workflow: investigating a regression)
当 CI 报某个修复为regressed(marker 已从文件中消失)时:
步骤 1 —— 查询回归窗口。运行 history 的regressions子命令:
node plugins/ruflo-core/scripts/witness/history.mjs \ --history verification-history.jsonl regressions对每个当前处于 regressed 状态的修复,输出lastPassCommit(最后一次通过的 commit)与regressedAtCommit(首次失败的 commit)。其底层算法在 lib.mjs 的 findRegressionIntroductions():从最新快照倒序回走,找到最近的markerVerified=true快照即 lastPass,其后的第一个快照即引入回归的 commit。
步骤 2 —— 定位改动。用 git 列出回归窗口内动过该文件的提交:
git log lastPassCommit..regressedAtCommit -- <file>步骤 3 —— 修复。检查 diff 中 marker 是否被删除;恢复被误删的 marker,或按新代码形态更新 marker,然后重新 regen。
history.mjs的四个子命令(history.mjs):
| 子命令 | 作用 |
|---|---|
summary | 最新快照相对上一份的状态迁移(newlyRegressed / newlyPassing / added / removed);有新增回归时退出码为 1 |
regressions | 列出当前每个回归修复的 lastPassCommit 与 regressedAtCommit |
timeline --id <fixId> | 单个修复跨全部快照的状态时间线(pass / regressed / absent) |
list | 列出所有快照(commit、issuedAt、摘要) |
所有子命令均支持--json输出机器可读结果。
六、实战四:校验签名与实时标记(verify.mjs)
verify.mjs做两件事:验签(清单是否被篡改)与对照真实文件树核对每个条目(哈希是否漂移、marker 是否还在):
node plugins/ruflo-core/scripts/witness/verify.mjs --manifest verification.md.json [--root <path>] [--source-only] [--json]--source-only:只校验源码条目,跳过/dist/等生成产物(适合未构建的检出);--json:输出结构化结果。
验签逻辑见 verify.mjs 的 verifySignature():重算清单哈希比对manifestHash、用 commit 重新派生种子并还原公钥比对publicKey、最后用 Node 内置node:crypto的 RFC 8410 DER 包装完成 Ed25519 验签——无需额外安装签名库。
6.1 每个文件的状态机
对清单中每个条目,脚本会得到四态之一:
| 状态 | 判定条件 | 含义 |
|---|---|---|
pass | 哈希一致 且 marker 存在 | 文件未被改动且修复仍在 |
drift | 哈希不一致 但 marker 仍在 | 文件有变动但修复逻辑未丢(需人工确认) |
regressed | marker 已不在文件中 | 已登记修复丢失,真正的失败 |
missing | 文件不存在 | 引用的文件缺失 |
6.2 退出码语义
0:签名有效,全部通过或仅 drift;1:签名无效,或存在 regressed / missing(真实失败);2:参数错误、文件不存在,或前置条件未满足——典型场景是所有条目都 missing 且清单引用了dist/产物:这是「只检出了源码、没跑构建」,而非回归(对应 issue #1880 的修复策略,避免定时任务对每个 cron 重复报 issue)。此时脚本会提示先执行npm ci && npm run build再校验。
七、反模式清单(Anti-patterns)
witness-curator 在评审与日常维护中需要主动拦截以下做法:
- 手工编辑
verification.md.json—— 任何手改都会破坏签名,必须重新 regen; - marker 过于通用—— 例如
'function'、'return',会在无关代码中误报命中,削弱回归检测价值; - 清单与历史分开提交—— 二者必须原子移动(见第四节步骤 5);
- 登记时
markerVerified=false的条目—— 修复尚未落盘就签发,等于记录一条「已知未通过」的修复;应先修复构建,再 regen。
八、在 ruflo 的 CI 与真实运行证据
8.1 CI 门禁
ruflo 的v3-ci.yml中witness-verify作业会在publish之前阻塞发布,触发条件即文档所述三类失败:
- 签名无效(有人手改过清单);
- 任一修复
regressed > 0(已登记修复丢失 marker); - 任一修复
missing > 0(引用的 dist 文件不存在)。
此外,多个审计脚本(如 scripts/audit-cli-mcp-tools.mjs、scripts/audit-plugin-packages.mjs、scripts/audit-hook-commands.mjs)也被列入witness-verify的依赖(needs[]),形成「发布前全链路门禁」。
8.2 仓库中的真实运行证据
仓库的 verification/linux/manifest.md.json 记录了一次签发的实际形态:totalFixes: 117, verified: 117, missing: 0,所有条目markerVerified: true。而 verification/linux/history.jsonl 展示了历史快照的演进——从 2026-05-09 的 81 条修复增长到 117 条,期间修复 ID 覆盖F1…F12、G1…G7-*、CAP-MCP-*(MCP 工具能力矩阵)、#1697…#1927系列 issue 以及ADR-094…ADR-129-P4系列 ADR,可见 witness 体系被用于为 MCP 工具面、联邦插件、CLI 修复等各类改动做发布见证。
历史中还真实出现过markerVerified: false的中间快照(如 ADR-104-transport、ADR-107-tls-pinning、ADR-104-stream-mux 在某次 macos 快照中),随后下一份快照全部转为true——这正是「发现问题 → 修复 → 重签」闭环的实证:回归会被历史如实记录,而无需删除或改写过去的快照,append-only 的不可变性得以保持。
8.3 对采用者的迁移路径
对于想在自有项目引入该门禁的团队:init.mjs引导后,按第四节流程登记首批修复、执行 regen 产出首份签名清单;随后在 CI 中仿照witness-verify增加一个作业,在发布前运行verify.mjs --manifest verification.md.json,以退出码 0 作为发布条件,即可获得与 ruflo 相同的「签名 + marker + 时间历史」三级保障。
总结
ruflo 的 witness-curator 系统把「修复声明」从一次性补丁升级为可审计、可签名、可二分定位的工程资产:SHA-256 哈希绑定文件内容、Ed25519 确定性签名绑定 git commit、append-only JSONL 历史绑定时间。结合 lib.mjs、regen.mjs、verify.mjs、history.mjs 四个核心脚本与 verification/witness-fixes.json 中的真实条目,你可以快速理解其原理,并在自己的项目中复刻这套回归门禁——无论是「这个修复还在吗」的实时校验,还是「它什么时候坏的」的历史追溯,都能在一条命令内得到答案。
【免费下载链接】ruflo🌊 The original agent meta-harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, RAG integration, and native Claude Code / Codex / Hermes and many more Integrated项目地址: https://gitcode.com/GitHub_Trending/cl/ruflo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考