5.8 KiB
QingLong 3.0 镜像 OS 漏洞门
本流程覆盖 control|control-ai|admin|local|worker × amd64|arm64 十个 release candidate 的 OS/base image package,不替代 npm
production dependency audit、CycloneDX、BuildKit SBOM/provenance、Cosign 或 GitHub attestation。
日常检查
pnpm audit:image-os-vulnerability-policy:ql3
pnpm audit:image-release:ql3
pnpm audit:cluster-deployment:ql3
默认 exception policy 位于 deploy/containers/ql3-os-vulnerability-exceptions.json,当前必须返回:
{"schemaVersion":1,"fixture":"qinglong/image-os-vulnerability-exceptions@v1","compatible":true,"exceptionCount":0,"imageExceptionCounts":{"admin":0,"control":0,"local":0}}
真实 scan 在 QL3 CI 已有十个 native build 后执行;受保护 release 的十个 native job 各自只构建一次 OCI layout tar, Trivy 直接扫描该 tar。扫描成功后才解包、审计并上传同一 OCI graph;publisher 只合并 amd64/arm64 graph,不再 build。 只有六份 artifact 和 D-236 私密 evidence job 全部成功,publisher 才会启动。scanner/DB 网络故障与漏洞命中使用相同 的失败关闭结果,但日志会区分下载错误和 finding。
Build-once 发布链
每个 control|admin|local × amd64|arm64 native job 固定执行:
- Buildx 用 exact Dockerfile、source revision、SBOM 与 provenance 生成
${RUNNER_TEMP}/ql3-native/image.oci.tar; - Trivy 以
input扫描该 tar,禁止 daemon/candidate tag; - 扫描成功后解包到
layout/,repository recorder 复验 platform、source、SBOM/provenance 和全部 digest,写入evidence.json,随后删除 tar; - 以
run_id/run_attempt/image/arch唯一命名上传layout + evidence,保留 1 天且禁止 overwrite。
publisher 的固定顺序是:下载同一 run attempt 的两份 native artifact → 本地重验并确定性 merge → 生成最终 OS
vulnerability predicate → checksum 验证 regctl → 登录 GHCR → IMAGE@DIGEST import → 读取远端 digest 比对 →
Cosign/SLSA/CycloneDX/OS-vulnerability attest 与 verify → manifest/rollout verify → 最后创建 version 与完整 commit tag。
publisher 不得安装 Buildx/QEMU、运行 Dockerfile 或在 tag promotion 后追加 step。
创建短期例外
优先升级 digest-pinned Node base。只有当前没有可部署修复且风险被明确接受时,才能在 central JSON 的
exceptions 中增加一项:
{
"id": "CVE-2026-12345",
"images": ["admin", "control"],
"purls": ["pkg:deb/debian/libssl3@3.0.0-1"],
"owner": "security/platform",
"ticket": "QLSEC-123",
"expiresOn": "2026-08-15",
"rationale": "Temporary exposure accepted while the fixed base image is qualified."
}
约束:
- entries 按
id严格升序,ID 唯一;images/purls 各自唯一且升序; - 只接受
CVE-*与pkg:apk|deb|rpm,不能屏蔽 npm/library finding; expiresOn必须晚于 UTC 当天且最多 30 天,到期当天自动失败;- owner、ticket、rationale 缺一不可;ticket 必须先完成独立安全复核;
- 不得使用
ignore-unfixed=true、裸.trivyignore、skip path、allow-all Rego 或无期限 VEX 代替本策略。
提交前执行:
node --test test/back/ql3ImageOsVulnerabilityPolicy.test.cjs
node --test test/back/ql3ClusterImageReleaseAudit.test.cjs
pnpm audit:image-os-vulnerability-policy:ql3
pnpm audit:image-release:ql3
策略生成器会为每个 image 创建临时 .trivyignore.yaml;Trivy action 会把该低敏 exception view 显示在 job log。
不得在 rationale、owner 或 ticket 中写 credential、内部 URL、个人数据或 Secret。
升级 scanner 或基础镜像
- 阅读 Trivy 官方 release 与 security advisory,确认目标版本不在已知暴露窗口;
- 解析 signed/immutable action release 到完整 commit SHA,审查 composite action 的所有 nested action pin;
- 固定 scanner exact version,禁止
latest;保持 cache false、OS-only、unfixed 不忽略; - 对 Node base 的多架构 manifest digest 执行签名/来源核验;四个 production Dockerfile 的 runtime stage 必须同步更新 exact digest;
- 更新 ADR、静态审计 expectation 与 mutation tests;执行十个 native scan 后才能发布;
- 修复后删除已不需要的 exceptions,不等待
expiresOn。
失败恢复
- native job 失败或 artifact 未生成:重新运行整个 release;不要手工上传 artifact 或把旧 run artifact 改名复用;
- artifact/evidence/layout digest 不一致:视为供应链完整性失败,从 native build 重新开始,不通过重新打 tar 修复;
- regctl checksum 或下载失败:禁止回退到未固定 binary、
docker push或先推 candidate tag; - exact digest 已导入但证明/验证失败:不要创建 tag。保留 digest 用于调查,修复后由新 run 重建;
- tag promotion 失败:确认目标 tag 没有指向其他 digest;不得覆盖不一致 tag来“完成”发布;
- 清理 runner 时只删除该 job 的
${RUNNER_TEMP}/ql3-native、${RUNNER_TEMP}/native和 merge 输出,不能删除 workspace、D-236 owner-private source 或共享 Docker/Kind 资源。
当前证据边界
仓库已证明 policy、workflow、base pin、build-once/scanned-digest merge 和 fail-closed mutation contract。本机尝试
真实 OCI attested build 时,Docker container driver 获取 BuildKit SBOM scanner 遇到网络超时并已中止,临时目录已
删除,因此没有本地 live CVE clean 结论。首次 GitHub-hosted 六矩阵成功记录和首个 evidence-backed GHCR exact-digest
publish 仍属于外部 Release Gate。control/admin 的 exact Dockerfile 已在本机 arm64 成功构建并确认 10001:10001,
对应临时 image 随后已删除;这只证明 build/base pin,不替代漏洞数据库扫描。