Files
gongxue-base/ocr-reports/修复记录.md
T
wangziqi 1289aea7ce docs(ocr): 全库 OCR 审查与修复记录
由 OCR(open-codereview.ai,deepseek-v4-flash)审查产出:
- 审查汇总.md / high-severity-comments.md / all-comments.jsonl / 修复记录.md 等

Reviewed-by: OCR (open-codereview.ai)
2026-08-09 21:29:54 +08:00

13 KiB
Raw Blame History

gongxue-base 修复记录(Phase 0-2 实施)

依据 2026-08-09 OCR 全库审查(all-comments.jsonl,1626 条精确去重)与用户确认的计划(P0+P1,直接实施,允许 schema 变更)。 执行:主 agent + 9 个并行 worker(按互不重叠的文件划分)。全部改动未提交,供人工 review。

验证基线(最终)

  • servernpm run typecheck npm run lint 0 error 0 warning jest 148 套件 / 1087 用例
  • adminnpm run typecheck vitest run 33 文件 / 175 用例 oxlint 0 errorany 为 warn
  • OCR 复查:全量改动 ocr review 1 轮(100 文件 / 84 条),定向 ocr scan 2 轮(12 文件 60 条 → 4 文件 18 条),发现的 critical/high 已逐条修复或明确降级为待办。

Phase 0 — 部署/运维

  • serve-proxy.jsAPI_TARGET 真正生效(new URL 解析);SPA fallback 仅导航请求,缺失资源 404fs.promises 异步读文件;剥离 hop-by-hop 头(含 Connection 提名头);proxyRes/req error 监听 + 30s 超时(带 error 销毁 + 504+ 同步异常 try/catch;路径穿越防护。
  • migrate.sh:密码改用子 shell 内 MYSQL_PWD(不进 argv、不泄漏 pm2);删除硬编码兜底密码,缺失即报错;SQL 包事务;sleep 8 改为轮询 users/tenants/operation_logs 就绪;pm2 startOrReloadtrap ERR 停应用;.env 从脚本目录读取并去引号;导入计数不再被 set -e 掩盖。
  • deploy.sh / .gitea/workflows/deploy.ymlrsync 排除 .env*/data.sql/uploads/;总是 npm ci(含 devDependenciesmigration:run 依赖 ts-node);远程块 set -eworkflow 加 concurrency。
  • ecosystem.config.cjskill_timeout: 5000listen_timeout: 8000、绝对日志路径。
  • oxlint.config.ts:React 版本对齐实际安装(19.2.7);no-explicit-any 改为 warn。

Phase 1 — 安全

  • JWTjwt-secret.ts 统一取密钥,生产缺 JWT_SECRET 启动即失败,删除公开兜底密钥。
  • 密码策略:登录最短 8 位、@MaxLength(72);用户名 @MaxLength(64);登录失败文案统一防枚举。
  • 越权/IDORclasses 全部变更接口补 assertReadAccess;dashboard 五个全局接口按班级范围收紧(非管理员返回空);schedules.findAll 始终应用范围;students basic-lookups 范围化;attendance match 校验学生范围、auto-match 仅管理员;archive 全部路由按学生范围校验(新增 resolveRecordStudentId + StudentsService.assertStudentAccess);exams 权限码尝试分离后因 exam:create/edit/delete 属废弃码回滚exam:view(服务层已有范围校验,见待办)。
  • 全局 ValidationPipe({ transform: true })(不开 whitelist,避免裸 body 被剥空)。
  • 凭据:集成配置 appSecret 复用 AES-256-GCM 静态加密(secret-crypto.ts + 回填脚本 npm run encrypt:integration-secrets);对外输出脱敏。
  • 注入:common/like-escape.ts + 13 处 LIKE 调用转义(含 rbac 教师搜索)。
  • 无界输入:attendance records @ArrayMaxSize(500)、ai-chat values ≤200 字段、notes @MaxLength(1000)、sync limit ≤200、全部上传 10MB 上限。
  • 上传/下载/XSScommon/mime.ts 扩展名白名单归一化 + X-Content-Type-Options: nosniff + 安全类型才 inline;上传判空 400;流 error/close 处理;AttachmentsTab 不再 window.open(blobURL)img/sandbox iframe/ + revoke)。
  • 其他:request-utils 默认不信任代理头(TRUST_PROXY=1 才信任);updateTeacherProfile 返回脱敏;.env.example 补充 TRUST_PROXY 说明。

