基于 ADR-103 的加密签名 Witness Manifest 维护指南:ruflo witness-curator 代理的实操与源码解析
2026/9/10 4:52:49 网站建设 项目流程

基于 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、分支、摘要以及每个修复的sha256markerVerified)。正是这份快照序列,让「某个现在已回归的修复,最后一次通过是在哪个 commit」成为可回答的问题。

ruflo 仓库的落地布局(由 scripts/regen-witness.mjs 定义):每个操作系统一份独立清单与历史,放入按 OS 划分的认知容器目录:

  • verification/linux/manifest.md.jsonverification/linux/history.jsonl
  • verification/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/cliv3/@claude-flow/plugin-agent-federation等候选根)探测@noble/ed25519,找不到时抛出带探测路径的错误,并支持用环境变量WITNESS_ED25519_ROOT显式指定安装根;
  • loadRvfNode()尝试加载@ruvector/rvf-node,成功则可用二进制 RVF 后端,否则回退到 JSONL。

也就是说,工具包在设计上是**项目无关(project-agnostic)**的:它不假设调用方一定是 ruflo,只要求你的项目里安装了@noble/ed25519npm 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已存在且未传--forceinit.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.jsonfixes数组中;若项目没有配置文件,也可直接写入regen.mjsNEW_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.jsonverification-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 仍在文件有变动但修复逻辑未丢(需人工确认)
regressedmarker 已不在文件中已登记修复丢失,真正的失败
missing文件不存在引用的文件缺失

6.2 退出码语义

  • 0:签名有效,全部通过或仅 drift;
  • 1:签名无效,或存在 regressed / missing(真实失败);
  • 2:参数错误、文件不存在,或前置条件未满足——典型场景是所有条目都 missing 且清单引用了dist/产物:这是「只检出了源码、没跑构建」,而非回归(对应 issue #1880 的修复策略,避免定时任务对每个 cron 重复报 issue)。此时脚本会提示先执行npm ci && npm run build再校验。

七、反模式清单(Anti-patterns)

witness-curator 在评审与日常维护中需要主动拦截以下做法:

  1. 手工编辑verification.md.json—— 任何手改都会破坏签名,必须重新 regen;
  2. marker 过于通用—— 例如'function''return',会在无关代码中误报命中,削弱回归检测价值;
  3. 清单与历史分开提交—— 二者必须原子移动(见第四节步骤 5);
  4. 登记时markerVerified=false的条目—— 修复尚未落盘就签发,等于记录一条「已知未通过」的修复;应先修复构建,再 regen。

八、在 ruflo 的 CI 与真实运行证据

8.1 CI 门禁

ruflo 的v3-ci.ymlwitness-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…F12G1…G7-*CAP-MCP-*(MCP 工具能力矩阵)、#1697#1927系列 issue 以及ADR-094ADR-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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询