ci(retag/deploy): 增加镜像内容校验,防止静默部署旧/损坏镜像 #1569

Merged
xiaoxia merged 1 commits from ci/image-content-verification into develop 2026-08-31 13:07:43 +08:00
Owner

目标

防止 retag 步骤静默复用旧镜像后部署了损坏/过期代码。

变更

retag_skipped_image.sh 加固

  • 源镜像 layers 有效性检查(layers=0 拒绝 retag)
  • 镜像创建时间审计(>72h 输出警告)
  • digest 审计记录

ci_staging_deploy.sh 加固

  • pull 后逐服务校验镜像 layers 有效性
  • 记录每个镜像的 digest/size/created
  • 对比上次部署 manifest,标注变化状态
  • 写入 deploy-manifest.json 供下次对比
  • 校验失败直接阻断部署

不改动

  • concurrency 保持 cancel-in-progress: true
  • 生产发版链路不动
## 目标 防止 retag 步骤静默复用旧镜像后部署了损坏/过期代码。 ## 变更 ### retag_skipped_image.sh 加固 - 源镜像 layers 有效性检查(layers=0 拒绝 retag) - 镜像创建时间审计(>72h 输出警告) - digest 审计记录 ### ci_staging_deploy.sh 加固 - pull 后逐服务校验镜像 layers 有效性 - 记录每个镜像的 digest/size/created - 对比上次部署 manifest,标注变化状态 - 写入 deploy-manifest.json 供下次对比 - 校验失败直接阻断部署 ## 不改动 - concurrency 保持 cancel-in-progress: true - 生产发版链路不动
xiaoxia added 1 commit 2026-08-31 12:01:36 +08:00
ci(retag/deploy): 增加镜像内容校验,防止静默部署旧/损坏镜像
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 3m58s
CI/CD Pipeline / Check push changed paths (push) Successful in 4m19s
CI/CD Pipeline / Build Staging Web Image (push) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m22s
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 4m43s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 5m5s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 5m15s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 5m18s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 2m51s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m7s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 3m9s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m57s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m18s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 8m31s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m23s
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 2m28s
AI Code Review / AI Code Review (pull_request) Successful in 11m10s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Successful in 2m23s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / Integration Tests (push) Successful in 4m31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m32s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m23s
CI/CD Pipeline / Unit Tests (push) Successful in 17m40s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Successful in 5m1s
f7693baeae
retag_skipped_image.sh 加固:
- 源镜像 layers 有效性检查(layers=0 拒绝 retag)
- 镜像创建时间审计(>72h 输出警告)
- digest 审计记录,方便溯源

ci_staging_deploy.sh 加固:
- pull 后逐服务校验镜像 layers 有效性
- 记录每个镜像的 digest/size/created
- 对比上次部署 manifest,标注变化状态
- 写入 deploy-manifest.json 供下次对比
- 校验失败直接阻断部署

concurrency 保持 cancel-in-progress: true(不变)
生产发版链路不动
Collaborator

代码审查结果 - PR #1569

⚠️ 问题(2个需要修改)

  1. scripts/ci_staging_deploy.sh 第311-315行:生成的 JSON 格式错误,存在尾随逗号。代码在循环内无条件追加逗号,导致生成的 deploy-manifest.json 中最后一个元素 "web_layers" 后带有逗号,这在 JSON 标准中是非法的。如果后续步骤使用 jq 或其他 JSON 解析器读取该文件,将会解析失败。
  2. scripts/ci_staging_deploy.sh 第297行:解析 Manifest 的正则表达式逻辑错误。使用 sed 's/.*: *"\(.*\)".*/\1/' 提取 ID 时,如果上一次的 manifest 是压缩的单行 JSON(例如 {"api_id": "sha256:abc", "web_id": "sha256:def"}),该正则会贪婪匹配,提取出 abc", "web_id": "sha256:def",导致 ID 对比逻辑失效,每次都会误判为 "changed"。

💡 建议(1个可选)

  1. scripts/ci/retag_skipped_image.sh 第59行date -d 是 GNU date 特有语法,在 macOS 等环境会报错。虽然 CI 环境通常是 Linux,但为了脚本健壮性,建议检查 date 版本或使用兼容性更好的处理方式(如 Python 脚本处理时间)。

格式检查通过 | 逻辑审查需修改 | 性能无明显问题


🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 04:06:59 | 模型:

## 代码审查结果 - PR #1569 ### ⚠️ 问题(2个需要修改) 1. **scripts/ci_staging_deploy.sh 第311-315行**:生成的 JSON 格式错误,存在尾随逗号。代码在循环内无条件追加逗号,导致生成的 `deploy-manifest.json` 中最后一个元素 `"web_layers"` 后带有逗号,这在 JSON 标准中是非法的。如果后续步骤使用 `jq` 或其他 JSON 解析器读取该文件,将会解析失败。 2. **scripts/ci_staging_deploy.sh 第297行**:解析 Manifest 的正则表达式逻辑错误。使用 `sed 's/.*: *"\(.*\)".*/\1/'` 提取 ID 时,如果上一次的 manifest 是压缩的单行 JSON(例如 `{"api_id": "sha256:abc", "web_id": "sha256:def"}`),该正则会贪婪匹配,提取出 `abc", "web_id": "sha256:def"`,导致 ID 对比逻辑失效,每次都会误判为 "changed"。 ### 💡 建议(1个可选) 1. **scripts/ci/retag_skipped_image.sh 第59行**:`date -d` 是 GNU date 特有语法,在 macOS 等环境会报错。虽然 CI 环境通常是 Linux,但为了脚本健壮性,建议检查 `date` 版本或使用兼容性更好的处理方式(如 Python 脚本处理时间)。 --- ✅ 格式检查通过 | ❌ 逻辑审查需修改 | ✅ 性能无明显问题 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 04:06:59 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->

🚀 预览环境已部署

项目 详情
PR号 #1569
预览链接 https://pr-1569.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1569 | | 预览链接 | [https://pr-1569.preview.xiaoxiajianji.com](https://pr-1569.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
xiaoxia merged commit f7693baeae into develop 2026-08-31 13:07:43 +08:00

🗑️ 预览环境已清理

PR #1569 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1569 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.