octopus-evidence
v0.2.0
Published
The shared Evidence primitive for the Octopus stack — canonical, hashable, tamper-evident evidence that flows between repos.
Maintainers
Readme
English | 简体中文
Evidence
Octopus 栈共享的 Evidence(证据)原语 —— 一个规范 (canonical)、可哈希、 防篡改的支撑单元,在各仓库之间流动。
Octopus Core 的一部分 —— 受治理 AI 的开源基础设施栈。 这是其它仓库共享的根原语:Scout 采集证据 · Observe 规范化它 · Blackboard 为它排时间线 · Runtime 基于它审批 · Replay 重建它 · Experience 为它建图 · Inspect 校验它。
Evidence → hash → chain (timeline) → verify为什么
治理需要证据。合规需要证据。审计需要证据。所以 Evidence 是根 —— 比它们都低 一层。一个 AI 系统的每一项可辩护主张(“这已被批准”“这个测试通过了”“这个决定有其 理由”)都落在一个证据单元上,而该单元是规范的(两个相等的事实哈希相等)、 可归属的(谁/什么/何时),以及防篡改的(任何事后编辑都可被察觉)。本包恰好拥有 这个单元以及它背后的密码学 —— 且仅此而已:它不派生任何东西、不编排任何东西、 不执行任何东西。
它同时消除了真实的重复:octopus-observe 和 octopus-replay 各自独立地重新发明了
规范 JSON + SHA-256 + 哈希链。这些东西在这里存在一次,于是每个仓库都对“相等”和
“可验证”的含义达成一致。
安装
npm install octopus-evidenceNode ≥ 22。零运行时依赖(仅用 Node 内置能力)。Apache-2.0。
Evidence 信封 (envelope)
import { createEvidence, verifyEvidence } from "octopus-evidence";
const ev = createEvidence({
kind: "test",
subject: [{ type: "pull_request", id: "octopus-evidence#1" }],
actor: { type: "agent", id: "ci" },
content: { passed: true, cases: 42 },
provenance: { source: "ci", method: "test-run", at: "2026-07-03T00:00:00.000Z" },
});
ev.id; // "ev_<sha256…>" —— 确定性:相同输入 → 相同 id
ev.integrity; // 覆盖**整条证据**的哈希;可察觉任何事后编辑
verifyEvidence(ev); // true —— id 与 integrity 都从各字段重新算出createEvidence 是幂等的(相同输入总是产出相同的证据),且是
内容寻址的(不同的 content、actor 或 provenance → 不同的 id)。若任何字段被
编辑,verifyEvidence 会返回 false —— 且它绝不抛出,即便面对恶意/畸形的
存储 content。
若要防止篡改(而不仅是察觉篡改)的完整性,用 HMAC 为它加密钥。该密钥覆盖 整条证据 —— content、actor、subject、kind 与 provenance —— 因此没有密钥的 攻击者也无法伪造谁 / 何处 / 何时,而不仅仅是 payload:
const sealed = createEvidence(input, { integritySecret: process.env.EVIDENCE_KEY });
verifyEvidence(sealed, process.env.EVIDENCE_KEY); // 用同一密钥校验Evidence 时间线(防篡改链)
把一串证据提交进一条只追加 (append-only) 的哈希链 —— 这是审计轨迹或 Blackboard 时间线所构建于其上的原语。对更早的链接做任何编辑、插入、删除或重排,都会破坏校验。
import { buildChain, verifyChain, nextLink, GENESIS_HASH } from "octopus-evidence";
const chain = buildChain(events.map((e) => e.id)); // 链接每个 evidence id
verifyChain(chain); // { ok: true } | { ok: false, brokenAt, reason }
// 或增量追加(纯的 —— 返回下一个链接,由你存储):
const link = nextLink(chain, nextEvidence.id);向 buildChain / nextLink 传入一个 secret(并用 verifyChain({ secret })),
即可得到一条带密钥的 HMAC 链 —— 没有该密钥便无法伪造新链接。
一条裸链只证明它自身是一个自洽的前缀 —— 因此尾部截断(回滚最新的条目) 无法自我察觉。把头哈希与长度带外记录下来并传入,即可抓到它:
import { chainHead } from "octopus-evidence";
verifyChain(chain, { expectedHead: chainHead(chain), expectedLength: chain.length });规范哈希(共享基础)
两者之下都是同一个原语:
import { stableStringify, canonicalHash, canonicalEqual } from "octopus-evidence";
canonicalEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // true —— 键序无关
canonicalHash({ a: 1, b: 2 }) === canonicalHash({ b: 2, a: 1 }); // truestableStringify 拒绝任何 JSON 无法忠实往返的内容(非有限数值、undefined、
环 (cycle)),因此一次“成功”的哈希绝不掩盖静默的数据丢失。
CLI —— 无需信任存储即可验证
把一份 JSON 导出和这个二进制文件交给审计人员,他们就能独立地重新验证每一个 id、 完整性哈希与链接 —— 无需编写代码,也无需信任生成它的那个存储。零运行时依赖 (仅使用 Node 内置模块)。
npx octopus-evidence verify export.json文件可以包含单个 Evidence、Evidence 数组、裸的 ChainLink 数组,或一个带有
evidence 和/或 chain 数组的对象 —— 形状会被自动检测。
Evidence: 3/3 verified, 0 failed
Chain: ok (3 links)
Result: VALID如果任何内容被改动,验证在重算时就会出现不匹配,工具会如实指出 —— 被篡改的载荷、 错误或缺失的密钥,或被破坏 / 重排的链:
Evidence: 2/3 verified, 1 failed
✗ [1] ev_9f… — integrity/id mismatch (tampered or wrong secret)
Chain: BROKEN at link 2 — previousHash mismatch at link 2 (chain broken or reordered)
Result: INVALID对于用 HMAC 密封的证据或链,用 --secret 传入相同的密钥;若需要机器可读的报告
(例如在 CI 中),传入 --format json:
octopus-evidence verify export.json --secret "$EVIDENCE_KEY"
octopus-evidence verify export.json --format json退出码:0 全部有效,1 有任意证据/链无效,2 用法 / IO / 解析错误。
运行 octopus-evidence --help 查看完整参考。
边界 (Boundaries)
Evidence 是一个原语,而非一个系统。它没有存储、没有查询、没有网络、没有派生。 存储证据、跨 agent 为它排时间线、派生因果图,或基于它对动作设卡 (gate),都是其它 仓库的职责 —— 它们依赖这个形状;这个形状不依赖任何东西。
许可证
Apache-2.0 © Octoryn。
