8.9 KiB
CMPP 平台代码质量整改执行结果
- 执行日期:2026-08-28
- 对应方案:
docs/code-quality-remediation-plan-20260828.md - 本地分支:
main - 测试环境:
100.93.204.60 - 测试环境最终业务代码:
fc4a6a7afcfc3c1c11d1e353f46d5b724f48a39e - 环境边界:本轮只修改和部署测试环境;未访问、覆盖、回退或部署预生产
1. 结论
本轮已经关闭两个 P0,并完成可信租户上下文、强密码哈希、旧哈希透明迁移、Redis 验证码/锁定、重点写接口 DTO 校验、依赖升级、覆盖率和包体门禁、路由分包、ECharts 按需加载、数据库配置 fail closed、mock 类型解耦及仓库缓存治理。最终代码已部署到测试环境,95 项迁移全部一致,11 项相关服务 active,API/Gateway 健康,Redis 回执结果 Stream pending=0、lag=0,发布后核心服务 error 级日志为 0。
本轮没有把“完整治理方案”中的长期重构和全业务链复验冒充已完成:两个超大 SendChain Service 未做高风险机械拆分;未重新发送短信、执行压力测试或改动 MinIO 业务对象;浏览器完成登录页真实渲染和控制台检查,但没有在本轮自动输入测试密码和验证码完成登录后页面验收。这些项目不影响本次 P0 关闭和已发布代码运行,但仍属于后续专项验收范围。
2. 已实施变更
2.1 租户隔离
- 会话校验从数据库读取用户
tenantId,客户端请求只使用服务端可信上下文。 - 客户端缺少租户时直接拒绝;
x-tenant-id仅做一致性检查,不再决定授权范围。 - 请求头伪造租户返回
403 / CLIENT_TENANT_MISMATCH并写安全事件。 - 客户端认证、删除治理、Open API、风险审核、发送链、运营日志、短信配置、账务及用户接口均改用可信租户。
- 客户端创建请求中的
tenantId、operatorId、createdById不再作为可信身份字段;服务端覆盖或严格拒绝。 - 应用参数、状态、密钥等按资源 ID 的操作补充租户复合范围。
测试环境双租户真实 API 结果:
| 场景 | 结果 |
|---|---|
| 当前租户且不带租户请求头 | 通过 |
| 当前租户且请求头一致 | 通过 |
| 请求头伪造其他租户 | 403 CLIENT_TENANT_MISMATCH |
| 请求体提交其他租户 ID | 被服务端强制归属当前租户 |
| 访问其他租户应用资源 ID | 404 |
2.2 密码哈希
- 使用 Node 标准库 scrypt,格式包含版本、
N=32768/r=8/p=1、独立 16 字节随机 salt 和摘要。 - 验证使用恒定时间比较,并限制可接受参数范围。
- 创建用户、改密、重置密码、生产管理员维护工具和真实环境 smoke 工具只写强哈希。
- 旧 64 位 SHA-256 继续只读兼容;正确密码登录后使用条件更新透明升级,错误密码不迁移。
- 首次发布使用最长 2 小时的受限兼容窗口,建立第二份恢复资产后移除兼容写入环境变量并重启 API;最终配置和 API 进程均无
PASSWORD_HASH_LEGACY_*。 - 测试环境创建一次性旧 SHA-256 测试账号,经真实验证码和客户端登录接口成功迁移为 scrypt,随后硬删除;收尾
@integration.invalid活跃账号为 0。 - 测试环境仍有 4 个未登录的历史 SHA-256 账号,按透明迁移策略保留;本次没有改写未知用户密码。
2.3 登录状态与输入校验
- 验证码迁移到 Redis TTL,并用
GETDEL原子消费。 - 匿名失败计数使用哈希化 key 和 Lua 原子
INCR/EXPIRE,连续 5 次失败锁定 24 小时,成功登录清理计数。 - Redis 不可用时 fail closed,不再退回进程内无界 Map。
- 认证和高风险客户端写接口启用
transform / whitelist / forbidNonWhitelisted严格校验;额外身份字段会被拒绝。
2.4 依赖、性能和工程门禁
react-router-dom/react-router升级到7.18.2,NanoID 解析固定到3.3.18;根生产依赖审计为 0。- 全部页面改为
React.lazy路由级加载,新增统一加载/失败/重试边界。 - ECharts 改为 core、chart、component、canvas renderer 按需注册。
- 初始入口 JavaScript gzip 从审计基线约 626 KiB 降至约 107.38 KiB;图表异步块约 181.64 KiB,按首轮实测将单块预算校准为 190 KiB,入口预算 250 KiB。
- API 覆盖率门槛建立为 statements 59%、branches 50%、functions 60%、lines 62%;本轮实际分别为 69.77%、53.47%、71.08%、73.05%。
- 新增门禁禁止生产页面导入 mock、禁止客户端可信租户回退、禁止密码写工具使用裸 SHA-256、检查依赖版本和 bundle budget。
- 生产/测试环境缺少
DATABASE_URL时 fail closed;开发和测试模式才允许显式本地默认值。 auditColumns业务类型移出 mock;停止跟踪api/tsconfig.build.tsbuildinfo并补充缓存/产物忽略规则。AdminDownstreamDeliveriesPage的展示和详情辅助逻辑已拆出。两个 SendChain 超大 Service 本轮不做无业务收益的高风险拆分,保留到专门重构任务。
3. 自动化验证
| 门禁 | 结果 |
|---|---|
| API Jest | 47/47 套、542/542 项通过 |
| API 覆盖率 | 69.77 / 53.47 / 71.08 / 73.05,全部超过门槛 |
| API TypeScript 正式构建 | 通过 |
| 前端 TypeScript | 通过 |
| Vite 正式构建 | 通过 |
| bundle budget | 通过 |
Gateway go test ./... -count=1 |
通过 |
Gateway go vet ./... |
通过 |
| Prisma validate / migration | 通过,测试环境 95/95 |
| Gateway 队列契约 | 5/5 通过 |
| 代码质量/安全部署门禁 | 通过 |
| 根生产依赖审计 | 0 vulnerabilities |
git diff --check |
通过 |
API 子项目安装仍报告其依赖树中的 9 项公告(2 moderate、7 high),但原审计明确列出的 React Router 和 NanoID 两项已关闭,现有依赖缓解门禁通过。本轮没有为了追求审计数字盲目升级可能破坏 Prisma/Nest 兼容性的主版本;剩余公告应另行建立升级兼容矩阵。
4. 测试环境发布与恢复资产
密码格式具有单向迁移属性,因此采用两阶段发布:先发布能同时读取新旧格式且只允许受限兼容写入的版本,确认新格式写路径后重新建立恢复资产,再关闭兼容写入并发布最终版本。
| 恢复点 | 用途 |
|---|---|
/opt/cmpp-platform-backups/code-quality-before-d85ff859-20260828T035007Z |
首次兼容发布前,旧部署 0b843702... |
/opt/cmpp-platform-backups/code-quality-compatible-d85ff859-20260828T035426Z |
兼容版本稳定后 |
/opt/cmpp-platform-backups/code-quality-before-fc4a6a7-20260828T040150Z |
最终强哈希发布前 |
三份恢复点均包含 PostgreSQL custom dump、运行目录、配置、Redis RDB、MinIO 数据、服务/监听/Stream 状态、回退说明和 SHA256SUMS;pg_restore --list、tar 目录读取、Redis RDB 和摘要校验通过。最终发布包:
outputs/cmpp-code-quality-fc4a6a7-20260828-120252.tar.gz- SHA-256:
7b025b31d2964e290b20104f83532ef4613929574bc3d790d584e433273841be - 955 个归档条目
5. 发布后验收
- 部署标记:
fc4a6a7afcfc3c1c11d1e353f46d5b724f48a39e。 - PostgreSQL:源码迁移 95,数据库完成迁移 95。
- 服务:MinIO、Security Agent、Submit Outbox、Gateway Callback、Protocol Log Worker、Gateway、API、Send Worker、Nginx、Redis、PostgreSQL 共 11 项 active。
- API 和 Gateway 健康响应均为
status=ok,测试环境入口 HTTP 200。 - Redis
PONG;gateway.submit.results消费者 1、pending=0、lag=0。 - 发布后 API、Worker、Outbox、Callback、Protocol Log Worker、Gateway、Nginx 的 error 级日志均为 0。
- 恢复资产重新回读通过;配置与 API 进程均不存在旧哈希兼容环境变量。
- 临时管理员、双租户 API 账号、浏览器验收账号和旧哈希迁移账号均已删除;活跃
@integration.invalid用户为 0。 - 浏览器真实打开客户端登录页,页面标题、账号/密码/验证码、验证码挑战、登录按钮和“返回官网”均可见,控制台 error/warning 为 0。
6. 保留项与边界
- 登录后的客户端/运营端页面、深层路由刷新、异步加载失败和移动端状态仍需使用有效账号完成真实浏览器验收;本轮未把未登录页面或源码检查替代为登录后验收。
- 本轮没有重新执行短信发送、压力测试、MinIO 上传下载或 CMPP 模拟器全链;Gateway、队列和 MinIO 只做健康、状态及自动化契约验证,没有产生业务短信、计费或文件写入。
- 两个 SendChain 超大 Service 的职责拆分属于长期可维护性重构,应在独立提交中先补行为锁定测试后实施,不与本次安全发布混合。
- 工作区既有未跟踪文件
=和pnpm-lock.yaml未纳入、覆盖或删除;根package-lock.json为本轮依赖门禁的标准锁文件。 - 测试环境通过不自动授权预生产。预生产仍必须在新的明确授权后重新建立恢复资产再发布。