# CMPP 平台代码质量复评报告 V2 - 报告日期:2026-08-28 - 复评时间:2026-08-28 12:38~12:57(Asia/Shanghai) - 复评基线:`3af145abe5eb8cae567bb18e29116b4940889258` - 对比基线:`171c7d38e8f17de0dd83570603da316d47c0d015` - 分支状态:`main`,本地 `HEAD` 与 `origin/main` 一致 - 变更规模:58 个文件,新增 1,953 行、删除 487 行 - 复评范围:React/Vite 前端、NestJS API、Prisma/PostgreSQL、Redis、Go Gateway、自动化测试、依赖与仓库门禁、测试环境只读健康探测 - 明确未执行:提交、推送、部署、服务重启、数据库写入、短信发送、压力测试、MinIO 业务对象写入、预生产或生产环境操作 ## 1. 复评结论 本次采用两个相互独立的结论,避免把“代码整改完成”和“环境可发布”混为一谈: 1. **代码整改:有条件通过。** 上一版的两个 P0 已在源码、自动化测试和结构门禁层面关闭;前端分包、覆盖率门槛、Redis 状态存储、数据库配置 fail closed、mock 解耦等整改有效。 2. **发布就绪:待完整验收。** 2026-08-28 12:50 在 Clash 虚拟网卡/代理开启状态下探测测试环境时曾连续返回 HTTP 502;关闭 Clash 后使用 `curl --noproxy '*'` 绕过代理直连,12:56 连续 3 次访问 `/api/health` 均返回 HTTP 200、`status=ok`,TCP 12026 端口可达,连接耗时约 10 ms、总响应约 19~28 ms。此前 502 判定属于本地网络代理干扰,不是测试环境运行故障。 当前代码质量综合参考分:**82/100**,较上一版 **58/100** 提升 24 分。该分数只表示仓库代码治理水平,不等价于功能验收通过率。 测试环境外部 API 健康探测已经恢复为通过;但在重新核对部署版本、内部服务/队列状态并完成真实后端与登录后浏览器复验前,**仍不建议进入预生产发布**。 ## 2. 质量评级 | 维度 | 上版 | 本次 | 复评结论 | |---|---:|---:|---| | 业务正确性与并发设计 | B | B+ | API/Gateway 回归通过,核心幂等与队列逻辑保持;未重跑真实 CMPP 全链。 | | 安全性 | D | B+ | 可信租户上下文和强密码哈希已落地;重点写接口校验仍非全覆盖。 | | 自动化测试 | C | B- | API 47 套 543 项通过并建立覆盖率阈值;前端测试仍为 0。 | | 前端性能 | C- | B+ | 路由懒加载和 ECharts 按需加载生效,入口 gzip 降至 107.38 KiB。 | | 可维护性 | C | C+ | mock 解耦和页面辅助逻辑拆分完成;两个 SendChain Service 仍超大,未建立 ESLint/Prettier。 | | 数据库工程 | B | B+ | Prisma 校验通过,生产/测试缺少 `DATABASE_URL` 时 fail closed;本轮未做真实数据执行计划复测。 | | 依赖与仓库卫生 | C- | B- | 根正式锁文件审计为 0;API 依赖树仍有 7 项公告,且未跟踪的旧 pnpm 锁文件会造成错误审计口径。 | | 运行与发布就绪 | 未评 | B- | 绕过本地代理后测试环境外部 `/api/health` 连续 3 次返回 200;本次未独立核对内部服务、队列和登录后业务链。 | ## 3. 上一版问题关闭状态 | 编号 | 原级别 | 本次状态 | 判定依据 | |---|---:|---|---| | CQ-SEC-001 客户端租户可伪造 | P0 | **已关闭(代码级)** | 会话中间件从数据库用户写入 `sessionTenantId`;客户端装饰器只读取可信上下文;伪造 header 返回 `CLIENT_TENANT_MISMATCH`;相关租户隔离测试通过。 | | CQ-SEC-002 无盐 SHA-256 密码 | P0 | **已关闭(代码级)** | 使用随机 salt 的版本化 scrypt、恒定时间比较、参数上限解析;旧 SHA-256 只读兼容并在正确登录后透明升级;写路径和工具门禁已覆盖。 | | CQ-API-001 缺少运行时输入校验 | P1 | **部分关闭** | 已新增严格 `ValidationPipe` 和重点客户端写 DTO;但未全局注册,部分凭据、Webhook、日志导出等写接口仍使用内联类型和裸 `@Body()`。 | | CQ-AUTH-001 验证码/失败计数进程内 Map | P1 | **基本关闭** | 已迁移 Redis TTL、`GETDEL` 和 Lua 原子计数,Redis 异常 fail closed;仍建议补 IP+账号双维度限流与容量指标。 | | CQ-FE-001 主包过大、无路由分包 | P1 | **已关闭** | 全部业务页采用懒加载;ECharts 按需注册;入口 gzip 107.38 KiB,低于 250 KiB 门槛,最大异步图表包 181.64 KiB,低于 190 KiB 门槛。 | | CQ-TEST-001 测试与验收层级不足 | P1 | **部分关闭** | API 覆盖率阈值已建立且本轮通过;Gateway 测试通过;前端仍无测试,登录后浏览器和真实全链未完成。 | | CQ-DEP-001 两个 high advisory | P2 | **原问题已关闭** | 正式 `package-lock.json` 使用 React Router 7.18.2、NanoID 3.3.18;按该锁文件重建审计结果为 0。 | | CQ-MAINT-001 超大文件、无静态风格门禁 | P2 | **部分关闭** | 页面辅助逻辑已拆分,增加结构质量脚本;两个 SendChain Service 仍为 86,253/53,421 字节,`lint` 实际为结构检查加 TypeScript,不是 ESLint/格式门禁。 | | CQ-CONFIG-001 数据库默认凭据 | P2 | **已关闭** | 非 development/test 环境缺少 `DATABASE_URL` 时启动失败,不再静默使用默认生产连接。 | | CQ-ARCH-001 生产代码依赖 mock | P2 | **已关闭** | 类型已迁至 `src/api/types`,结构门禁禁止生产页面重新导入 mock。 | | CQ-REPO-001 仓库产物与审计基线不稳定 | P2 | **部分关闭** | `*.tsbuildinfo` 已停止跟踪并加入忽略;但工作区仍有未跟踪的 `=` 和过期 `pnpm-lock.yaml`。 | ## 4. 关键整改证据 ### 4.1 可信租户上下文 - `api/src/auth/session-validation.middleware.ts:70-72`:客户端请求携带的租户头与登录用户租户不一致时返回 403,并将数据库用户租户写入 `request.sessionTenantId`。 - `api/src/auth/current-tenant-id.decorator.ts:10-13`:只允许 client portal 读取可信租户上下文,不再回退到请求头。 - 客户端认证、短信配置、账务、发送链、风险复核、用户等控制器已改用 `@CurrentTenantId()`。 - 管理端 `@TenantId()` 仍存在于 `admin/files`、`admin/operation-logs`、`admin/billing` 等管理路由中,不属于客户端授权依据;结构门禁已禁止客户端控制器回退使用旧装饰器。 判定:原 P0 的根因已消除。测试环境真实双租户结果在整改记录中有描述;本次只复核外部健康接口,没有重跑双租户矩阵,因此仍按代码级关闭记录。 ### 4.2 密码存储与迁移 - `api/src/auth/password-hasher.ts:1-82`:版本化 scrypt、随机 salt、`timingSafeEqual`、参数边界和旧 SHA-256 识别均已实现。 - 旧哈希兼容写窗口被限制为最长 2 小时;正常写路径默认生成新格式。 - 登录成功后通过条件更新透明迁移旧哈希,错误密码不迁移。 - 单测覆盖随机盐、错误密码、旧哈希验证/迁移、畸形参数和兼容窗口边界。 判定:满足上一版“强哈希、版本参数、恒定时间比较、透明迁移”的最小关闭标准。测试环境仍保留的历史 SHA-256 数量来自整改记录,本次未直接查询数据库复核。 ### 4.3 登录状态与输入校验 - `api/src/auth/session.service.ts:129-163`:验证码使用 Redis TTL,消费使用 `GETDEL`;失败计数使用 Redis Lua 原子逻辑。 - `api/src/common/strict-validation.pipe.ts`:启用 transform、whitelist 和 forbidNonWhitelisted。 - 重点客户端写接口已增加 class-validator DTO 和严格管道。 - `api/src/open-api/client-open-api.controller.ts:15-18` 的凭据/Webhook 写入,以及 `api/src/operations/client-operations.controller.ts:78-84` 的日志导出仍使用内联 body,未套用严格校验管道。 判定:验证码多实例一致性问题已关闭;输入校验只能判为阶段性完成,不能写成全 API 闭环。 ### 4.4 前端性能 - `src/routes/AppRoutes.tsx:10-74`:业务页面统一路由级懒加载。 - `src/components/ui/Chart.tsx:3-8`:只注册实际使用的 ECharts 图表、组件和 Canvas renderer。 - 本次生产构建:入口 `index-*.js` 370.54 KiB,gzip 107.38 KiB;图表异步包 553.06 KiB,gzip 181.64 KiB。 - 包体预算脚本通过:入口不高于 250 KiB gzip,异步包不高于 190 KiB gzip。 判定:原主包 626.18 KiB gzip 的问题已实质关闭。Vite 仍提示图表 chunk 的未压缩体积超过 500 KiB,但其 gzip 体积在当前预算内,作为后续优化项而非阻断项。 ### 4.5 数据库与工程配置 - API 正式构建通过。 - Prisma Schema validate 通过;仓库存在 95 个 migration 目录。 - 非开发/测试环境缺少 `DATABASE_URL` 时 fail closed。 - 本轮没有连接真实 PostgreSQL 执行 `EXPLAIN (ANALYZE, BUFFERS)`,也没有独立核对测试库 95/95 migration;相关运行态数据仅见整改记录。 ## 5. 本次独立复测结果 | 检查项 | 本次结果 | |---|---| | Git 基线 | `HEAD == origin/main == 3af145a...` | | 工作区 | 仅发现既有未跟踪 `=`、`pnpm-lock.yaml`;未修改或删除 | | 前端 TypeScript | 通过 | | Vite production build | 通过 | | Bundle budget | 通过;入口 107.38 KiB gzip,最大异步包 181.64 KiB gzip | | API TypeScript build | 通过 | | Prisma validate | 通过 | | API Jest | 47/47 套、543/543 项通过 | | API 全源覆盖率 | statements 59.84%,branches 51.29%,functions 60.15%,lines 62.60% | | API 覆盖率门槛 | 通过;门槛分别为 59%、50%、60%、62% | | Gateway `go test ./... -count=1` | 通过 | | Gateway `go vet ./...` | 通过 | | Gateway 队列契约 | 5/5 通过 | | 代码质量结构检查 | 通过 | | 依赖缓解/安全部署检查 | 通过 | | 根正式锁文件生产依赖审计 | 0 个公告 | | API 正式锁文件生产依赖审计 | 7 个公告:2 moderate、5 high | | 前端自动化测试 | 0 个测试文件,未通过验收出口标准 | | 测试环境 `/api/health` | **通过;关闭 Clash 后绕过代理直连,连续 3 次 HTTP 200、`status=ok`** | | 测试环境 TCP 12026 | **通过;可连接** | | 测试环境 SSH 只读核验 | 未完成;当前凭据认证失败 | 覆盖率说明:整改结果文档记录的 69.77%/53.47%/71.08%/73.05% 使用 Jest 默认“已加载源码”口径;本报告显式使用 `collectCoverageFrom=src/**/*.ts` 的全源口径,得到 59.84%/51.29%/60.15%/62.60%。两个结果不是同一统计口径,不应直接比较。本次全源结果仍满足已设门槛,并略高于上一版全源基线。 依赖审计说明:工作区未跟踪的 `pnpm-lock.yaml` 固定了旧 React Router 7.18.1 和 NanoID 3.3.16,直接运行 pnpm audit 会错误报出上一版两个 high。按正式、已跟踪的 `package-lock.json` 在临时目录重建锁文件后,根项目审计为 0。该旧锁文件仍应由文件所有者确认后清理或更新,避免 CI/开发者误用。 ## 6. 当前阻断项与剩余风险 ### 运行探测校正:此前 502 为本地代理干扰,不构成缺陷 **证据链** - 2026-08-28 12:50,在 Clash 虚拟网卡/代理开启状态下,PowerShell Web 请求曾连续返回 HTTP 502。 - 用户关闭 Clash 后,首次 PowerShell `-NoProxy` 请求出现一次 10 秒超时,随后请求开始恢复。 - 2026-08-28 12:56,使用 `curl --noproxy '*'` 明确绕过代理连续请求 3 次,均返回 HTTP 200 和 `{"status":"ok","service":"cmpp-platform-api"}`。 - 三次直连总响应时间分别约 28 ms、23 ms、19 ms,TCP 12026 检测为可连接。 **校正结论** 此前新增的 `CQ-OPS-001 / P0` 撤销,不计入缺陷和发布阻断。测试环境外部 API 当前可用,原整改记录中的 API 健康结论没有被本次复评推翻。 **仍保留的验证边界** 本次 SSH 凭据认证失败,因此没有独立读取部署标记、11 项服务状态、内部 Gateway health、Redis Stream pending/lag、migration 或服务器日志。这些项目继续引用整改发布记录,预生产前仍应在可用只读凭据下重新核对。后续私网健康探测应显式绕过系统代理,避免 Clash 等本地网络工具造成误判。 ### CQ-API-001 / P1:严格输入校验尚未覆盖全部写接口 当前采取“重点接口逐步接入”而非全局管道。凭据创建、Webhook 更新和日志导出等入口仍使用运行时会被擦除的内联 TypeScript 类型。建议先覆盖所有 client POST/PUT/PATCH/DELETE,再评估 admin 高风险写接口;为字段长度、URL、枚举、数组大小和额外字段补负向测试。 ### CQ-TEST-001 / P1:前端与真实环境验收未闭环 前端测试文件仍为 0;本轮没有可用登录态,无法验证登录后页面、控制台、请求、加载/空/错误/刷新状态。本次仅确认外部 API health,未重新执行真实 PostgreSQL、Redis、MinIO、Gateway 和 CMPP 联动复验。 ### CQ-DEP-002 / P1:API 依赖树仍有 7 项生产审计公告 按 `api/package-lock.json` 重建审计后为 2 moderate、5 high,涉及 ExcelJS 间接 UUID、Prisma 可选工具链、brace-expansion、Swagger 间接 js-yaml 等。公告并不等于当前业务路径全部可利用,但应建立“依赖路径、运行时是否打包/调用、可升级版本、兼容回归”的矩阵,不能只以根项目审计为 0 宣告供应链闭环。 ### CQ-MAINT-001 / P2:超大服务和有风格门禁仍未治理 `send-inbound-entry.service.ts` 约 84.2 KiB,`send-gateway-submit.service.ts` 约 52.2 KiB;职责仍集中。建议先补行为锁定测试,再按入站持久化、关联/去重、重试路由、下游投递和计费拆分。另应增加 ESLint 与 format check;当前 `npm run lint` 名称实际只执行结构脚本和 TypeScript 检查。 ### CQ-REPO-001 / P2:双锁文件口径仍可能误导审计 正式锁文件是 `package-lock.json`,但未跟踪 `pnpm-lock.yaml` 仍存在且版本过期。应先确认其归属,再选择唯一包管理器和唯一锁文件;本报告没有擅自删除或更新用户保留文件。 ## 7. 发布建议 当前建议为:**代码可进入下一轮验证,但暂停预生产发布。** 最小充分关闭顺序: 1. 使用显式绕过系统代理的方式复核测试环境,并在可用只读凭据下核对实际部署标记、内部服务和队列状态。 2. 在测试环境重跑双租户隔离和旧密码透明迁移,不发送真实短信。 3. 补齐剩余客户端写接口 DTO/严格校验,并增加负向测试。 4. 建立最小前端测试集:登录、权限、路由懒加载失败、列表加载/空/错误、关键确认操作。 5. 对 API 7 项公告建立升级兼容矩阵;优先处理直接运行时路径。 6. 在单独任务中治理 SendChain 超大服务、ESLint/格式门禁和唯一锁文件。 7. 只有在真实 PostgreSQL、Redis、MinIO、Gateway/CMPP 模拟器和登录后浏览器证据齐全后,再申请预生产发布授权。 ## 8. 最终判定 - 原 P0 代码问题:**2/2 已关闭**。 - 原 P1:**2 项关闭或基本关闭,2 项部分关闭**。 - 原 P2:**3 项关闭,2 项部分关闭**。 - 新增运行态阻断:**0 项**;此前 502 已确认是本地 Clash 代理干扰并撤销。 - 自动化门禁:除 API 子树依赖审计和前端测试缺失外,其余本次执行项通过。 - 代码质量:**82/100,有条件通过**。 - 当前发布就绪:**待完整验收;无 502 运行态阻断**。 本报告是对固定提交的独立复评和一次当前测试环境只读探测,不替代完整功能验收、生产安全评估或预生产发布审批。