mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): gate release tags on deployment readiness
This commit is contained in:
@@ -11,6 +11,28 @@
|
||||
|
||||
最新增量证据(2026-08-18):
|
||||
|
||||
- D-351/ADR-0443(已接受;首份真实 GHCR deployment-ready finalization 待实际 release tag):D-350 的 catalog-ready
|
||||
publication 继续收紧为 deployment-ready publication。`release-set` job 只发布、验签并 attested immutable catalog,不再登录 registry
|
||||
或修改最终 image tag;`local|all` 必须先完成 Edge 与 Standalone 的 catalog-bound 正式 Compose rollout,`cluster|all` 必须先完成三节点
|
||||
K3s install、Head 与 UID/resourceVersion fenced retirement。两个只读部署 job 现在连同 content-free report 保存各自 exact-three-file
|
||||
catalog consumption bundle;终态 `release-finalization` 按 scope 强制精确 success/skipped 真值表、下载并复验 exact 文件集合,再第三次独立消费
|
||||
公开 immutable catalog。新增 `qinglong/release-deployment-readiness-receipt@v1` 联合绑定 finalizer consumption、要求的部署族、每个
|
||||
consumption/report digest、release-set/catalog identity 与清理结果,拒绝 synthetic/incomplete/unclean、跨 scope 或 catalog-detached
|
||||
evidence,并在任何 Docker login/tag mutation 前本地复审和单独 attested。publication plan/closure receipt 升为 v2,发布 authority 为
|
||||
`verified_catalog_bound_deployments`;D-350 的 bounded inventory、零写 conflict preflight、exact reuse、absent copy、终态 tag 回读和
|
||||
`crossRepositoryAtomicity=false`/`registryTagCas=false` 均保留。最终 90 天 bundle 闭合 finalizer catalog、部署 evidence、readiness、plan、
|
||||
observation 与 closure。该变化不新增 package、生产依赖、数据库、migration、Kubernetes object 或设备常驻资源;Local 不承担 K3s 门,
|
||||
Cluster 不承担 Compose 门,Edge/Standalone/路由设备与集群节点稳态成本仍为零。阶段门已重跑:readiness/publication/workflow/Console
|
||||
distribution 聚焦测试 112/112,完整 backend 1,393 pass + 2 条条件 skip/0 fail,18-package clean build/test 退出 0,14/14 静态审计与
|
||||
14/14 artifact 档位全部 compatible;artifact 字节保持基础 Edge/Standalone `2589890/2589968`、adopted
|
||||
`2809185/2809308`、application `3632769/3632889`、application-api `3800322/3800466`、AI `3069143/3069233`、
|
||||
application+AI `4493043/4493175`、MCP `7315930/7316038`。真实 Docker 三节点 K3s v1.34.3/arm64 fixture 完成 install、Head、
|
||||
UID/resourceVersion fenced retirement、receipt audit 与零残留;fixture 明确保持 `synthetic_live_fixture`,不冒充公开 catalog 证据。
|
||||
PostgreSQL 18.6/arm64 HA 再次通过 142/142、timeline `1→2`,报告 SHA-256 为
|
||||
`d7bb8164b46c1392518eb08bea338640639fe5eca71a7401d98d98ea94146fd2`,离线复审通过且容器/卷/网络残留为零。本机成功构建 exact Local
|
||||
image,但 Local selection 有意只接受真实 `ghcr.io/<owner>/...@sha256`,因此本地 loopback registry 和 image-id 伪装均失败关闭;首份真实
|
||||
Local catalog-bound rollout 与完整 deployment-ready finalization 仍只能由受保护 release tag 产生。
|
||||
|
||||
- D-350/ADR-0442(已接受;首份真实 GHCR 部分 promotion/replay 证据待实际 release tag):正式 image tag 不再在完整
|
||||
release-set 审计后、durable catalog 建立前提前公开。`versionTag/sourceTag` mutation 现位于 release-set provenance、catalog
|
||||
immutable round-trip、catalog signature/provenance 验证、catalog receipt 审计及其 attestation 全部成功之后。新的
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# ADR-0442:Catalog-ready 的终态 Release Tag 发布与闭合收据
|
||||
|
||||
- 状态:Accepted
|
||||
- 状态:Superseded by ADR-0443(bounded promotion/closure 机制继续有效,发布前置顺序被收紧)
|
||||
- 日期:2026-08-18
|
||||
- 关联 RFC:QL-RFC-0001 D-03、D-14、D-336、D-349、D-350
|
||||
- 关联 ADR:ADR-0427、ADR-0428、ADR-0439、ADR-0441
|
||||
- Supersedes:ADR-0427 中“完整 release-set 审计后即可 promotion”的最早发布顺序
|
||||
- Superseded by:ADR-0443 将最终 tag mutation 继续后移到 scope-exact deployment readiness attestation 之后
|
||||
|
||||
## 上下文
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# ADR-0443:Deployment-ready 的终态 Release Finalization
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-18
|
||||
- 关联 RFC:QL-RFC-0001 D-03、D-14、D-336、D-344、D-345、D-350、D-351
|
||||
- 关联 ADR:ADR-0436、ADR-0437、ADR-0441、ADR-0442
|
||||
- Supersedes:ADR-0442 中“catalog receipt attested 后即可 mutation 最终 image tag”的发布顺序
|
||||
|
||||
## 上下文
|
||||
|
||||
ADR-0442 已把最终 image tag 从 release-set 聚合点后移到 immutable catalog 建立并验签之后,但 Local Compose 与 Cluster K3s
|
||||
下游门仍在该次 tag mutation 之后运行。若 catalog 可验证而 Edge、Standalone 或三节点 K3s 的真实部署链失败,公开
|
||||
`versionTag/sourceTag` 已经存在,却没有与本次 scope 对应的 catalog-bound 部署证据。此时“catalog-ready”只证明发布材料完整,不能证明
|
||||
该发布已进入要求的部署族。
|
||||
|
||||
同时,部署 job 原先只上传 content-free report,不保留生成 report 时独立消费的 catalog ceremony bundle。终态发布者无法证明 report
|
||||
确实来自与自身复验相同的 immutable catalog,也无法在一个可离线审计的 readiness receipt 中闭合 catalog、scope 和部署结果。
|
||||
|
||||
## 决策
|
||||
|
||||
1. `release-set` job 只负责聚合、审计、签证 release-set,发布并验证 immutable OCI catalog,以及签证 catalog receipt。它不再拥有最终
|
||||
image tag mutation、registry login 或 publication closure 权限。
|
||||
2. `local|all` 必须成功完成 Edge 与 Standalone 两个正式 Compose rollout;`cluster|all` 必须成功完成 catalog-bound 三节点 K3s
|
||||
install、Head 和 fenced retirement。终态 `release-finalization` 使用显式 needs/result 真值表,要求当前 scope 的 job 全部 `success`,不属于
|
||||
当前 scope 的 job 必须为 `skipped`;`failure`、`cancelled` 或意外运行均失败关闭。
|
||||
3. 每个部署 evidence artifact 必须同时保留 owner-private、canonical、exact-three-file catalog consumption bundle 和 content-free report。
|
||||
Local artifact 精确为 consumption 三文件、`edge.json`、`standalone.json`;Cluster artifact 精确为 consumption 三文件、`report.json`。
|
||||
finalizer 下载后重新固定目录 `0700`、文件 `0600` 并拒绝缺失或额外文件。
|
||||
4. finalizer 不信任 publisher 或部署 job 的瞬时内存。它再次从 discovery ref 解析 immutable catalog,独立执行 Cosign、GitHub provenance、
|
||||
manifest round-trip 与 ceremony audit,并从自己读取的 bytes 重建 catalog plan/receipt。
|
||||
5. 新增 `qinglong/release-deployment-readiness-receipt@v1`。它联合审计 finalizer consumption、当前 scope 要求的每个 deployment
|
||||
consumption bundle 和 report,绑定 release identity、immutable catalog reference、manifest/release-set digest、每份 consumption/report
|
||||
digest、精确部署族和清理结果。它拒绝 synthetic fixture、不完整报告、catalog 脱离、跨 scope 证据和未清理现场。
|
||||
6. readiness receipt 必须在 Docker login 和任何 tag mutation 之前生成、复审并单独 attested。只有该 attestation 成功,finalizer 才生成并执行
|
||||
`qinglong/release-publication-plan@v2`。v2 plan 和 `qinglong/release-publication-closure-receipt@v2` 都绑定 readiness receipt digest、
|
||||
finalizer consumption digest 和精确部署族,发布 authority 升为 `verified_catalog_bound_deployments`。
|
||||
7. D-350 的 bounded inventory、全量 conflict preflight、exact-tag reuse、absent-tag copy、最终逐 tag 回读和无 CAS/跨仓库事务声明保持不变。
|
||||
它们只从 catalog publisher 移入唯一的 finalizer,并发生在 readiness attestation 之后。
|
||||
8. 90 天最终 bundle 保存 finalizer consumption、scope-exact deployment evidence、readiness receipt、publication plan、tag observation 与 closure
|
||||
receipt。部署 authority 仍是签名并 attested 的 immutable catalog digest;mutable tag 与 closure 只表示发布可见性和终态证据。
|
||||
|
||||
## 失败与恢复
|
||||
|
||||
- catalog 已发布但任一要求的部署门失败:没有最终 image tag mutation。该 catalog 是可复验候选材料,不是 deployment-ready tag authority。
|
||||
- evidence artifact 缺失、额外、权限过宽、包含 synthetic report 或引用不同 catalog:finalizer 在 registry login 前失败。
|
||||
- readiness attestation 失败:不发布 tag;同一 protected source tag 可重跑并重新取得现场证据。
|
||||
- tag promotion 中途 response loss:继续使用 ADR-0442 的 exact-tag reuse,仅补 absent tag;不同 digest 永远冲突失败。
|
||||
- readiness receipt 是本次部署运行的操作证据,其 digest 可以随新的真实 consumption/report 变化;它不重新定义 release-set 或 immutable
|
||||
catalog identity,也不伪称跨重跑逐字节确定。
|
||||
|
||||
## 部署与资源影响
|
||||
|
||||
- Edge、Standalone、低配路由设备和 Cluster 节点不安装 Node、regctl、Cosign 或 GitHub CLI,不新增 watcher、timer、listener、updater、
|
||||
queue、缓存或常驻进程。
|
||||
- 不新增 workspace package、生产依赖、数据库、schema、migration、SQL、Kubernetes object、RBAC 或业务副本。
|
||||
- 增量 CPU、内存、网络和磁盘只发生在短生命周期 release runner。Local scope 不运行 K3s 门,Cluster scope 不运行 Compose 门;`all` 才运行两族。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### catalog-ready 后继续立即发布最终 tag
|
||||
|
||||
拒绝。catalog 完整不等于 scope 要求的部署路径已成功,仍会留下“公开 tag 成功、真实部署失败”的窗口。
|
||||
|
||||
### 只依赖 GitHub job result,不闭合部署证据
|
||||
|
||||
拒绝。瞬时调度状态不能证明 report 使用了哪个 immutable catalog,也无法让最终 bundle 独立审计。
|
||||
|
||||
### 让部署 job 自行发布 tag
|
||||
|
||||
拒绝。会把 package write、attestation write 和 registry login 权限扩散到多个高成本 runner,并引入多写者竞争。
|
||||
|
||||
### 把完整 token、kubeconfig 或命令 transcript 上传给 finalizer
|
||||
|
||||
拒绝。finalizer 只需要 owner-private catalog bundle 和 content-free bounded report;credential 与现场控制材料必须留在原 job 生命周期内。
|
||||
|
||||
## 验证
|
||||
|
||||
- readiness contract 覆盖 Local/Cluster/All 精确部署族、缺失/额外/跨 scope 证据、catalog 脱离、synthetic/incomplete/unclean report、
|
||||
receipt tamper、自摘要重算和 closed CLI;
|
||||
- release workflow 静态门固定 `catalog receipt → scope-exact deployment jobs → finalizer independent consumption → readiness audit/attestation →
|
||||
tag mutation → closure audit/attestation` 顺序,并拒绝 evidence bundle、needs/result、独立 attestation 或最终 bundle 漂移;
|
||||
- 完整仓库、产物档位和部署 Gate 的阶段结果记录在 QL-RFC-0001 D-351;首份真实 GHCR deployment-ready finalization 仍须由受保护
|
||||
`v3` release tag 或受控 release repository 演练产生。
|
||||
+2
-1
@@ -445,7 +445,8 @@
|
||||
| [ADR-0439](./ADR-0439-deterministic-private-evidence-receipts-and-release-set-replay.md) | 确定性私有证据收据与 Release-set 重放 | Accepted(首份真实线上重放待实际 release tag) |
|
||||
| [ADR-0440](./ADR-0440-release-set-closure-private-evidence-freshness.md) | Release-set 闭合时私有证据 Freshness 重验证 | Accepted(首份真实线上闭合待实际 release tag) |
|
||||
| [ADR-0441](./ADR-0441-no-overwrite-release-catalog-discovery-publication.md) | Release Catalog Discovery Tag 无覆盖发布 | Accepted(首份真实 GHCR conflict/reuse 证据待实际 release tag) |
|
||||
| [ADR-0442](./ADR-0442-catalog-ready-terminal-release-tag-publication.md) | Catalog-ready 的终态 Release Tag 发布与闭合收据 | Accepted(首份真实 GHCR 部分 promotion/replay 证据待实际 release tag) |
|
||||
| [ADR-0442](./ADR-0442-catalog-ready-terminal-release-tag-publication.md) | Catalog-ready 的终态 Release Tag 发布与闭合收据 | Superseded by ADR-0443(bounded promotion/closure 机制保留) |
|
||||
| [ADR-0443](./ADR-0443-deployment-ready-terminal-release-finalization.md) | Deployment-ready 的终态 Release Finalization | Accepted(首份真实 GHCR deployment-ready finalization 待实际 release tag) |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
@@ -36,28 +36,50 @@ cert-manager 三项静态审计摘要。v2 收据不持久化私有 runner 的 w
|
||||
|
||||
## 发布流水线内置 Local 与 Cluster 下游门
|
||||
|
||||
durable catalog 建立只表示候选发布材料可独立验证,不再直接授予最终 image tag 发布权。最终
|
||||
`versionTag/sourceTag` 只能由 `release-finalization` 在当前 scope 的全部下游门成功、deployment readiness receipt 已复审并单独
|
||||
attested 后写入。catalog 先存在而部署门失败时,不会产生正式 image tag;运维者不得把 discovery tag 或未闭合 catalog 当作
|
||||
deployment-ready 版本公告。
|
||||
|
||||
`local|all` scope 在 durable catalog 发布后启动独立 `release-catalog-local-deployment-live`。它与 publisher 权限隔离,从公开 catalog
|
||||
重新完成发现、Cosign/GitHub provenance 验证和 three-file bundle audit,随后物化唯一 Local v2 selection。该 selection 不是只做 JSON
|
||||
检查:同一个 immutable Local image 与 selection 会依次进入 Edge、Standalone 的正式 Compose rollout、SQLite backup/restore、evidence
|
||||
collection 和 graceful stop。两个 content-free report 必须绑定同一 release-set、catalog manifest、consumption report 与 selection digest;
|
||||
任一 Profile 失败都会阻断 Local release。
|
||||
|
||||
该 job 只有 `contents|packages|attestations:read`,不执行 Docker login、签名、tag promotion 或 catalog mutation。regctl、Cosign、GitHub CLI、
|
||||
Node workspace、token 和原始 bundle 仅存在于短生命周期 release runner;路由设备/NAS/单机用户不安装这些发布工具,也不增加常驻 updater、
|
||||
listener 或 timer。第一份真实证据仍必须由受保护 release tag 产生;PR fixture 只验证失败关闭与产品 rollout 路径。
|
||||
该 job 只有 `contents|packages|attestations:read`,不执行 Docker login、签名、tag promotion 或 catalog mutation。成功 artifact 精确保存
|
||||
owner-private catalog consumption 三文件、`edge.json` 和 `standalone.json`,供终态 finalizer 复审;token 与命令材料不上传。regctl、Cosign、
|
||||
GitHub CLI、Node workspace 和原始 bundle 仅存在于短生命周期 release runner;路由设备/NAS/单机用户不安装这些发布工具,也不增加常驻
|
||||
updater、listener 或 timer。第一份真实证据仍必须由受保护 release tag 产生;PR fixture 只验证失败关闭与产品 rollout 路径。
|
||||
|
||||
## 发布流水线内置 Cluster 下游门
|
||||
|
||||
`ql3-image-release.yml` 在 durable catalog、签名、provenance、receipt 和 90 天便利 bundle 全部发布后,才启动独立
|
||||
`ql3-image-release.yml` 在 durable catalog、签名、provenance 与 receipt 全部发布后,才启动独立
|
||||
`release-catalog-deployment-live`。该 job 只处理 `cluster|all`;Local-only 发布不会启动 K3s。它没有 publisher 的 package/attestation
|
||||
写权限或 registry 登录态,而是按下文工作站协议重新消费公开 catalog,离线重建 deployment lock,并在隔离三节点 K3s 上完成 install、
|
||||
Head commit、一个显式 ConfigMap 的 UID/resourceVersion 围栏退役和两个 receipt audit。任何公开读取、exact workflow identity、source
|
||||
tag/revision、digest、scope、角色闭包、server-side apply/Head 或清理失败都会让 Cluster release 失败。
|
||||
|
||||
该门的四个业务 Deployment 都为零副本:它证明真实 catalog image authority 已进入目标 API、lock、Head 与 receipt 闭包,不重复下载和启动
|
||||
完整业务数据面。应用启动、数据库、Secret、Worker 与 AI lifecycle 继续由各自 live/release gate 负责。成功 artifact 只保存 content-free
|
||||
JSON evidence;consumption bundle、token、kubeconfig 和 command 文件不上传。首份真实成功记录必须来自实际受保护 release tag,普通 PR 中的
|
||||
synthetic live fixture 不能替代它。
|
||||
完整业务数据面。应用启动、数据库、Secret、Worker 与 AI lifecycle 继续由各自 live/release gate 负责。成功 artifact 精确保存
|
||||
owner-private catalog consumption 三文件和 `report.json`;token、kubeconfig 与 command 文件不上传。首份真实成功记录必须来自实际受保护
|
||||
release tag,普通 PR 中的 synthetic live fixture 不能替代它。
|
||||
|
||||
## Deployment-ready 终态发布
|
||||
|
||||
`release-finalization` 是唯一具有 `packages:write` 与 `attestations:write` 的最终 tag 写者。它使用严格 scope 真值表:`local` 要求 Local
|
||||
成功且 Cluster 跳过,`cluster` 要求 Cluster 成功且 Local 跳过,`all` 要求两者都成功。下载的 Local evidence 必须精确为五个文件,Cluster
|
||||
evidence 必须精确为四个文件;目录重新设为 `0700`、文件为 `0600`,缺失、额外、synthetic、未完成或未清理报告均失败关闭。
|
||||
|
||||
finalizer 随后独立重新消费公开 immutable catalog,而不是复用 publisher 的临时输出。`qinglong/release-deployment-readiness-receipt@v1`
|
||||
把 finalizer consumption、scope 要求的每个 deployment consumption/report、immutable catalog、release-set 和清理结果闭合为一份
|
||||
self-digest receipt。只有该 receipt 完成本地 audit 和独立 attestation,`qinglong/release-publication-plan@v2` 才能进入 bounded tag
|
||||
inventory、全量冲突预检与 promotion;`qinglong/release-publication-closure-receipt@v2` 最终绑定同一 readiness。90 天 bundle 包含 finalizer
|
||||
consumption、部署 evidence、readiness、plan、tag observation 和 closure,能够离线复查“哪个 catalog、哪些部署族、哪些终态 tag”。
|
||||
|
||||
readiness 是本次 release workflow 的操作证据,不是新的镜像内容 identity。同一 protected source tag 因失败而重跑时,新的真实部署报告可使
|
||||
readiness digest 不同;release-set 与 immutable catalog digest 仍必须相同,既有 exact tag 只能复用,不同 digest 继续失败。OCI registry
|
||||
没有跨 repository 事务或 tag CAS,因此 closure 证明的是观测到的终态,不是原子提交。
|
||||
|
||||
## 选择 scope
|
||||
|
||||
|
||||
Reference in New Issue
Block a user