From 687d7cc1317b1ba9ab640cae2a413abf2f41e772 Mon Sep 17 00:00:00 2001 From: v6ole Date: Tue, 28 Jul 2026 17:03:13 +0800 Subject: [PATCH] ci(security): add SBOM scan and release evidence --- .gitlab-ci.yml | 33 +++++++++++++++++++++- README.md | 2 +- docs/发布与回滚检查表.md | 53 ++++++++++++++++++++++++++++++++++++ 整改计划-中国电信研发规范.md | 5 ++-- 4 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 docs/发布与回滚检查表.md diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e3e85a4..c630eb5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,9 +9,15 @@ backend_verify: - pip install --no-cache-dir -r backend/requirements.txt pytest ruff bandit pip-audit - PYTHONPATH=backend python -m compileall -q backend/app - ruff check backend/app backend/tests - - PYTHONPATH=backend pytest -q backend/tests + - PYTHONPATH=backend pytest -q backend/tests --junitxml=backend-test-report.xml - bandit -q -r backend/app -lll - pip-audit -r backend/requirements.txt + artifacts: + reports: + junit: backend-test-report.xml + paths: + - backend-test-report.xml + expire_in: 180 days frontend_build: stage: build @@ -20,3 +26,28 @@ frontend_build: - cd frontend - npm ci - npm run build + artifacts: + name: "qiji-frontend-$CI_COMMIT_SHORT_SHA" + paths: + - frontend/dist/ + expire_in: 30 days + +backend_sbom: + stage: verify + image: python:3.12-slim + script: + - pip install --no-cache-dir cyclonedx-bom + - python -m cyclonedx_py requirements backend/requirements.txt --output-reproducible --of JSON -o sbom-backend.cdx.json + artifacts: + name: "qiji-sbom-$CI_COMMIT_SHORT_SHA" + paths: + - sbom-backend.cdx.json + expire_in: 180 days + +filesystem_security: + stage: verify + image: + name: aquasec/trivy:0.67.2 + entrypoint: [""] + script: + - trivy fs --exit-code 1 --ignore-unfixed --severity HIGH,CRITICAL --scanners vuln,misconfig,secret . diff --git a/README.md b/README.md index a405e5f..474c1ad 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ |---|------| | 后端 | FastAPI + SQLAlchemy 2.0 (async) + asyncpg | | 数据库 | PostgreSQL | -| 文件存储 | MinIO (预签名直传) | +| 文件存储 | MinIO(后端受控图片上传) | | 认证 | Casdoor OIDC + JWT | | 前端 | Vue 3 + Vite + TypeScript + Element Plus | | 状态管理 | Pinia | diff --git a/docs/发布与回滚检查表.md b/docs/发布与回滚检查表.md new file mode 100644 index 0000000..3d0c0df --- /dev/null +++ b/docs/发布与回滚检查表.md @@ -0,0 +1,53 @@ +# 企迹系统发布与回滚检查表 + +> 每次生产发布由发布负责人逐项勾选,并将结果随变更单、流水线和制品一并归档。 + +## 1. 发布前 + +- [ ] 变更已合并至受保护分支,MR 审核记录完整。 +- [ ] 已创建发布 Tag,记录提交 SHA、镜像摘要和发布日期。 +- [ ] CI 全部通过:后端测试、前端构建、Ruff、Bandit、依赖漏洞审计、SBOM、Trivy 文件系统扫描。 +- [ ] 已归档 `sbom-backend.cdx.json`、测试报告和扫描报告。 +- [ ] 生产密钥由受控环境或密钥管理系统注入,未写入 Git、镜像层或发布记录。 +- [ ] 数据库已完成备份,并验证备份可读取;回滚负责人和窗口已确认。 +- [ ] 对象存储桶为私有,应用服务账号采用最小读写权限。 + +## 2. 数据库迁移 + +在维护窗口、使用生产应用运行身份执行: + +```bash +cd /path/to/qiji/backend +alembic current +alembic upgrade head +alembic current +``` + +- [ ] `alembic current` 显示预期修订版本。 +- [ ] 核验 `users.wecom_userid` 的唯一索引已创建。 +- [ ] 如迁移失败,停止发布;不得通过手工修改表结构绕过迁移记录。 + +## 3. 发布与验证 + +- [ ] 使用指定 Tag/镜像摘要部署;禁止直接从未审核工作区运行。 +- [ ] 服务以受控进程或编排平台运行,未使用开发热重载。 +- [ ] 仅反向代理对公网开放 HTTPS;数据库、缓存、MinIO 管理端口不对公网监听。 +- [ ] 健康检查通过:`GET /health`。 +- [ ] 回归登录、角色授权、企微绑定、受控图片上传和图片下载授权。 +- [ ] 抽查应用日志,确认未输出口令、密钥、令牌或用户输入正文。 + +## 4. 回滚 + +触发条件:迁移失败、健康检查失败、关键业务回归失败、出现高危安全告警。 + +1. 停止本次发布流量切换,恢复上一稳定版本的镜像/制品。 +2. 仅在已验证可逆且有审批的情况下执行 `alembic downgrade`;基线迁移不允许通过盲目降级删除历史表。 +3. 如数据不兼容,按已验证的备份恢复方案处理,并保留操作审计。 +4. 复测健康接口和关键业务,记录故障、影响范围、回滚时间和后续整改项。 + +## 5. 发布归档 + +- [ ] 变更单与审批记录 +- [ ] Git Tag、提交 SHA、镜像摘要和 SBOM +- [ ] 测试、扫描、迁移和部署日志 +- [ ] 上线验证与回滚演练记录 diff --git a/整改计划-中国电信研发规范.md b/整改计划-中国电信研发规范.md index d5d7893..f7e4ac1 100644 --- a/整改计划-中国电信研发规范.md +++ b/整改计划-中国电信研发规范.md @@ -17,7 +17,8 @@ | 管理配置鉴权 | 已完成 | 系统配置列表接口仅允许 director 访问 | | 上传与日志基础防护 | 已完成(仓库侧) | 上传经后端校验尺寸与图片内容、重编码为 JPEG 后才写入私有对象存储;回调和认证失败日志不再写入正文/token | | 企微绑定令牌持久化 | 已完成(仓库侧) | 一次性令牌存入数据库并原子消费;通过 Alembic 迁移创建企微 ID 的部分唯一索引,防止重复绑定 | -| 测试与构建流水线 | 已完成(仓库侧) | 增加上传、配置和 JWT 安全 API 测试;CI 执行编译、Ruff 致命错误检查、pytest、高危 Bandit 扫描、依赖漏洞审计和前端构建 | +| 测试与构建流水线 | 已完成(仓库侧) | 增加上传、配置和 JWT 安全 API 测试;CI 执行编译、Ruff 致命错误检查、pytest、高危 Bandit 扫描、依赖漏洞审计、SBOM、Trivy 文件系统扫描和前端构建,并归档测试报告、SBOM 与前端制品 | +| 发布与回滚材料 | 已完成(仓库侧) | 新增 `docs/发布与回滚检查表.md`,明确迁移、发布验证、回滚触发条件和归档清单 | | 可追踪数据库变更 | 已完成(仓库侧) | 新增 Alembic 基线迁移;容器启动先执行 `alembic upgrade head`,不再由应用启动时直接改表 | | 企微回调解析与 JWT 依赖加固 | 已完成(仓库侧) | 使用 defusedxml 解析回调、cryptography 解密、常量时间签名比较;移除存在无修复传递漏洞的 `python-jose`/`ecdsa` 依赖 | | 清理禁止的二进制文件 | 已完成 | 移除仓库根目录两份 `.xlsx` 模板;系统仍可由导入模板接口动态生成模板 | @@ -31,7 +32,7 @@ | P1 | 在生产环境接入恶意内容扫描,并确认对象存储桶策略不允许匿名读取 | 后端/安全 | 上线前 | 扫描日志、桶策略和抽样验证 | | P1 | 在生产数据库执行 Alembic 迁移,验证 `users.wecom_userid` 唯一索引创建成功,并完成并发绑定演练 | 后端/DBA | 上线前 | 数据库迁移日志、并发绑定测试、令牌过期与审计记录 | | P1 | 配置保护分支、MR 至少一名评审、禁止直接推送 `main`/`develop` | Git 平台管理员 | 2 个工作日 | 平台截图/导出配置、MR 审计记录 | -| P2 | 补充 SBOM 和容器镜像扫描,并将高危结果设为流水线阻断条件 | DevSecOps | 5 个工作日 | 流水线报告、阻断规则、漏洞例外审批 | +| P2 | 在 GitLab 运行并验收 SBOM、Trivy 文件系统/镜像扫描;补充许可证扫描并将高危结果设为流水线阻断条件 | DevSecOps | 5 个工作日 | 流水线报告、阻断规则、漏洞例外审批 | | P2 | 扩展鉴权、对象访问、企微绑定、文件上传的 API 集成测试覆盖,并明确测试准入/准出及缺陷闭环 | 测试/后端 | 5 个工作日 | 测试计划、用例、报告、缺陷清单 | | P2 | 准备生产发布包:Tag、制品摘要、SBOM、测试报告、变更单、备份与回滚方案、上线验证用例 | 项目经理/运维 | 每次发布 | 发布审批记录和可回放部署记录 |