Witness 是一个加密修复回归跟踪工具包。它允许你在每次发布时附带一份已签名清单,清单中列出代码库中所有已记录的修复,以及对应的 sha256 和标记子串。任何拥有相同 git 提交的人都可以重新推导公钥并验证签名,而无需提交私钥。
时间历史(JSONL)跟踪修复群体如何跨版本演变——因此当出现回归时,你可以精确定位引入它的提交,而不仅仅是知道“现在坏了”。
该技能有两种使用方式:
在 ruflo 内部——由 ruflo 自己的 CI 用于门禁发布(参见 .github/workflows/v3-ci.yml 中的 witness-verify 任务)。
在你自己的项目中——将 plugins/ruflo-core/scripts/witness/ 复制到你的仓库,运行 init.mjs,在 witness-fixes.json 中注册你的修复,并在发布流水线中调用 regen.mjs。
快速开始(任意项目)
一次性引导——创建 verification.md.json、
verification-history.jsonl 和 witness-fixes.json 模板
node plugins/ruflo-core/scripts/witness/init.mjs --root .
编辑 witness-fixes.json:为每个修复添加 { id, desc, file, marker }。
“marker” 是一个独特的子串,当修复存在时它必须出现在 file 中。
如果有人回退了修复,标记消失,verify 会将其报告为 regressed。
重新生成清单(签名需要 @noble/ed25519)
npm i @noble/ed25519
node plugins/ruflo-core/scripts/witness/regen.mjs
--manifest verification.md.json
--history verification-history.jsonl
--fixes witness-fixes.json
验证标记存在于当前树中
node plugins/ruflo-core/scripts/witness/verify.mjs
--manifest verification.md.json
或者在干净克隆中验证清单并检查源标记。
生成的 dist/ 条目会被明确报告为跳过。
node plugins/ruflo-core/scripts/witness/verify.mjs
--manifest verification.md.json --source-only
对于 CI 哈希绊线,当文件更改但标记保留时也失败。
node plugins/ruflo-core/scripts/witness/verify.mjs
--manifest verification.md.json --source-only --strict
不使用 --strict 时,保留标记的 SHA 漂移会被报告但退出码为 0。 --strict 使该漂移退出码为 1,而不改变签名或缺失文件检查。
时间查询(ADR-103)
最新快照与上一个对比
node plugins/ruflo-core/scripts/witness/history.mjs
--history verification-history.jsonl summary
对于每个当前回归的修复,找到引入它的提交
node plugins/ruflo-core/scripts/witness/history.mjs
--history verification-history.jsonl regressions
特定修复的状态时间线
node plugins/ruflo-core/scripts/witness/history.mjs
--history verification-history.jsonl timeline --id F1
供 CI 使用的机器可读输出
node plugins/ruflo-core/scripts/witness/history.mjs
--history verification-history.jsonl summary --json
如果自上次快照以来有任何修复新出现回归,summary 会以非零退出码退出——可将其作为软性预合并门禁放入 CI。
反模式
手动编辑 verification.md.json——始终通过 regen.mjs 重新生成,否则签名会损坏。
标记过于通用(如 'function'、'import')——选择足够独特的标记,以免 grep 对无关代码产生误报。
跳过历史追加——不使用 --history,你将失去二分定位回归引入时间的能力。
只提交其中一个——verification.md.json 和 verification-history.jsonl 应属于同一次提交;JSONL 是让未来的你验证已签名清单是序列中最新版本的关键。
文件
scripts/witness/lib.mjs——共享的重新生成/历史逻辑。
scripts/witness/regen.mjs——CLI:签名并追加历史。
scripts/witness/history.mjs——CLI:查询时间日志。
scripts/witness/init.mjs——CLI:引导到新项目。
scripts/witness/verify.mjs——CLI:验证签名和标记。
在 ruflo 的 CI 中
v3-ci.yml 中的 witness-verify 任务在行为冒烟测试之后、发布之前运行。失败模式:
失败 | 原因
signatureValid: no | 清单被手动编辑;重新运行 regen
regressed: > 0 | 一个已记录的修复自签发以来丢失了标记
missing: > 0 | 引用的 dist 文件不再存在;重新构建或移除该条目
scope: source-only | 签名和源标记已检查;生成的条目被有意跳过