Files
lislgosms/docs/code-quality-remediation-result-20260828.md
T

8.9 KiB
Raw Blame History

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 项相关服务 activeAPI/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、风险审核、发送链、运营日志、短信配置、账务及用户接口均改用可信租户。
  • 客户端创建请求中的 tenantIdoperatorIdcreatedById 不再作为可信身份字段;服务端覆盖或严格拒绝。
  • 应用参数、状态、密钥等按资源 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.2NanoID 解析固定到 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 状态、回退说明和 SHA256SUMSpg_restore --list、tar 目录读取、Redis RDB 和摘要校验通过。最终发布包:

  • outputs/cmpp-code-quality-fc4a6a7-20260828-120252.tar.gz
  • SHA-2567b025b31d2964e290b20104f83532ef4613929574bc3d790d584e433273841be
  • 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 PONGgateway.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. 保留项与边界

  1. 登录后的客户端/运营端页面、深层路由刷新、异步加载失败和移动端状态仍需使用有效账号完成真实浏览器验收;本轮未把未登录页面或源码检查替代为登录后验收。
  2. 本轮没有重新执行短信发送、压力测试、MinIO 上传下载或 CMPP 模拟器全链;Gateway、队列和 MinIO 只做健康、状态及自动化契约验证,没有产生业务短信、计费或文件写入。
  3. 两个 SendChain 超大 Service 的职责拆分属于长期可维护性重构,应在独立提交中先补行为锁定测试后实施,不与本次安全发布混合。
  4. 工作区既有未跟踪文件 =pnpm-lock.yaml 未纳入、覆盖或删除;根 package-lock.json 为本轮依赖门禁的标准锁文件。
  5. 测试环境通过不自动授权预生产。预生产仍必须在新的明确授权后重新建立恢复资产再发布。