feat(ql3): close public local release pair

This commit is contained in:
whyour
2026-08-27 14:51:33 +08:00
parent 238df17fdf
commit 78c261b556
31 changed files with 558 additions and 91 deletions
+3 -1
View File
@@ -11,11 +11,13 @@
最新增量证据(2026-08-27):
- D-412/ADR-0507(已实现,真实公开发布待受保护 tag):Public Local Release Set 从“只签 Application、用户旅程却依赖另一个未发布 operator”的断层收敛为一对分别构建、扫描、签名和 multi-arch attestation 的镜像:`local` 是唯一常驻 Application`local-operator` 只承担 setup/upgrade/recovery 等短生命周期 Owner authority。release candidate 的 Local scope 精确包含两者,并分别要求 Application Edge/Standalone rollout 与 operator `--version`/`setup --help` 门;CI OCI 证据、OS 漏洞策略、release-set、catalog consumption、final tag closure 和 Local selection 均按六镜像总闭包升级。`qinglong/release-set-image-record@v2``qinglong/release-set@v4``application/vnd.qinglong.release-set.v4+json``qinglong/local-compose-release-image@v3``qinglong/local-compose-image-selection@v3` 失败关闭旧孵化 schema。Compose revision 只保存 operator digest 作为管理 authority,不生成 operator service,所以路由设备稳态仍只有 Application,没有新增进程、listener、timer、端口或 RSS;管理动作才短暂下载/运行 operator。18-package clean build 退出 0package boundary 保持 18 packages、`singleSourcePackages=[]``shallowSourcePackages=[]`Local Owner CLI 为 301 total / 294 pass / 7 conditional skip / 0 failbackend 为 1,610 total / 1,608 pass / 2 conditional skip / 0 fail,静态 release workflow 审计 100/100。该切片证明发布机制闭合,不冒充已经存在 GHCR tag 或真实用户可下载 Public Release Set;首份正式可交付物仍需受保护 release tag 的六镜像、签名、catalog-bound Local/Cluster 部署证据和终态 closure。
- D-411/ADR-0506(已实现,真实 downloadable v2 artifact 待授权):Local Alpha materializer 不再凭调用 `create` 就把九个 gate 无条件写成 `passed`。bundle schema 升为 `qinglong/alpha-local-trial-kit@v2`,新增 `verification-evidence.json`,其 subject 精确绑定版本、source、Tier-1 架构与 Application/operator image IDworkflow 精确绑定 `whyour/qinglong/.github/workflows/ql3-ci.yml@refs/heads/next`、workflow SHA、`workflow_dispatch``local-image`、run ID/attempt。CI 静态门固定 `fresh journey → native cancellation → record-verification → create → audit → upload`,evidence 作为第七个闭合文件进入 manifest byte/SHA-256 与 `SHA256SUMS`create/audit 均拒绝跨源码、跨架构、跨镜像或跨 workflow 复制。旧 v1 bundle 因没有来源证明只保留为工程候选。提交 `4239464a` 的主 CI run `32990652047` 已 40/40Kubernetes run `32990652416` 与三节点 Security run `32990653482` 同源成功,证明源码的双架构门;但本地 `4239464a` v1 archive 不是 exact CI artifact,仍不能冒充 v2 用户 Alpha。该增强只增加一个小型发布期 JSON,不新增 workspace package、镜像 layer、设备依赖、常驻进程、RSS 或端口;首个真实双架构 v2 下载物仍需维护者显式授权 milestone workflow。
- Alpha 阶段产物历史基线(当前性已由 D-411 收紧):`QingLong 3.0 CI` 的显式 `produce_alpha_artifacts` 门只在手动里程碑运行中归档已经通过原生测试的镜像,而不把普通 push/PR 的中间构建冒充发布。source `e3c05862b8c2690d69f58b098cdc128a09c83f97` 已产出 Local arm64 Application Docker archiveSHA-256 `01afb30cbe0c21f980ca083ad98fd316e659941f940dd8930ffd9ccfa7153edf`image ID `sha256:dfce2cc9d70044d75f72f2cc3075e1f24569fb9fe279d9c25a45698c19c3bde9`)、CycloneDX SBOM、release-candidate contract、manifest、verification evidence 与 checksumimage identity/architecture/non-root user、read-only/no-network、128 MiB/0.5 CPU smoke、Edge/Standalone lifecycle/graceful stop/SQLite integrity、库存对账与 Trivy 0.70.0 HIGH/CRITICAL=0 已复验。但该 archive 只有 headless runtime,未携带完成 fresh setup/Owner 管理所需的独立 `ql3` 制品,因此按 D-408 重新准确分类为“运行时工程候选”,不再冒充完整用户 Alpha。macOS Docker Desktop 无法等价证明的 Local API cancellation 由原生 Linux arm64 job `97986754052` 通过;本机 Edge 首次 startup receipt 在 Docker Desktop 文件桥出现一次瞬态,精确重跑和原生 Linux门均通过,证据未隐藏首次失败。远端 CI run `32903679764` 首轮为 37/40(两项 GitHub action 内部 DNS 失败、一次 PostgreSQL 18 x64 scheduler 并发断言),failed-only attempt 2 收敛为 40/40;独立 Kubernetes deployment run `32903679644` 与三节点 Security Administration/CNPG/PVC run `32903679570` 同源成功。该证据保留为演进记录,不再代表当前 v2 Alpha bundle 资格;public GHCR digest、签名/attestation、catalog、deployment-lock 与生产 HA/DR/CSI/IdP 仍是 Public Release Set 的硬门。
- D-408/ADR-0503(进行中):阶段产物成熟度现在按真实部署用户旅程而非“已有 Dockerfile/镜像”裁决。新增独立 `qinglong3-local-operator` 短生命周期镜像,复用既有 `@qinglong/local-owner-cli` 的统一 `ql3` 入口而不新增 workspace package;它默认 `65532:65532`、无端口、无 listener/daemon/timer、network none,和常驻 Local Application 保持物理制品分离,因此 Owner/bootstrap authority 不进入 runtime closure,Edge 稳态资源零变化。本机基于未提交工作树构建的 arm64 operator 原型 ID 为 `sha256:115e90a7442b3c92db0c566f8fc8a560e689878b67eace0236836681a14689ae`,运行库存为 9 package/904 files/9,479,647 bytesread-only、drop ALL、no-new-privileges、128 MiB/0.5 CPU/32 PID 下的 `ql3 --version``ql3 setup --help` 已通过。这些数值只证明实现可构建,不冒充 commit-bound release evidence。Alpha workflow 将在同一原生 runner 上把 Application 与 operator 通过一次 `docker image save` 合并为去重的 `qinglong3-local-trial-kit-<arch>.docker.tar`manifest 同时绑定两个 image ID、共同 archive SHA-256、source/version/architecture,并从镜像入口完成 fresh setup exact replay、Identity provision、challenge、首 Owner claim/ack、Application active/SIGTERM drain 和 SQLite integrity。Docker Desktop bind mount 根目录会把宿主 UID 501 映射为容器 root、子文件仍为 501,不能等价满足完整 POSIX lineage;本机失败被记录为平台不等价,未放宽门禁或伪装通过。D-408 转 Accepted 仍需同一提交的原生 Linux x64/arm64 journey 成功和完整回归;实际上传双架构 trial kit 仍需维护者显式授权,Public Release Set 是否正式增加 operator artifact 另行决策。
- D-408/ADR-0503(进行中):阶段产物成熟度现在按真实部署用户旅程而非“已有 Dockerfile/镜像”裁决。新增独立 `qinglong3-local-operator` 短生命周期镜像,复用既有 `@qinglong/local-owner-cli` 的统一 `ql3` 入口而不新增 workspace package;它默认 `65532:65532`、无端口、无 listener/daemon/timer、network none,和常驻 Local Application 保持物理制品分离,因此 Owner/bootstrap authority 不进入 runtime closure,Edge 稳态资源零变化。本机基于未提交工作树构建的 arm64 operator 原型 ID 为 `sha256:115e90a7442b3c92db0c566f8fc8a560e689878b67eace0236836681a14689ae`,运行库存为 9 package/904 files/9,479,647 bytesread-only、drop ALL、no-new-privileges、128 MiB/0.5 CPU/32 PID 下的 `ql3 --version``ql3 setup --help` 已通过。这些数值只证明实现可构建,不冒充 commit-bound release evidence。Alpha workflow 将在同一原生 runner 上把 Application 与 operator 通过一次 `docker image save` 合并为去重的 `qinglong3-local-trial-kit-<arch>.docker.tar`manifest 同时绑定两个 image ID、共同 archive SHA-256、source/version/architecture,并从镜像入口完成 fresh setup exact replay、Identity provision、challenge、首 Owner claim/ack、Application active/SIGTERM drain 和 SQLite integrity。Docker Desktop bind mount 根目录会把宿主 UID 501 映射为容器 root、子文件仍为 501,不能等价满足完整 POSIX lineage;本机失败被记录为平台不等价,未放宽门禁或伪装通过。D-408 转 Accepted 仍需实际上传同一提交的原生 Linux x64/arm64 v2 trial kitPublic Release Set operator artifact 决策已由 D-412 接受,但不等于正式 release 已产生
- D-407/ADR-0502(已完成受审 Kubernetes live ceremony):Cluster API credential pepper 从“数据库保存 key ID、运行时却只有一个固定 material”收敛为最多 old/new 两代的显式 keyring。Security Administration 只用 active key 签发并持久化 exact IDCluster Control 按 credential record 精确选一把 key,未知 ID/material 一律 unavailable,绝不 fallback 或遍历,因此认证热路径仍为一次摘要。旧 raw pepper 只通过 `legacy-v1` singleton bridge 保持通用 CLI/进程兼容;Kubernetes Job 和常驻 Cluster Control manifest 已统一为 keyring-only,不再维护第二套单值 Secret 注入模式。新增 `pepper.references` 以数据库时间返回最多 64 个当前 latest active/unexpired credential ID 和 `hasMore`,只作为退休前检查,不执行删除。keyring 文件有 2 KiB、canonical/no-symlink/private/stable-read 边界,无 watcher/timer/新连接池;Edge/Standalone package、依赖与常驻资源零变化。远程 run `32893754795` 在 source `beb490c48c7d8ee4aee629924b5003fd8c73e9cb` 上完成 K3s `v1.34.3+k3s1` 三节点、CloudNativePG 1.30.0 三实例 PostgreSQL 18.4、三次真实双副本反亲和 rollout 和五次 `/api/v3` 认证 probeold/new 在 overlap 期间均认证成功并因无 Project role 返回 403,旧代引用从 1 收敛至 0contract 后 old 返回 401、new 仍返回 403;数据库保留 1 个旧代/3 个新代 credential version、四次授权拒绝与一次认证拒绝。首次远程失败还暴露了 no-symlink 运行时约束与 kubelet Atomic Writer 投影的架构冲突;最终部署用 hardened init container 固定解析一个 `..data` generation,将 CA/keyring 复制成 `0400` Pod-private 普通文件,常驻容器不再读取原始 symlink 投影。完整 backend 为 `1599 total / 1597 pass / 2 conditional skip / 0 fail`,治理/部署聚焦门为 88/88source `f8934b401d724378fe5a6ea9dbe63e696b5480b9` 的远程 CI run `32898407637` 为 40/40CloudNativePG failover、Plugin Package PostgreSQL OCI recovery、Secret rotation、Provider credential K3s/CNPG 等关键 live job 全部通过,独立 Kubernetes deployment run `32898407590` 同样通过。live 报告离线复审 `compatible=true/findings=[]`SHA-256 为 `d9e9fd1395adcef60f7f360959fcad27a9b2f0b132869bc1c75043dedd400ff6`。该门关闭应用合同与权限边界,不冒充生产 control-plane HA、跨主机 STONITH/DR、加密 CSI 或外部 ingress TLSmaterial GC、持久 active catalog、索引/大规模查询计划、远程 UI/API 与双人复核仍是后续门禁。
@@ -0,0 +1,65 @@
# ADR-0507Public Local Application 与 Operator 发布对
- 状态:Accepted(首份真实公开发布待受保护 tag)
- 日期:2026-08-27
- 决策:D-412
- 关联:ADR-0432、ADR-0437、ADR-0503、ADR-0506
## 背景
Local 用户的完整 3.0 旅程已经物理分离为常驻 Application 与短生命周期 operator。前者只运行 Edge/Standalone 数据面,后者通过统一 `ql3` 入口承担 setup、upgrade 和 recovery。Alpha Trial Kit 已同时携带两者,但正式 Public Release Set 仍只列出 Application。
这会产生不可接受的发布断层:受保护 workflow 可以签名并闭合一个无法独立完成 fresh setup 的“Local release”,操作者只能另找未被同一 source、catalog 和 tag closure 证明的管理镜像。把管理命令重新塞回常驻 Application 又会扩大低配路由器的攻击面和稳态资源闭包。
## 决策
### 1. Local family 是两个独立镜像的精确闭包
`local` scope 必须恰好包含:
- `qinglong3-local-application`:唯一常驻 Edge/Standalone service
- `qinglong3-local-operator`:只在显式管理动作期间运行的 Owner authority。
`all` scope 因此由 Local 两镜像和 Cluster 四镜像组成,共六个;`cluster` scope 仍为四个。两个 Local 镜像分别构建、执行双架构 OCI 证明、OS 漏洞门、digest 签名与 attestation,不能共享 digest record 或由其中一个代替另一个。
### 2. 角色验证必须显式记录
image record 升为 `qinglong/release-set-image-record@v2`。publisher 必须传入 candidate matrix 中的 exact `localRoleVerification`Application 为 `application_rollout_verified`operator 为 `operator_entrypoint_verified`Cluster 角色为 `not_applicable`。Application 必须完成 Edge/Standalone rolloutoperator 必须在 read-only、network none、drop-all、no-new-privileges、128 MiB、0.5 CPU、32 PID 边界内通过 `--version``setup --help`
release-set 升为 `qinglong/release-set@v4`OCI artifact/file media type 同步升为 `application/vnd.qinglong.release-set.v4+json`。旧孵化 schema 没有公开 3.0 消费者,因此失败关闭,不引入含糊的自动补全。
### 3. 目标选择绑定 operator,但不把它常驻化
Local catalog selection 升为 `qinglong/local-compose-release-image@v3`,必须同时绑定同一 owner、source 和 release-set 中的 Application/operator immutable digest。Compose revision 升为 `qinglong/local-compose-image-selection@v3`,保存 `operator_image` 作为 setup/upgrade/recovery authority,但 Compose service 仍只有 Application。
发布后的 Local gate 从公开 catalog 重建 selection,拉取并验证 operator 入口,再用 Application 完成 Edge 与 Standalone rollout。operator 不开端口、不运行 listener/daemon/timer,默认无网络;低配设备稳态不新增进程、RSS 或连接。
## 被拒绝的替代方案
### Public Release Set 只发布 Application
拒绝。它没有覆盖 fresh setup 的真实用户旅程,并迫使用户使用 catalog 外管理制品。
### 将 Owner CLI 合并回 Application
拒绝。它把高权限管理闭包带进每个常驻低配设备进程,破坏物理隔离。
### 把 operator 配置为 Compose sidecar
拒绝。管理 authority 没有常驻需求;sidecar 会无谓增加稳态资源和攻击面。
## 影响
- Local 发布和首次拉取最多多一个 operator image;只运行 Application 的稳态不变;
- setup/upgrade/recovery 可在动作完成后删除 operator layer,下一次按 selection digest 重新获取;
- catalog、finalizer 和回退 revision 都能证明两个 Local 角色来自同一 release
- 旧 v2 Local selection 与 Compose revision 失败关闭,孵化环境必须从 v4 catalog 重新物化;
- 该决策不产生真实 GHCR tag,也不把普通 CI artifact 声称为正式发布。
## 验证
- release candidate、record、set、catalog、publication closure 和 deployment-lock 正反向测试覆盖 `local=2``cluster=4``all=6`
- 普通 CI 对 operator 增加独立 multi-arch OCI layout、SBOM/provenance 和 image-scoped Trivy 证据;
- 受保护 release workflow 在 record 前验证角色,在 catalog consumption 后再次验证 operator 入口;
- Local Owner CLI 的 prepare、upgrade、rollback 和 adopted deployment fixtures 保留同一 operator digest
- 完整 backend、package boundary、Local Owner CLI 和静态 workflow 审计通过后才允许提交。
+1
View File
@@ -510,6 +510,7 @@
| [ADR-0504](./ADR-0504-canonical-local-alpha-trial-kit-materialization.md) | Local Alpha Trial Kit 单一物化与离线审计 | Accepted |
| [ADR-0505](./ADR-0505-pinned-alpine-openssl-runtime-security-patch.md) | 固定 Alpine OpenSSL 运行时安全补丁 | Accepted |
| [ADR-0506](./ADR-0506-source-bound-local-alpha-verification-evidence.md) | 源码绑定的 Local Alpha 验证证据 | Accepted |
| [ADR-0507](./ADR-0507-public-local-application-and-operator-release-pair.md) | Public Local Application 与 Operator 发布对 | Accepted(首份真实公开发布待受保护 tag) |
## 规则
+1 -1
View File
@@ -9,7 +9,7 @@
| Runtime Engineering Candidate | QingLong 开发者、设备兼容测试者 | 单个常驻镜像的 OS 漏洞策略、SBOM/库存、资源门和生命周期 | 验证 runtime 可加载、可启动;缺少管理制品时不能称用户 Alpha |
| Local Alpha Trial Kit | amd64/arm64 路由器、NAS、单机试用者 | 同源 Application + 短生命周期 operator、fresh setup/Owner/active/stop 完整旅程、SBOM/库存与资源门 | 一个去重 Docker archive 完成隔离 fresh 试运行;不承诺生产升级 |
| Cluster Integration Candidate | amd64/arm64 集群测试节点 | OS 漏洞策略、SBOM 与镜像库存复核、non-root identityAdmin 额外通过产品 facade smoke | 导入隔离 registry/测试节点,进行多组件集成;不作为 production HA release |
| Public Release Set | 生产用户 | 受保护 tag、镜像 multi-arch digest、签名/attestation、私有发布证据、catalog、Local/Cluster 部署与回退闭环 | 尚未实际发布;只能由受保护 release workflow 生成 |
| Public Release Set | 生产用户 | 受保护 tag、镜像 multi-arch digestLocal Application/operator + Cluster 四角色)、签名/attestation、私有发布证据、catalog、Local/Cluster 部署与回退闭环 | 尚未实际发布;只能由受保护 release workflow 生成 |
只有 `Local Alpha Trial Kit` 可以称为本阶段“用户可试运行产物”。单个 headless runtime 和 Cluster archive 都只是工程候选;后者还不满足正式 Kubernetes deployment-lock 的 GHCR immutable digest 与 catalog provenance。
+12 -9
View File
@@ -15,7 +15,7 @@ ghcr.io/<owner>/qinglong3-release-catalog:v<version>-<scope>
## 私有发布证据收据链
当前长期 authority 是 `qinglong/release-set@v3``local` scope 的 `evidenceReceipts` 必须为空;`cluster|all` 必须按顺序恰好包含
当前长期 authority 是 `qinglong/release-set@v4``local` scope 的 `evidenceReceipts` 必须为空;`cluster|all` 必须按顺序恰好包含
`worker-management``cloudnativepg-disaster-recovery` 两份 `qinglong/private-release-evidence-receipt@v2`。每份收据绑定同一
version/source tag/revision/scope、24 小时 freshness、私有报告 digest 和自身 digestDR 收据还绑定 CloudNativePG backup、Barman Cloud 与
cert-manager 三项静态审计摘要。v2 收据不持久化私有 runner 的 wall-clock:创建时仍必须以当前时钟完成 freshness gate,但 durable JSON 只绑定
@@ -23,7 +23,7 @@ cert-manager 三项静态审计摘要。v2 收据不持久化私有 runner 的 w
这些收据不包含原始生产报告、路径、credential、token、Kubernetes object 或 transcript。公开 consumer 可以重算收据和 release-set digest
但必须保持 `publicConsumerReplay=not_possible_without_private_reports`;它不能声称重放了私有现场结果。原始报告不上传,只有收据以 1 天 artifact
从私有 job 交给 release-set job,随后完整嵌入 release-set v3 并由 durable catalog 长期保护。公开收据同时声明
从私有 job 交给 release-set job,随后完整嵌入 release-set v4 并由 durable catalog 长期保护。公开收据同时声明
`freshnessValidatedAtCreation=true``durableValidationClockPublished=false`,避免把未发布的临时时钟伪装成可离线重放的现场证据。
创建时通过不等于可以无限期等待再闭合发布。`cluster|all` 的 release-set aggregate 与紧随其后的 independent audit 会各自从 runner 内部取得当前
@@ -42,8 +42,9 @@ attested 后写入。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
重新完成发现、Cosign/GitHub provenance 验证和 three-file bundle audit,随后物化唯一 Local v3 selection。该 selection 同时绑定常驻
Application 与短生命周期 operator,但不会把 operator 写成 Compose service。operator 先在无网络、只读、drop-all 和 128 MiB/0.5 CPU
边界内完成入口验证;随后同一个 immutable Application 与 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。
@@ -100,9 +101,9 @@ attestation 仍必须通过受保护 release tag 或受控 release repository
| 部署类型 | release scope | 必须出现的镜像 |
| --- | --- | --- |
| 低配路由器、Edge、Standalone | `local` | `local` |
| 低配路由器、Edge、Standalone | `local` | `local``local-operator` |
| Kubernetes/Cluster | `cluster` | `control``control-ai``worker``admin` |
| 同时发布两族 | `all` | 上述个镜像 |
| 同时发布两族 | `all` | 上述个镜像 |
Local 用户不需要下载 Cluster 镜像,也不依赖 CloudNativePG 或 Worker 私有发布证据。Cluster 运维者不能拿 Local
image 的证明替代任一角色镜像;尤其 Worker 与短生命周期 Admin 必须有各自 digest。
@@ -451,12 +452,12 @@ SHA-256`receipt.expectedDigest` 是 receipt 内的 `receiptDigest`。审计
1. 只接受已验证 Cosign exact workflow identity 与 GitHub source tag/revision provenance 的 catalog immutable
referencediscovery tag 无 authority。
2. materializer 只能接受完整 `qinglong/release-catalog-consumption-ceremony@v1` bundle,不能接受旧的松散 `--release-set`;其中
`qinglong/release-set@v3``release.version``release.sourceRef``release.sourceRevision``release.scope` 必须与变更单一致。
`qinglong/release-set@v4``release.version``release.sourceRef``release.sourceRevision``release.scope` 必须与变更单一致。
3. 镜像集合必须与上表精确相等;每个 `reference` 必须是 digest reference,且 owner/repository 与部署目标一致。
4. Local scope 必须为零私有收据;Cluster/All 必须精确包含两份同 source、同 scope、自摘要有效且 freshness 闭合的 content-free 收据。
static lock compatible 不等于现场证据已公开重放,任何 consumer 都必须保留该限制。
5. Kubernetes 必须先渲染 overlay,再用离线 post-render materializer 生成和复验 v2 locked manifest;嵌套 overlay 的
`newName`/digest 不是最终 authority。Local 必须生成并审计 v2 service selection。两族输出都必须绑定同一 catalog manifest、
`newName`/digest 不是最终 authority。Local 必须生成并审计 v3 Application/operator selection。两族输出都必须绑定同一 catalog manifest、
consumption report 与 release-set digest,并且只能消费 release set 中的 `@sha256:` reference。
6. rollout 前再次确认 catalog receipt/immutable reference 与已检查文件一致。Kubernetes 必须把 locked manifest/report、pinned
kubectl/kubeconfig 和目标 cluster UID 绑定进 preflight/apply receiptversion/source/catalog tag 都只能用于发现,部署始终以
@@ -466,7 +467,9 @@ SHA-256`receipt.expectedDigest` 是 receipt 内的 `receiptDigest`。审计
路由器或其他低配 Edge 设备不需要安装 Node、regctl、Cosign、GitHub CLI、Kustomize 或 materializer。维护者在可信工作站
完成上述 ceremony 和 Local v2 selection 审计,再向设备传输已检查的 catalog-bound canonical JSON,并只把 `local` family 的
immutable image reference 写入 compose/rollout。
immutable Application image reference 写入 compose/rollout。operator 镜像只在 setup、upgrade、recovery 等显式管理动作期间按 digest 拉取并短暂运行;
它没有 listener、timer 或常驻 service,因此设备稳态仍只有 Application。设备不执行管理动作时可以不保留 operator layer,但每次管理动作必须先验证
selection 中的 exact operator digest,不能用 Application 入口或宿主 Node 代替。
设备不下载 Cluster 四镜像,也不加载 Kubernetes、CloudNativePG、PostgreSQL driver 或 Worker 私有发布证据。
如果设备本身不运行容器 registry client,可由工作站按 digest 拉取并通过既有离线交付渠道传送镜像;离线包的哈希与