Files
qinglong/docs/adr/ADR-0430-auditable-release-catalog-consumption-ceremony.md
T

7.7 KiB
Raw Blame History

ADR-0430:可审计的 Release Catalog 消费工作站 Ceremony

  • 状态:Accepted(实现与本地契约门完成;真实公开 catalog 结果待实际 release tag
  • 日期:2026-08-16
  • 关联 RFCQL-RFC-0001 D-03、D-14、D-333、D-335、D-336、D-337、D-338
  • 关联 ADRADR-0424、ADR-0425、ADR-0427、ADR-0428、ADR-0429

上下文

ADR-0428 已让发布 workflow 生成持久 OCI release catalogADR-0429 已能把验证后的 release set 离线物化为 Local selection 或 Kubernetes locked manifest。但部署者侧仍依赖手工 shell 串联 discovery tag 解析、Cosign、GitHub attestation、regctl artifact get、raw manifest 读取和 standalone inspection。该流程会把文件写入安全性留给调用者的 umask/重定向语义,也不检查 discovery tag 是否在 ceremony 中途移动,不保留工具身份、命令边界或可离线复验的 manifest。

因此,发布端已经有机器化证据,并不等于部署端消费同一 immutable catalog 的过程已经机器化。直接在 release workflow 内自动部署又会把发布写权限与生产部署权限合并,破坏显式运维授权边界。

决策

  1. 新增根级 ql3-release-catalog-consumption-ceremony.cjs,只在可信维护工作站显式运行。create 模式从 source-derived version、40-hex revision、exact tag ref、closed local|cluster|all scope、owner/source repository 和 三个 canonical absolute executable 推导唯一 catalog discovery reference,不接受任意 registry/repository/ref。
  2. ceremony 对 discovery tag 解析两次;两次都必须返回同一 lowercase SHA-256 digest。所有后续命令只使用第一次得到的 ghcr.io/<owner>/qinglong3-release-catalog@sha256:...。tag 在验证窗口中移动时失败且不发布 bundle;tag 永远没有部署 authority。
  3. immutable catalog 必须通过 exact workflow identity 的 keyless Cosign verification,以及绑定 source repository、 workflow、tag、revision、非 self-hosted runner 和 OCI bundle 的 GitHub provenance verification。owner-private token 只注入 单个 gh attestation verify 子进程;regctlcosign 不接收该 token,也不继承 ambient environment。
  4. ceremony 直接捕获而不是 shell 重定向 release-set 与 raw manifest bytes。release set 必须是 bounded canonical UTF-8 JSON 通过 standalone structure/identity/family/self-digest inspectionraw manifest 必须与 immutable digest、单层 media type、 empty config、basename、size/content digest 和四项 annotation 完全一致。工具在每一步前及 ceremony 结束前按 path/dev/inode/size/SHA-256 复验。
  5. 成功后才创建一个此前不存在的 owner-private 0700 bundle directory,并以 0600、no-replace、fsync 写入三项精确文件: 原始 canonical release set、原始 raw catalog manifest、canonical consumption report。report 绑定 source/release/catalog、 reconstructed plan/receipt digest、文件 digest、镜像闭包、工具 digest、六步 argv/stdout/stderr digest 和自身 digest;不保存 token、原始 transcript、本机路径或 workstation identity。
  6. audit 模式完全离线,不调用外部工具。它要求 bundle 只有上述三项文件,重新执行 release-set inspection、catalog plan、 raw manifest 与 receipt reconstruction,并精确重建 report;外部 Cosign/GitHub 结果只作为 digest transcript 记录,明确 externalToolResultsReplayed=false,不能冒充离线重验了网络证明。
  7. 外部工具的 cache/config/tmp 只能写入 bundle parent 下的 ceremony 私有临时目录,成功或失败后 best-effort 清理。ceremony 不执行 registry/GitHub mutation、不运行 Compose/Kubernetes apply、不连接数据库,也不取得部署 action authority。D337 materializer 只消费 audit 成功 bundle 中的 release set,部署仍是后续独立人工授权步骤。

部署与资源影响

  • 不新增 workspace package、生产 dependency、镜像层、数据库、migration、SQL、role、Pool、Pod、controller、listener、timer 或 watcher18-package 边界保持不变。
  • Edge/Standalone/低配路由设备不安装 Node、regctl、Cosign、GitHub CLI 或 ceremony。可信工作站只把审计后的 Local release set、 selection 和 immutable image 交给设备。
  • Cluster 工作站可消费 cluster|all 的四角色闭包,再把 release set 交给离线 Kubernetes post-render materializerceremony 本身没有 Kubernetes client 或 API authority。
  • 公开 GHCR、Fulcio/Rekor 与 GitHub Attestations 的实际可用性只由真实 release/consumption run 证明。本地 fake tool 测试只证明 命令、隔离、输入输出和失败关闭契约。

失败与恢复

  • discovery 两次解析不同:丢弃本次结果,以新的未使用输出目录重新开始;不能把任一 tag 值当成部署 authority。
  • Cosign/GitHub/registry 失败:不发布 bundle,不降级为仅检查 JSON 或 tag。
  • tool inode/bytes、token file、output parent 在运行中漂移:失败关闭;不从 ambient PATH 换用另一个 executable。
  • 创建最终目录后发生进程/文件系统失败:保留不完整目录供调查,但该目录无法通过 exact-three-file audit;恢复必须使用新目录, 不覆盖或补写旧 bundle。
  • offline audit 失败:重新执行在线 ceremony;不得手工修复 report/digest 声称通过。

被拒绝的替代方案

保留文档中的 shell 重定向即可

拒绝。它无法统一 no-replace、mode、symlink、输出上限、tool mutation、tag 中途移动和持久 manifest 证据,且容易把调用者的 ambient credential/environment 带入工具。

只保存下载后的 release-set JSON

拒绝。release-set self digest 不能证明 OCI manifest 的 media type、layer、title、annotation 或 immutable digestraw manifest 是离线重建 publication plan/receipt 的必要证据。

在 release workflow 成功后自动部署

拒绝。发布 OIDC/package 写权限与生产集群/路由设备 authority 必须分离;验证成功只生成无行动权的部署输入。

在路由设备上运行 ceremony

拒绝。该工具依赖 Node、regctl、Cosign 与 GitHub CLI,并执行网络验真;这些成本和凭据面不应进入低资源运行设备。

验证

  • ceremony 正负门覆盖 Local/All scope、六步工具与 token 隔离、双次 discovery、canonical release set、raw manifest、工具 mutation、external failure、no-replace、private mode、symlink/open CLI,以及 release-set/manifest/report/目录漂移;独立 ceremony 测试 20/20
  • 与 deployment lock、release candidate、release set、release catalog 和 image release workflow 的定向发布链联动 121/121;共享 supply-chain CI 显式运行新测试,删除该测试会失败关闭;
  • 完整 backend 共 1,315 项,1,313 pass、2 条件 skip、0 fail18-package clean build/test 退出 0package boundary 仍为 18 packagessingleSourcePackages=[]shallowSourcePackages=[]
  • release version、deployment lock surfaces、package boundary、cluster dependency、Edge import、Cluster/Worker deployment、image release、Local image 与 Console distribution 共 10 项审计全部 compatible14 档 Local artifact 全部 compatible,默认 Edge/Standalone 为 2,589,890/2,589,968 bytesapplication+AI 为 4,493,043/4,493,175 bytesMCP 为 7,315,930/7,316,038 bytes
  • Cluster Admin pack dry-run 保持 250 files、271,238-byte tarball、1,690,196-byte unpacked
  • 本 Gate 不改变数据库或 HA 拓扑,除非完整回归发现相关漂移,否则复用紧邻发布 Gate 的 PostgreSQL 18.6 arm64 physical HA 基线,不把未重跑结果声明为本阶段新证据。