全部文章

阅读约 5 分钟

在 CI/CD 与脚本中使用 CardanoWall CLI

用脚本运行存在性证明:cardanowall CLI 把 JSON 输出到 stdout、把诊断信息输出到 stderr,给你稳定的验证退出码,安全地接收密钥,并能通过任意 Label 309 网关发布。

当存在性证明需要在脚本里运行,而不是在浏览器中操作时,就该用 cardanowall CLI。它是为自动化而生的:加上 --json 就能在 stdout 上拿到机器可读的数据,把 stderr 当作诊断信息,再依据一小组稳定的退出码做分支判断。这就足以把它接入 CI/CD、发布流水线、合规作业和内部审计工具链。

CLI 无需 CardanoWall 账户即可验证记录,能通过任意 Label 309 网关发布证明,在本地为记录签名,从种子派生身份,构建并校验 Merkle 证明,还能读取封存收件箱。它是任何人都能运行的同一款开源工具,以二进制名 cardanowall 发布在 crates.io 上——没有 cw 别名——源码位于 github.com/cardanowall

为什么用 CLI 而不是网站?

网站是为人设计的。自动化需要的是另一套东西:

  • 可以无人值守运行的确定性命令;
  • 机器可读的输出;
  • 可供分支判断的稳定退出码;
  • 不必驱动浏览器会话;
  • 用显式的网关配置,而非已登录的账户;
  • 密钥从 stdin、文件或环境变量读入——绝不在提示符里手敲;
  • 可与作业一同归档的日志。

这正是 CLI 给你的,而且它让证明贴近真正产出证据的那套系统。

如何在脚本里验证一份证明?

验证是最容易自动化的命令,也是最值得到处运行的那一个:

cardanowall verify <tx-hash> --json

验证既不需要 CardanoWall 账户,也不需要网关运营方。它从公开的 Cardano 浏览器(兼容 Koios 或 Blockfrost)读取交易元数据,可选地从公开的 Arweave 或 IPFS 网关获取内容,校验记录,并核验所有签名。这正是该标准的要义:一份你验证过一次的证明,对任何人都保持独立可验证,无需信任发布者、其域名或其服务器。

若要更精细地控制,可指向你自己的数据源并设定一个确认深度:

cardanowall verify <tx-hash> \
  --cardano-gateway https://api.koios.rest/api/v1 \
  --threshold 20 \
  --json

数据走 stdout,诊断信息走 stderr,因此命令组合保持干净:

if cardanowall verify "$TX_HASH" --json > verify-report.json; then
  echo "proof verified"
else
  code=$?
  echo "verification did not pass, exit code: $code" >&2
fi

想更深入了解验证方究竟检查了什么,参见如何验证一条 Label 309 记录

这些退出码是什么意思?

依据退出码做分支判断,而不是去解析给人看的文字——退出码已经告诉你结果属于哪一类:

退出码含义
0有效 / 成功
1完整性类失败(某项密码学或结构检查未通过)
2网络类失败或无法验证的结果(获取或传输出错)
3待定——通常是确认数不足
4CLI 输入错误(参数有误或缺少必需输入)

verify 而言,退出码 03 直接对应验证方的判定——分别是 validfailedunverifiablepending——因此无论你读退出码还是读 --json 报告,契约都是一致的。

这给自动化一套清晰的策略:

  • 0:继续。
  • 1:作业失败——证明或内容检查未通过。
  • 2:重试,或将本次运行标记为不确定。
  • 3:等待更多确认后再重试。
  • 4:修正脚本或其输入。

在发布工作流中,不要把 pending 当作成功。一份待定的证明日后可能会落定,但它此刻尚未达到最终性。

如何在自动化中发布一份证明?

发布需要一个网关,因为它会提交一笔真实的 Cardano 交易,并从你的网关余额中扣款,以支付交易费用和任何 Arweave 存储费。(至于发布为何会产生费用,参见发布为何要收费。)

对一个文件计算哈希并锚定:

cardanowall submit \
  --file ./release-manifest.json \
  --base-url https://your-gateway.example \
  --api-key "$CARDANOWALL_API_KEY" \
  --json

锚定一个预先计算好的摘要:

cardanowall submit --hash <64-hex-digest> --json

锚定一个由叶子列表构建的 Merkle 批次:

cardanowall submit --merkle ./leaves.txt --json

这三种模式干净地对应到常见的自动化场景。小型作业可以锚定单个文件。发布系统可以锚定一份预先计算好的清单摘要。高吞吐系统可以把许多条目的哈希折叠进一个 Merkle 根,发布一条记录。完整的首次走查见发布你的第一份证明

运行 cardanowall <command> --help 可获取与版本对齐的权威标志列表——对于你已安装的构建版本,它始终是关于可用选项的最终定论。

如何一次性配置网关,而非每个作业各配一遍?

把网关 URL 和 API 密钥硬编码进每个作业既脆弱又易出错。CLI 改为存储具名的网关配置档:

cardanowall gateway add prod --base-url https://your-gateway.example
cardanowall gateway use prod
cardanowall gateway list

在 CI 中,从 stdin 喂入密钥,而不是回应交互式提示:

cardanowall gateway add prod \
  --base-url https://your-gateway.example \
  --api-key-stdin < ./gateway-api-key.txt

