# ADR-0254:Digest 固定的跨架构 OS 漏洞发布门
> ADR-0255 supersedes 本 ADR 决策 5 中 release candidate 到 publisher 的传输方式:release 现在 build once、扫描
> exact OCI layout tar,并按同一 audited digest 发布。本 ADR 的 base pin、Trivy pin、OS-only gate 与例外治理继续有效。
- 状态:Accepted(base pin、策略审计器、CI/release 接线与负向测试已实现;联网六矩阵扫描记录待取得)
- 日期:2026-08-01
- 关联 RFC:QL-RFC-0001 D-14、D-61、D-128、D-186、D-236、D-237
- 关联 ADR:ADR-0128、ADR-0195、ADR-0196、ADR-0253
## 背景
QingLong 3.0 已对 npm production graph 执行 high/critical advisory gate,但这不覆盖 Debian/base image OS package。
同时 control/admin Dockerfile 仍通过可覆盖的 `ARG NODE_IMAGE` 引用 tag,而 local image 已固定多架构 digest;即使
对某次本地 build 扫描通过,后续 build 也可能解析到另一份基础镜像。
Trivy 官方在 2026-03 披露过 action/tag 与部分二进制发布渠道被篡改的供应链事件,并明确要求 action 使用完整
commit SHA。D-237 不能用 movable `@v0.x` 或 `latest` 引入一个拥有 workflow 执行能力的 scanner。
## 决策
1. control、admin、local 的 build/runtime stage 统一固定
`node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d`。
control/admin 删除 `ARG NODE_IMAGE`,不得允许 build arg 覆盖 base;三个镜像继续拥有独立 Dockerfile、应用闭包和
最终 image digest。
2. scanner 固定为 Trivy `v0.70.0`,GitHub Action 固定完整 commit
`ed142fd0673e97e23eac54620cfb913e5ce36c25`(action `v0.36.0`)。禁止 tag、`master`、`latest`、
`continue-on-error` 和 scanner cache;网络、release asset 或 vulnerability DB 不可用均失败关闭。
3. 只扫描 `vuln-type=os`、`scanners=vuln`、severity `HIGH,CRITICAL`,`ignore-unfixed=false`、exit code 1。
npm/library advisory 继续由既有 production dependency audit 独立负责,不能用 OS 例外隐藏应用依赖漏洞。
4. `.github/workflows/ql3-ci.yml` 复用已经存在的 native build:control/admin 各 amd64+arm64,local
amd64+arm64,共六个真实本地 image。每个 build 后生成 image-scoped ignore view 并执行 Trivy。
5. release workflow 增加独立只读 `os-vulnerability` 六矩阵 job,在发布前用 exact Dockerfile、base digest、lock 和
source revision 构建 native candidate。`publish` 必须同时依赖 D-236 private evidence 与全部 OS scan 成功,
才能获得 GHCR/OIDC/attestation 写权限。scan job 不读取 D-236 私密 source,不参与签名或 publish。
6. 唯一例外事实源为 `deploy/containers/ql3-os-vulnerability-exceptions.json`。顶层和每条 entry 都是 exact shape;
每条必须包含唯一且排序的 CVE、非空且排序的 `admin|control|local` image 集合、非空且排序的
`pkg:apk|deb|rpm` purl、owner、ticket、20–512 字理由和未来到期日。
7. 例外最多 128 条,单条例外最长 30 天;到期当天即无效。策略审计器为每个 image 生成临时 `0600`、no-replace
`.trivyignore.yaml`,映射为 Trivy 官方 `id+purls+expired_at+statement`。不得直接维护 `.trivyignore`、全局 CVE ID、
path skip、Rego allow-all、VEX bypass 或无期限 exception。
8. 当前 production policy 为 `exceptions=[]`。新增例外必须先关联安全 ticket、指定责任 owner、确认 package purl 与
受影响 image、设置最短到期日,并通过变异测试;修复 base 后立即删除,不等待到期。
9. scanner、生成器、策略和 workflow 都是 repository/release-time 工具,不新增 workspace package、第三方 runtime
dependency、migration、daemon、controller、timer、watcher、listener、Pool 或 Profile 常驻资源。
## 失败与恢复
- base digest/tag/action/version 漂移:静态审计失败,先审查上游 release 与签名,再显式更新 ADR/测试;
- scanner 或 DB 下载失败:CI/release 失败,不回退到旧 DB、不跳过扫描;
- HIGH/CRITICAL 命中且无例外:升级基础镜像/OS package;只有短期无法修复时才按本 ADR 添加 exception;
- exception 到期、超过 30 天、缺 owner/ticket/rationale、使用 library purl 或 image scope 为空:policy gate 失败;
- 一个架构构建/扫描失败:整个 `os-vulnerability` matrix 不满足,三个 publisher 都不得启动;
- 本地临时 scanner 下载超时:只能记录“未取得本地 live scan”,不能把静态契约或 checksum 预检记为漏洞通过。
## 被拒绝的替代方案
### 发布后扫描 GHCR digest
拒绝。HIGH/CRITICAL 被发现前 tag/manifest 已进入 registry;发布前 native candidate scan 才能阻止写入。
### 只扫描 amd64
拒绝。多架构 base 的 OS package/config 可能不同,amd64 结果不能证明 arm64 路由器/节点镜像。
### `ignore-unfixed=true`
拒绝。它把所有无修复漏洞变成隐式永久例外;D-237 要求每个例外有 scope、owner、ticket、理由和到期日。
### 直接提交 `.trivyignore.yaml`
拒绝。Trivy 的 `statement` 不参与过滤,且原生 schema 不要求 owner、ticket、最长周期或 image scope;仓库级严格
策略生成 image-specific view 可以补足这些治理约束。
### 用 action tag 或 scanner `latest`
拒绝。上游供应链事故已证明 tag 可被重写;完整 action commit 与 exact scanner version 是最低可接受边界。
## 验证
- OS exception policy 8/8:empty、image scope、purl、owner/ticket/rationale、expired/same-day/>30 天、排序/重复、
`0600` no-replace 与 exact CLI;
- image release contract 34/34:新增覆盖 CI/release action pin、六矩阵、publish dependency、unfixed、OS-only、
cache 与既有签名/SBOM/provenance 门;
- Cluster deployment 31/31,包含 control/admin mutable/overridable base 负向测试;
- 本机 arm64 exact Dockerfile build 已通过:control `sha256:58ca2905c6489d3051663804f07adb0ea24dce734cc96863f882c8e5cb73579c`、
admin `sha256:79f8eda7194cf63669ba144917eabecd11faa0546858ac1feb7ee52ccffc5f27`,均为 arm64、
`10001:10001`;验证 image 已删除;
- `audit:image-release:ql3` 返回 Trivy 0.70.0、exact action commit、amd64/arm64、OS-only、HIGH/CRITICAL、
`ignoreUnfixed=false`、maximum exception 30 days;
- 当前 policy `exceptionCount=0`;workspace 保持 19 个 package,无新增 runtime dependency。
## 上游依据
- Trivy filtering 与 YAML `id/purls/expired_at/statement`:;
- Trivy ecosystem supply-chain advisory:;
- Trivy Action v0.36.0:。