mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): revalidate release evidence at closure
This commit is contained in:
@@ -11,6 +11,24 @@
|
||||
|
||||
最新增量证据(2026-08-18):
|
||||
|
||||
- D-348/ADR-0440(已接受;首份真实线上闭合待实际 release tag):补齐 D-347 确定性收据与实际 tag promotion 之间的 freshness 窗口。此前私有
|
||||
job 在收据创建时验证 24 小时 freshness,但 release-set aggregate 只检查 `observedAt` 可解析与 receipt digest;镜像构建、扫描和 attestation
|
||||
延迟后,创建时有效的收据可能在闭合时已经过期。现在 `cluster|all` aggregate 与紧随其后的 source-record audit 必须各自取得 runner-owned 当前
|
||||
时钟,对两份 receipt 公开的 `observedAt` 重新执行 24 小时最大年龄和五分钟未来偏差门;缺失/非安全整数/过期/未来漂移均在 release-set 写文件、
|
||||
tag promotion 和 catalog publication 前失败关闭。当前时钟没有 CLI 参数、环境变量或 durable 字段,只参与瞬时准入;因此同一 source evidence 在
|
||||
两个有效闭合时钟下仍生成逐字节相同的 receipt v2、release-set v3 与 catalog identity。Local scope 保持零私有收据且该门为
|
||||
`not_applicable`;历史 standalone inspection 继续验证结构/identity/self-digest 而不以今天的时钟淘汰合法 catalog,并诚实声明未重放 source
|
||||
records/private reports。本 Gate 不修改 durable schema/media type,不新增 package、生产依赖、数据库、migration、Pod、controller、RBAC、
|
||||
listener、timer、设备工具或稳态资源。定向 release receipt/set/catalog/consumption/deployment-lock/image audit 回归 137/137;完整 backend
|
||||
1,365 项为 1,363 pass/2 条件 skip/0 fail,18-package clean build/test 退出 0。12 项 package boundary、Cluster dependency、Edge
|
||||
import、Cluster/Worker/CloudNativePG 部署、backup、Barman/cert-manager selection、image release、deployment-lock surface 与
|
||||
release-version 审计全部 compatible;14 档 Local artifact 全部 compatible 且保持既有字节基线:默认 Edge/Standalone 为
|
||||
2,589,890/2,589,968 bytes,adopted 为 2,809,185/2,809,308 bytes,application 为 3,632,769/3,632,889 bytes,
|
||||
application-api 为 3,800,322/3,800,466 bytes,AI 为 3,069,143/3,069,233 bytes,application+AI 为
|
||||
4,493,043/4,493,175 bytes,MCP 为 7,315,930/7,316,038 bytes。真实 PostgreSQL 18.6 arm64 physical HA 再次通过 142/142、
|
||||
timeline `1→2`,报告 SHA-256 为 `7566a54f86f3e4e0fee2096a49ea2877d827595575c7075bc44b65314cb2ba19`,离线审计通过且无
|
||||
`ql3-ha-*` Docker 容器、卷或网络残留;真实线上 closure 仍只能由实际受保护 `v3` release tag 取得。
|
||||
|
||||
- D-347/ADR-0439(已接受;首份真实线上重放待实际 release tag):修正 D-346 收据把私有 runner `validatedAt` wall-clock 写入 durable
|
||||
JSON 导致同一 source/report 在 workflow 重跑时产生第二个 release identity 的问题。私有收据升为
|
||||
`qinglong/private-release-evidence-receipt@v2`:创建时仍以当前私有时钟执行 source-aware gate 和 24 小时 freshness 双重验证,但 durable
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# ADR-0440:Release-set 闭合时私有证据 Freshness 重验证
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-18
|
||||
- 关联 RFC:QL-RFC-0001 D-03、D-14、D-335、D-346、D-347、D-348
|
||||
- 关联 ADR:ADR-0427、ADR-0438、ADR-0439
|
||||
- Extends:ADR-0439 的确定性私有证据收据与 release-set replay
|
||||
|
||||
## 上下文
|
||||
|
||||
ADR-0439 从私有证据收据中移除了 runner `validatedAt` wall-clock,使同一 release identity、私有报告和静态 lock 在合法 workflow 重跑时生成相同
|
||||
receipt、release-set 与 catalog digest。创建私有收据时仍会用当前私有 runner 时钟执行 24 小时 freshness gate。
|
||||
|
||||
但 release-set job 可能在镜像构建、扫描、签名和 attestation 后才消费短期收据。D347 的聚合路径只验证 `observedAt` 可解析、receipt identity 和
|
||||
self digest,没有在 tag promotion 前以闭合时钟重新计算年龄。GitHub artifact 的一天 retention 是存储配置,不是精确的证据 freshness authority;
|
||||
收据在创建时有效,不代表在 release-set 闭合时仍有效。
|
||||
|
||||
## 决策
|
||||
|
||||
1. `cluster|all` release-set closure 必须取得一个 runner-owned、safe-integer validation clock。该时钟不是 release-set input field,也不能由 CLI
|
||||
参数、环境变量、image record 或私有 receipt 指定。
|
||||
2. `inspectPrivateReleaseEvidenceReceipt` 在 closure caller 显式提供 validation clock 时,除 exact shape/source/report/self-digest 外,还必须用公开的
|
||||
`observedAt` 重新执行 24 小时最大年龄和五分钟未来偏差门。
|
||||
3. release-set `aggregate` 与紧随其后的 source-record `audit` 各自从进程内当前时钟执行该门;缺失、非安全整数、过期或未来漂移均在写 release-set、
|
||||
tag promotion 和 catalog publication 前失败关闭。
|
||||
4. validation clock 只参与准入,不进入 receipt、release-set、catalog plan、OCI manifest 或 digest。两个不同但都在有效窗口内的闭合时钟必须生成
|
||||
逐字节相同的 release-set。
|
||||
5. `local` scope 必须保持零私有收据,closure freshness 为 `not_applicable`,不要求该时钟即可创建同一 Local release-set。
|
||||
6. `inspectReleaseSet` 是历史 durable catalog 的 standalone verifier,不以当前日期淘汰曾经合法的发布。它继续验证结构、identity、image/receipt 顺序与
|
||||
self digest,并诚实声明 source records/private reports 未重放;当前年龄不能证明过去发布时的 freshness。
|
||||
7. 不升级 receipt v2、release-set v3 或 OCI v3 media type,因为 durable bytes 和消费者结构没有变化;本 Gate 只收紧创建/审计时可接受的瞬时输入。
|
||||
|
||||
## 失败与恢复
|
||||
|
||||
- 收据在创建时有效、闭合时超过 24 小时:aggregate 在任何 durable 输出和 tag mutation 前失败,必须重新取得 source-aware 私有报告及其确定性收据。
|
||||
- 收据时间超过闭合时钟五分钟:视为时钟/报告异常并失败,不能通过推迟发布等待其“自然有效”。
|
||||
- aggregate response-loss 后以同一 source evidence 重跑:新的闭合时钟若仍在窗口内,生成相同 bytes;若已过期则必须重新取得私有证据,而不是复用旧收据。
|
||||
- 历史 catalog 多年后验真:standalone inspection 仍可通过 structural/digest/provenance 链;不得声称重新执行了当年的私有 freshness gate。
|
||||
- Local 发布:没有私有 evidence receipt,不执行 Cluster freshness 语义,也不新增设备或发布 runner 工作。
|
||||
|
||||
## 部署与资源影响
|
||||
|
||||
- Edge/Standalone 设备、Local image、selection 和 Compose 路径零变化,不安装发布工具,不增加 CPU/RSS、I/O、timer、listener 或 updater。
|
||||
- Cluster 节点和 Kubernetes object 零变化;重验证只发生在短生命周期 release-set runner,成本为两次时间读取和两个时间戳的常数比较。
|
||||
- 不新增 workspace package、生产依赖、数据库、migration、SQL、Pod、controller、RBAC、Secret、网络连接或持久状态。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 重新把 `validatedAt` 写入 receipt
|
||||
|
||||
拒绝。它会恢复 D347 已消除的 wall-clock digest 漂移,让合法 workflow retry 产生第二个 catalog identity。
|
||||
|
||||
### 依赖一天的 GitHub artifact retention
|
||||
|
||||
拒绝。retention 是删除上限,不保证下载瞬间的精确年龄、未来偏差或 tag promotion 前重验证,也不是 release contract 的可测试语义。
|
||||
|
||||
### 让 CLI 传入 `--validation-clock`
|
||||
|
||||
拒绝。发布者可选择旧时钟会把 freshness gate 变成自报事实。测试通过显式 dependency injection 驱动边界,生产 CLI 不开放该输入面。
|
||||
|
||||
### 在所有历史 catalog inspection 中按当前时间拒绝
|
||||
|
||||
拒绝。这样所有合法发布都会在 24 小时后不可审计,并把“当前仍新鲜”错误等同于“发布时曾通过 freshness gate”。
|
||||
|
||||
## 验证
|
||||
|
||||
- 同一 Cluster source evidence 在两个不同有效 closure clock 下生成对象和 canonical bytes 完全相同;
|
||||
- 超过 24 小时、未来偏差和缺失 validation clock 均在 release-set 写入前失败;
|
||||
- CLI production path 使用内部 clock,测试证明 stale retry 不产生输出;
|
||||
- Local scope、历史 standalone inspection、catalog consumption 和 deployment lock 保持兼容;
|
||||
- 定向发布链 137/137,完整 backend 1,365 项为 1,363 pass/2 条件 skip/0 fail,18-package clean build/test 退出 0;
|
||||
- 12 项静态审计和 14 档 Local artifact 全部 compatible,Edge/Standalone 至 MCP 的既有制品字节与 RSS 上限未漂移;
|
||||
- PostgreSQL 18.6 arm64 physical HA 通过 142/142、timeline `1→2`,证据 SHA-256 为
|
||||
`7566a54f86f3e4e0fee2096a49ea2877d827595575c7075bc44b65314cb2ba19`,离线审计 compatible 且 Docker 资源零残留;
|
||||
- 完整证据记录于 QL-RFC-0001 D-348;首份真实线上 closure 仍须由受保护 `v3` release tag 产生。
|
||||
@@ -443,6 +443,7 @@
|
||||
| [ADR-0437](./ADR-0437-post-publication-catalog-bound-local-release-gate.md) | 发布后 Catalog-bound Local Release Gate | Accepted(首份真实公开 catalog evidence 待实际 release tag) |
|
||||
| [ADR-0438](./ADR-0438-content-free-private-release-evidence-receipt-chain.md) | 内容无关的私有发布证据收据链 | Accepted(首份真实公开收据待实际 release tag) |
|
||||
| [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) |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
@@ -26,6 +26,14 @@ cert-manager 三项静态审计摘要。v2 收据不持久化私有 runner 的 w
|
||||
从私有 job 交给 release-set job,随后完整嵌入 release-set v3 并由 durable catalog 长期保护。公开收据同时声明
|
||||
`freshnessValidatedAtCreation=true` 与 `durableValidationClockPublished=false`,避免把未发布的临时时钟伪装成可离线重放的现场证据。
|
||||
|
||||
创建时通过不等于可以无限期等待再闭合发布。`cluster|all` 的 release-set aggregate 与紧随其后的 independent audit 会各自从 runner 内部取得当前
|
||||
时钟,并对两份收据公开的 `observedAt` 重新执行同一 24 小时最大年龄和五分钟未来偏差门;当前时钟没有 CLI 参数、环境变量或 durable JSON 字段。
|
||||
任一收据在闭合时已过期,release-set 文件会在写入、tag promotion 与 catalog publication 前失败关闭。`local` scope 没有私有收据,因此该门为
|
||||
`not_applicable`,不会把 Cluster 私有证据成本带到 Local 发布。
|
||||
|
||||
长期 catalog 的 standalone inspection 故意不以“今天的时钟”拒绝历史发布;它验证 receipt/release/source/self-digest 闭包,但诚实返回私有现场
|
||||
证据未重放。发布时 freshness 由受保护 workflow 的 aggregate/audit 与 provenance 约束,历史 consumer 不得把当前年龄检查冒充当时的现场验证。
|
||||
|
||||
## 发布流水线内置 Local 与 Cluster 下游门
|
||||
|
||||
`local|all` scope 在 durable catalog 发布后启动独立 `release-catalog-local-deployment-live`。它与 publisher 权限隔离,从公开 catalog
|
||||
|
||||
Reference in New Issue
Block a user