关于 signed-audit-trails-recipe
这是一项讲解如何用 Cedar 策略限制 Claude Code 工具调用并生成签名收据的教程技能,适用于需要审计 Agent 行为的团队。内容涵盖受监管流程及 CI/CD 中的验证方法。
主要功能
- 01执行前进行 Cedar 策略检查
- 02生成 Ed25519 签名调用收据
- 03离线验证收据
- 04演示篡改检测
- 05提供 CI/CD 验证指南
适用场景
- 01记录受监管工作中的策略决策
- 02在 CI 中验证自动构建工具调用
- 03向协作方提供可验证的 Agent 活动记录
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshobson/ agents --skill signed-audit-trails-recipe安装后在 Claude Code 中输入/signed-audit-trails-recipe确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cedar-policy.mdci-cd.mdhook-wiring.mdreceipt-format.md详细介绍
Claude Code 工具调用的签名审计追踪
以 Cookbook 风格逐步演示如何为每次 Claude Code 工具调用生成经过加密签名的回执。这是一个教学技能。若要使用运行时实现,请安装 protect-mcp 插件。
它能为你带来什么
每次工具调用(Bash、Edit、Write、WebFetch)都会:
- 在执行前根据 Cedar 策略进行评估。如果策略拒绝该调用,工具就不会运行。
- 在执行后签名为 Ed25519 回执。回执采用 JCS 规范化,任何人都可以用公钥离线验证。
审计员、监管机构或交易对手之后可以验证每一份回执(步骤 5)。无需网络调用,无需查询供应商,无需信任运营方。
何时使用该模式
- 受监管环境(金融、医疗、关键基础设施),你需要 Agent 行为不可篡改的证据
- CI/CD 流水线,你想证明每个自动化构建步骤都通过了策略门禁
- 多方协作,交易对手希望在不信任你的运营方的情况下验证你的 Agent 行为
- 合规场景(欧盟 AI 法案第 12 条、Agent 构建软件的 SLSA 来源证明),标准日志记录不足以满足要求
步骤 1:安装钩子配置
使用 /plugin install protect-mcp 安装 protect-mcp 插件。它的钩子会在每次工具调用前运行 evaluate.sh,在调用后运行 sign.sh。两个脚本都从 stdin 读取钩子事件,因为 Claude Code 不设置 TOOL_NAME 或 TOOL_INPUT 变量。钩子配置以及每个脚本向 protect-mcp 传递的内容,请参见
references/hook-wiring.md。
protect-mcp 0.7.4 不会创建签名密钥,而没有密钥时回执就是未签名的。请创建一次 ./protect-mcp.key。该命令永远不会替换已有的密钥:
if [ ! -e ./protect-mcp.key ]; then
d=$(mktemp -d) && npx [email protected] init --dir "$d" && mv "$d/keys/gateway.json" ./protect-mcp.key
fi
把该文件中的 publicKey 值交给审计员。不要提交该文件,因为它还保存着私钥。
将私钥和回执目录添加到 .gitignore:
echo "/protect-mcp.key" >> .gitignore
echo "/receipts/" >> .gitignore
步骤 2:编写 Cedar 策略
根据 references/cedar-policy.md 中的示例创建 ./protect.cedar。它允许只读工具和一小组 Bash 命令,拒绝 shell 链式调用和破坏性命令,并将写入限制在项目内,且拒绝带 .. 段的路径。
步骤 3:正常使用 Claude Code
启动 Claude Code。每次工具调用都会经过这两个钩子:
You: Please read the README and summarize it.
Claude: I will read README.md.
[PreToolUse: Read ./README.md -> allow]
[Tool: Read executes]
[PostToolUse: receipt rcpt-a8f3c9d2 signed to ./receipts/]
... summary of README ...
一个包含 20 次工具调用的会话会向 ./receipts/receipts.jsonl 追加 20 份回执。
步骤 4:查看回执
protect-mcp 0.7.4 会将每份回执作为一行追加到
./receipts/receipts.jsonl。打印最新的一条:
tail -n 1 ./receipts/receipts.jsonl | python3 -m json.tool
该回执是一个签名的 v2 信封,其中标明工具名称,且不包含公钥。示例和已签名字段请参见
references/receipt-format.md。
步骤 5:验证回执
将 ./protect-mcp.key 中的 publicKey 值传给验证器:
PUB=$(node -p 'JSON.parse(require("fs").readFileSync("./protect-mcp.key")).publicKey')
npx @veritasacta/[email protected] --replay-chain ./receipts/receipts.jsonl --key "$PUB"
退出码:
| 代码 | 含义 |
|---|---|
0 | 每份回执都验证通过 |
1 | 某份回执验证失败(被篡改、密钥错误或行格式错误) |
2 | 无法读取回执文件 |
步骤 6:演示篡改检测
将最新回执的 decision 从 allow 改为 deny:
python3 -c "
import json
path = './receipts/receipts.jsonl'
lines = open(path).read().splitlines()
r = json.loads(lines[-1])
r['payload']['decision'] = 'deny'
lines[-1] = json.dumps(r)
open(path, 'w').write('\n'.join(lines) + '\n')
"
npx @veritasacta/[email protected] --replay-chain ./receipts/receipts.jsonl --key "$PUB"
验证器会以退出码 1 退出,并报告哪一行验证失败。Ed25519 签名不再与被篡改载荷的 JCS 规范化字节匹配。
恢复该字段后,验证会再次通过。
加密机制的工作原理
两个不变量确保收据可在离线状态下由任何符合规范的实现验证:
- 签名前执行 JCS 规范化(RFC 8785)。按 UTF-16 代码单元排序键、尽可能减少空白、不规范化字符串。对于相同的收据内容,两个独立实现会生成字节完全相同的签名载荷。
- 对规范化后的字节执行 Ed25519 签名(RFC 8032)。 确定性、固定大小、不依赖随机数。
protect-mcp 0.7.4 收据不包含指向上一条收据的链接,因此无法检测收据是否被删除。
正式的线路格式请参阅 draft-farley-acta-signed-receipts。
跨实现互操作
目前,收据格式有四种独立实现:
| 实现 | 语言 | 用途 |
|---|---|---|
| protect-mcp | TypeScript | Claude Code、Cursor、MCP 主机 |
| protect-mcp-adk | Python | Google Agent Development Kit |
| sb-runtime | Rust | 操作系统级沙箱(Landlock + seccomp) |
| APS governance hook | Python | CrewAI、LangChain |
由其中任何一种实现生成的收据,都可以通过
@veritasacta/verify 验证。
审计员无需信任操作者选择的工具:格式本身就是约定。
CI/CD 集成
在 CI 中验证收据,以便被篡改的收据能导致构建失败。
references/ci-cd.md 提供了一个 GitHub Actions 工作流,会在向默认分支推送时运行。它从仅限分支的环境中安装签名密钥、运行 Agent、验证收据并上传收据。它不会在拉取请求上运行,因为那会将密钥交给未经审核的代码。
与 Agent 构建软件的 SLSA 来源证明组合使用
当 Claude Code 构建并发布软件时(将 npm install、
npm build、npm publish 作为工具调用运行),收据链就是逐步构建日志。SLSA Provenance v1 为此提供了扩展点:byproducts 字段可以在构建证明旁引用收据链。
agent-commit build type 使用 ResourceDescriptor 结构说明了这一模式:
{
"name": "decision-receipts",
"digest": { "sha256": "..." },
"uri": "oci://registry/org/build-xyz/receipts:sha256-...",
"annotations": {
"predicateType": "https://veritasacta.com/attestation/decision-receipt/v0.1",
"signerRole": "supervisor-hook"
}
}
SLSA 来源证明由构建器身份签名;收据证明由 supervisor-hook 身份签名。两个信任域通过副产物层交叉引用。有关组合方式的讨论,请参阅 slsa-framework/slsa#1594。
常见问题
私钥被提交到版本控制中。 生成的 ./protect-mcp.key 不得提交。上述示例会将其添加到 .gitignore 中。如果不慎提交了密钥,请立即轮换。将密钥和
./receipts/receipts.jsonl 移至存档,然后再次运行步骤 1 中的命令。
使用旧公钥验证存档的收据。
通过 stdin 传递钩子载荷。 Claude Code 不会设置 $TOOL_NAME 或 $TOOL_INPUT 变量。钩子命令如果传入 --tool "$TOOL_NAME",会发送空工具名称,因此策略会拒绝每次调用。应像插件脚本那样从 stdin 读取载荷。
CI 中的收据目录。 如果 Claude Code 在 CI 中运行,请在作业结束时将收据作为构件上传,否则作业结束时收据就会丢失。
缺少策略。 如果 ./protect.cedar 不存在,evaluate.sh 会向 stderr 打印警告并允许调用。直到你在步骤 2 中创建策略之前,都不会对任何调用进行限制。
此 Marketplace 中的相关项目
protect-mcp— 运行时钩子实现 (在生产环境中使用此插件)review-agent-governance— 在执行审查界面操作前要求人工批准;可与 protect-mcp 组合使用
参考
draft-farley-acta-signed-receipts— IETF 草案,回执线格式- RFC 8032 — Ed25519
- RFC 8785 — JCS
- Cedar 策略语言
- npm 上的 protect-mcp
- npm 上的 @veritasacta/verify
- in-toto/attestation#549 — Decision Receipt 谓词提案
- agent-commit 构建类型 — 面向 Agent 生成提交的 SLSA 来源
- Microsoft Agent Governance Toolkit(
examples/protect-mcp-governed/) - AWS Cedar for Agents