服务网关按固定顺序解析:显式标志优先,其次是环境变量,最后是当前激活的配置档。这种分工同时适配两类环境——开发者可以依赖保存好的配置档,而 CI 注入 CARDANOWALL_BASE_URLCARDANOWALL_API_KEY,完全跳过配置文件。

如何让密钥不出现在命令行里?

这是个容易犯的错,所以要让它难以犯下。绝不要把原始的身份种子或接收方密钥直接写进命令参数——argv 会泄露进 shell 历史、CI 日志和进程列表(ps)。

改用安全的输入来源:

  • --seed-stdin--seed-file
  • --secret-key-stdin--secret-key-file
  • 环境变量,仅当你的 CI 密钥处理足够干净时才用。

例如,从 stdin 把种子管道传入:

printf '%s' "$CARDANOWALL_SEED" | \
  cardanowall submit --file ./manifest.json --seed-stdin --json

一项密钥必须恰好来自一个来源;同时从两处提供(比如一个过时的 --seed-file 加上 CARDANOWALL_SEED)会触发硬性输入错误,这样旧值就绝不会悄悄盖过你本意要用的那个。原始的 --seed--secret-key argv 标志仍然存在,可用于一次性的测试值,但使用它们时会在 stderr 上打印一行警告。把那行警告当作一道真正的防线,而不是噪声。还有,由于完成这项工作时密钥从不需要传到服务器,种子始终留在运行命令的那台机器上——这正是为什么密钥从不离开设备背后的原则。

如何在流水线里为一条记录签名?

一条已签名的记录证明的不只是内容曾经存在,还证明某个特定项目或组织的密钥为它背书。在 Label 309 中,作者身份签名始终是可选的——仅含哈希的证明同样有效——但当来源溯源重要时,它们就派得上用场。

若要直接在本地签名,可在发布时安全地附上种子:

cardanowall submit --file ./release.json --seed-stdin --json

对更严格的环境,可让密钥完全不接触构建主机,分两步签名:

cardanowall sign prepare --signer-pubkey <hex> --hash <hex>
cardanowall sign assemble --signer-pubkey <hex> --signature <hex> --in record.cbor

这种拆分让 KMS、HSM、离线工作站或受保护的签名服务来产出 Ed25519 签名,而自动化流水线负责组装记录并发布,全程从不接触私钥。

如何把数千件产物批处理进一条记录?

Merkle 根正是 CLI 工作流实现规模化的方式。与其每件产物发一笔交易,不如构建一个叶子列表并锚定其根:

cardanowall merkle build --in leaves.txt --json > merkle.json
cardanowall submit --merkle ./leaves.txt --json

之后,凭包含证明就能证明某一片叶子:

cardanowall merkle verify \
  --root <hex32> \
  --leaf <hex32> \
  --proof proof.json

这非常契合 CI/CD 发布证据、批量 AI 生成内容、数据集清单、合规快照、日志归档和媒体溯源材料包。把叶子列表和包含证明与其余发布证据一并留存:链上的根只是日后完整验证工作的一半。该模式在一条记录覆盖数千份文件中有深入讲解,而 CI 的视角见在你的 CI/CD 流水线中生成证明

自动化何时该处理封存记录?

CLI 也能处理封存的 PoE——即面向一个或多个接收方加密的记录:

cardanowall inbox sync --seed-stdin
cardanowall inbox list --seed-stdin --json
cardanowall inbox decrypt <tx-hash> --secret-key-stdin

只在获授权持有接收方密钥的机器上运行这些命令。除非某个作业明确属于接收方的可信处理边界之内,否则不要把接收方密钥放进一般的 CI 环境。解密还会产出明文:一个能解密的进程,原则上也能泄露它所解密的内容,所以把这一步放在密钥本就应当所属的地方。

对大多数公开自动化来说,你会验证已签名或仅含哈希的证明,而从不触及接收方密钥。当你在搭建私密证据接收、机密投递或受控归档时,才该动用封存收件箱相关命令。

CI 作业应当归档什么?

要归档证明报告,而不仅仅是交易哈希。一次良好的运行应保留:

  • CLI 版本;
  • 命令参数,并对密钥做脱敏处理;
  • 输入的清单或文件摘要;
  • 交易哈希;
  • --json 发布输出;
  • --json 验证报告;
  • 用到的话,还有 Merkle 叶子列表和包含证明;
  • 任何已签名记录的签名者身份;
  • 针对待定或无法验证结果的重试日志。

这给未来的审计者足够的上下文去复现检查,而无需任何人去还原几个月前一个发布作业究竟是怎么搭建起来的。

一种实用的发布模式

一个发布作业可以是这样的形态:

  1. 构建产物。
  2. 生成校验和、SBOM、证明文件和一份发布清单。
  3. 对清单计算哈希,或构建一个 Merkle 叶子列表。
  4. cardanowall submit 发布。
  5. 捕获交易哈希并等待确认。
  6. 运行 cardanowall verify
  7. 将 JSON 报告与发布产物一同存储。
  8. 遇到 failed 就让发布失败;遇到 pendingunverifiable 则重试或暂缓。

这一切都不复杂,而这正是重点。证明应当平淡到足以在每次发布时都跑一遍。

延伸阅读

cliautomationci-cd