Phase 2 — 数据正确性

  • 并发/事务:wallets 原子扣款/退款(balance ± :amount + 余额条件,杜绝 double-spend);financial-operations 条件认领 + 支持 15 分钟 stale running 回收 + 结果 JSON 解析容错;ai-a2ui 唯一约束冲突幂等;deposits purge/create 排除归档;with-audit-log best-effortsync-runner finally 不掩盖原错误;imports.commit/preview、students.import、rooms.create、exams 批量、attendance-generation 事务化;occupancies 用父行 FOR UPDATE 防重复入住 + 退宿按剩余在住置状态;attendance-import 用 MySQL advisory lock + 30 分钟看门狗。
  • 校验:3 个 DTO 的矛盾校验器(@Matches vs @IsISO8601 strict)统一为仅日期;rental 跨字段 endDate >= startDateexpenses 上传空值 400。
  • 实体:learning-record / student-profile 的 student_id 双映射移除;student-wallet / bill 金额 DECIMAL 加 number transformerding-leave/attendance-raw 可空 FK 类型 | nullclass-student 外键 onDelete 统一 CASCADEapp.module synchronize 仅显式 true。
  • 时区:common/china-time.tsgetChinaDate / addDaysToDateOnly / getWeekDayFromDateOnly / isConsecutiveDates + 单测);attendance-calendar、ai-review.import-basic、attendance-generation、rental-schedule 的本地/UTC 混用修复。
  • 状态/路由:bills batch/status 与 classrooms report 路由顺序;attendance-report 连续日真实判断;sync 空 mappedValues 跳过更新;考勤组名带 classIdrbac-seed 仅空表或 SEED_ROLES=true 播种 + 默认管理员仍会创建(生产缺 ADMIN_PASSWORD 报错、不打印密码、不再批量重激活禁用用户、删除死代码);expense-types 唯一性检查回滚为与 DB 唯一索引一致;agent-tool.registry 重复注册守卫。
  • 前端:Roles 多组勾选受控化;Schedules 月视图可新建;useDirtyGuard 返回稳定引用;JinshujuMatchModal success:false 分支;Attendance 订阅 storelate 计入出勤率/主状态;EditableCell Enter 不再与 select/date 编辑器冲突;DynamicChart 空数据短路;useSubmissionState ref 变更移到 layout effect。

追加修复(2026-08-09 第二轮)

  • exams 写权限分离exam:create/exam:edit/exam:deleteDEPRECATED_PERMISSION_CODES 移除并加入 PRESET_PERMISSIONS(seed 会创建);控制器 create→exam:createarchive/restore/batch-*/updateScore→exam:editpurge→exam:purge;spec 同步(新增 4 组权限断言)。
  • wallets refundBill 幂等:退款前对账单做条件更新 status <> 'cancelled'affected=0 直接返回),与 bills.cancel 的事务悲观锁双保险,杜绝并发重复冲正。
  • exams updateScore 防误清空score 缺失(undefined)直接 400,清空必须显式传 null。
  • 验证:server typecheck/lint jest 148 套件 / 1091 用例 ;定向 OCR 复查 3 文件无 high/critical。

持续修复循环(Round 1-7,OCR 复查驱动)

按用户要求启动持续修复+review goal:每轮并行派发 3 个互不重叠的 worker → 全量验证 → OCR 定向复查 → 再修,共 7 轮。

  • R1medium 清理)deploy SSH_HOST 校验/密钥 heredoc、jwt-secret 环境判定、encrypt 脚本防回退密钥+连接释放、archive 下载审计、bills 通知 catchrbac 密码 8-72、attendance-import success/release、wallets 分页、attendance 日期边界/连续段语义、AttachmentsTab 乱序、serve-proxy 尾斜杠;migrate trap/防重入/就绪检查、rental ENDED、students.import 死注入、bills-generation 注释。
  • R2high 修复)archive 死代码、rental 死循环×2、financial SQL 优先级、wallets :amount 绑定、exams 权限回滚+spec、rbac-seed admin 创建、attendance 看门狗语义、serve-proxy fallback MIME、migrate argv、deploy npm ci、expense-types 一致性。
  • R3exams 权限 + wallets 幂等)exam:create/edit 从废弃列表恢复并 seed、控制器按写操作标注;refundBill 条件更新幂等;updateScore 空 PUT 防护。定向复查 3 文件 0 high。
  • R4medium 批量)bills 通知/ids、jwt-secret、encrypt 脚本、archive 审计、attendance success/release/日期/连续段、AttachmentsTab 序号、serve-proxy、migrate trap/flock、rental ENDED、students.import 死注入、rbac.dto 校验。
  • R54 high + quick winsmigrate cd/TOCTOU、jwt SEED_DEV、students.import 空 updates、bills 首次生成并发(GET_LOCK);serve-proxy 超时竞态/非法头/请求头 hop-by-hop/URL 回退;attendance-generation N+1、matchImport 事务、锁名常量、rbac.dto 校验、bills 批量学生+allSettled。
  • R6high→1 + quickattendance 看门狗只告警、runner.connect try/finally、fetchAllPages 并发、mapToEntity 批量预取;attendance-generation 标签/死代码/事务;bills 批量保存/四舍五入/未用注入;rental 多日展开+事务+枚举;students.import host org 缓存/日期日历校验;rbac.dto 锚定正则+长度上限。
  • R7high→0bills 路由顺序(export 在 :id 前)+ ids DTOserve-proxy 失败分支 error 监听/写头抛错释放 socket/客户端断开;migrate DUMP 绝对路径/原子锁/文件预检/APP_STARTED/5 表就绪/DML-only 说明;rbac.dto 显示名允许内部空格+密码字节上限+subjects 唯一性;bills 通知幂等(仅新增 paid 才发)+ reason 审计转义(本轮新增)。

收敛结论

  • 连续 2 轮 OCR 定向复查(覆盖所有修复过的文件):high/critical = 0
  • 每轮全量验证:server typecheck lint 0 error jest 152 套件 / 1170 用例 admin typecheck vitest 175
  • 剩余为 P2 性能/重构/依赖 schema 项(见下),非本轮目标。

收尾补充(复查核对后)

  • bills.controller:取消账单的 reason 写入审计日志前做控制字符过滤(防日志注入)。
  • serve-proxy:删除 serveStatic 未使用的 req 参数。
  • migrate.sh:就绪检查超时时输出期间收集的 MySQL stderr(密码错误/容器未启动可诊断)。
  • 验证:server lint/typecheck/jest 152 套件 / 1170 用例全绿。

P2 纯代码项(并行 3 worker + 复查二修)

  • serve-proxy 静态流式化fs.stat + Content-Length + createReadStream pipe,消除全量缓冲;目录请求 404、realpath 防 symlink 穿越。
  • migrate.sh 库名变量化LEGACY_DB/TARGET_DB 抽变量;COMMIT 用 printf 防粘行;IMPORTED_COUNT 失败兜底;.migrate.done 改为数据提交后立即写。
  • attendance-importIN(dingIds) 按 1000 分块并发查询;finally 仅抢到锁才清理运行态。
  • students.importphone/idNumber 批量预取(2 条 IN 查询)替代逐行 findOne;新增双键冲突检测(phone/idNumber 命中不同学生 → 跳过并计 skippedConflict,防数据错乱)。
  • bills-generation:per-room 入住查询改为一次 IN 批量 + 内存分组;日期统一 YYYY-MM-DD 字符串比较(toDateOnly/daysBetweenDateOnly),消除 Date hydrate 比较不可靠;eligibleDays 提出循环。
  • bills DTOBatchIdsBodyDto 移入 dto/bill.dtobatchPurge/batchRemove 复用 common BatchIdsDtobillingMonth 收紧为真实月份。
  • rbac.dtoUpdateRoleDto/UpdateUserDto 用 PartialType/OmitType 去重;subjects 补非空白 each。
  • 复查二修:serve-proxy 目录/realpath、matchImport 冲突、bills 日期、attendance finally、DTO/migrate 小项;spec 同步。
  • 验证:server typecheck/lint 全绿,jest 152 套件 / 1178 用例

剩余(已收敛)

  • 数据库唯一约束(bills 周期、Student.phone/idNumber、expense-type code 放开软删复用)与迁移文件生成(class_student 外键 CASCADE)——需接库环境执行 npm run migration:generate -- FixEntityMappings
  • 少量 lowSTATIC_DIR 可配置、%20 解码、X-Forwarded 链保留、登录时序侧信道权衡项等)按需处理。
  • 迁移文件生成(class_student 外键 CASCADE 等):cd apps/server && npm run migration:generate -- FixEntityMappings(需接库环境)。
  • 低价值 low 项(如 STATIC_DIR 可配置、%20 解码、x-forwarded 链保留、attendance-import 无界 IN 分块等)按需后续处理。

待办/已知(未修)

  1. exams 写权限分离 已修复(见追加修复)。
  2. wallets refund 的 bill 状态 check-then-act 已修复(条件更新幂等)。
  3. 迁移文件:实体改动(class_student 外键 CASCADE 等)需在接库环境 cd apps/server && npm run migration:generate -- FixEntityMappings 生成并 review 后上线;本地无 MySQL 未生成。
  4. P2 backlog:剩余 low/维护性 ~700 条(见 all-comments.jsonl),未在本轮实施。
  5. OCR 复查仍提示的 medium/low(如 migrate.sh 无并发锁/命令注入面、rbac-seed N+1、serve-proxy 的 servedIndex 冗余等)可按后续迭代处理。

交付物

  • 改动:git status 约 120+ 文件(未提交)。
  • 报告:ocr-reports/审查汇总.mdhigh-severity-comments.mdall-comments.jsonladmin/server/misc-scan-comments.jsonl修复记录.md(本文件)。