364e688382
主要改动: backend 业务: - feat(error-codes): 统一错误码表 E1011/E1012 拆码 - E1011 AUTH_PASSWORD_WRONG: 本地密码错误 - E1012 AUTH_FIRST_LOGIN_PASSWORD_REQUIRED: 首次登录请先设置密码 - E1015 AUTH_OLD_PASSWORD_REQUIRED: 改密需要旧密码 - E1016 AUTH_OLD_PASSWORD_WRONG: 旧密码错误 - fix(agents): P0 降级放行时,如坐席已注册但未设密码,正确 raise 1012 (修复前会撞 1011 本地密码错误,与场景不符) - feat(approval): 审批模块 (T审批/A审批) - feat(config): approval_template_resource / approval_template_device 配置 - feat(main): /ready, /metrics, /version 端点(K8s 友好) backend 测试: - test(agents): 新增 test_agents.py — 3 个 Fix-4 降级登录测试 - 错误密码拒绝 - 缺密码拒绝 - 正确密码通过 pytest tests/test_agents.py → 3/3 通过 - test(conftest): 模块级 mock + slowapi 限流重置 + UTF-8 patch 解决 Windows pytest GBK 读 .env 失败 + 降级路径无法测试 仓库治理: - chore(gitignore): 排除 .workbuddy/memory/(workbuddy 本地记忆) - chore(docs): 重命名两份 IT 文档(前缀加智能区分版本) 部署与文档: - docs: RELEASE_NOTES_v0.5.0-beta.md / dashboard.html / 需求-发版预览页面 - docs: 部署、架构、PRD、安全、评审报告等同步 v0.5.0-beta - deploy-server: 打包脚本、nginx、docker-compose 版本号 bump 前端 (frontend-h5 / frontend-agent / frontend-admin / frontend-portal): - index.html / package.json 版本号与构建号 bump 自动验收(RELEASE_NOTES L100-104): - [x] pytest tests/test_agents.py -v → 3 passed - [x] grep Bs7ucT backend frontend-h5 frontend-agent → 无输出 - [x] grep AppException(101[123]) backend → 仅 1 处(登录场景 1012) - [ ] npm run build (frontend-h5 / frontend-agent) → 合并后跑 后续: 合并 feature/t-1-t4-merge → main,tag v0.5.0-beta
6.5 KiB
6.5 KiB
评审报告: workbuddy 2026-06-14 消息相关更新
评审日期: 2026-06-14 评审人: Claude (claude-opus-4-8) 评审范围: workbuddy 6-13/6-14 推送 + 版本更新说明文档 + 实际代码 diff 状态: P0 全部已修(本地代码);P1/P2 待 workbuddy 跟进
一、评审范围(8 个文件 + 1 文档)
| 文件 | 类型 | 评审点 |
|---|---|---|
backend/app/models/message.py |
改动 | status, recallable_until 字段 |
backend/app/api/messages.py |
新增 5 端点 | recall / delete / mark-read / image / file |
backend/app/services/ws_manager.py |
声称改动 | "消息状态广播"(实际未实现) |
backend/app/dependencies.py |
改动 | get_shared_ai_handler(AIHandler 修复) |
backend/app/api/h5.py |
改动 | 邀请功能 3 端点 + participants |
backend/app/api/agents.py |
改动 | OTP 双因素(otp-bind/otp-verify/otp-unbind) |
frontend-h5/src/api/conversation.ts |
改动 | mapMessage 字段映射(id→message_id) |
docker-compose.yml |
改动 | healthcheck 配置(backend 用 curl 已知坑) |
docs/智能IT支持服务台-版本更新说明-20250614.md |
文档 | v1.1.0 发布说明 |
二、文档 vs 代码 vs 记忆 三方不一致 ⭐ 关键发现
| 项 | 版本文档 | 代码 | workbuddy 6-14 记忆 |
|---|---|---|---|
| 消息撤回/删除/状态 | ✅ 文档说已做 | ✅ 实际做了 | ❌ 记忆未提 |
| 标记已读 | ✅ | ✅ | ❌ |
| 图片/文件上传 | ✅ | ✅ (路径在容器本地) | ❌ |
| Health Check 已配置 | ✅ | ⚠️ 配了但 backend 用 curl 永远 unhealthy | ❌ |
| ws_manager 状态广播 | ✅ 文档说做了 | ❌ 代码里没有 | ❌ |
| AI Gateway 预留 | ✅ 文档说做了 | ❌ 未看到 | ❌ |
| OTP 双因素 | ✅ | ✅ | ✅ |
| 数据库 id 字段 UUID→VARCHAR(36) | ❌ 文档未提 | ✅ | ✅ |
结论:
- 文档描述的"本次更新"远多于 workbuddy 实际 push 的内容
- 文档与代码有 5 处不一致(ws_manager 状态广播未做、AI Gateway 未做、healthcheck 配错、upload 路径不持久、SQL 迁移未走 Alembic)
- 文档 "审核状态: 待审核" → 本次评审填补了审核空缺
三、13 项发现(按严重度)
🔴 P0 安全(6 项,全部已修)
| # | 位置 | 问题 | 修复 |
|---|---|---|---|
| P0-1 | h5.py:1107 |
participants 端点仅校验"已登录",未校验"是否属于本会话" | 加 is_creator/is_participant 校验 |
| P0-2 | messages.py:293 |
recall_message 无任何鉴权,任意 HTTP 客户端可改任意消息 | 加 Depends(get_current_agent) + sender_id 校验 |
| P0-3 | messages.py:336 |
delete_message 同上,可删任意消息 | 同上 |
| P0-4 | messages.py:368 |
mark_read 任意人可改任意会话已读状态 | 加 agent 鉴权 + assigned/collaborator 校验 |
| P0-5 | messages.py:400 |
upload_image 无鉴权,可任意上传占用磁盘 | 加 Depends(get_current_agent) |
| P0-6 | messages.py:458 |
upload_message_file 同上 | 同上 |
🟡 P1 重要(4 项,待 workbuddy 跟进)
| # | 位置 | 问题 |
|---|---|---|
| P1-1 | messages.py:434,487 |
upload 保存到 media/images/,media/files/(容器本地),容器重建即丢失 |
| P1-2 | alembic/versions/ |
模型有 status/recallable_until,但未见对应迁移脚本;文档教用户手动 ALTER(反模式) |
| P1-3 | docker-compose.yml:118 |
backend healthcheck 用 curl,容器无 curl → 永远 unhealthy(关联 backend-healthcheck-curl-pitfall) |
| P1-4 | ws_manager.py |
文档承诺"添加消息状态广播",代码里没看到对应方法(ConnectionManager 仅有 send_to_agent/broadcast/send_to_employee/broadcast_to_employees) |
🟢 P2 次要(3 项)
| # | 位置 | 问题 | 状态 |
|---|---|---|---|
| P2-1 | messages.py:388 |
where(Message.is_read == False) 在 SQLAlchemy 里不报错但实际未生效 |
P0-4 修复时一并修:is_(False) |
| P2-2 | messages.py:440,494 |
upload 写文件非原子,中途崩溃留半文件 | 待 workbuddy 修 |
| P2-3 | messages.py:501 |
upload 返回原始 original_name,可能含中文/特殊字符 |
待 workbuddy 修 |
四、文档本身的 4 处错误(评审发现)
| # | 位置 | 错误 | 建议 |
|---|---|---|---|
| 1 | 部署步骤 6 | SQL ALTER TABLE ... DEFAULT 'sent' 引号未转义,shell 执行会语法错 |
改用 alembic 迁移脚本,不手动 ALTER |
| 2 | 部署步骤 5 | docker compose -p root up -d 正是用户 6-14 生产事故的根因 |
删除 -p root 标志,从 /opt/wecom-it-desk/ 跑即可 |
| 3 | 2.1 ws_manager | 声称"添加消息状态广播",代码里没有 | 文档状态改为 "未实现,后续迭代" |
| 4 | 2.1 docker-compose | "healthcheck 已配置" 不准确 | 注明 "backend healthcheck 有 curl 坑,待修" |
五、对比之前 workbuddy 评审
| 旧 P0 (5 项) | 本次 P0 (6 项) | 备注 |
|---|---|---|
| #1 WECOM_SECRET 明文 | (不变) | 等 P0 安全止血阶段 |
| #2 SSL 私钥在 docs/ | (不变) | 阶段 8-A 前置解决 |
| #3 Mock login bypass | (已修复) | — |
| #4 WS token 在 URL/日志 | (不变) | 等 P0 安全止血 |
| #5 坐席登录无 password | (不变) | 等 P0 安全止血 |
| — | P0-1 H5 participants 鉴权 | 本次新发现 |
| — | P0-2~P0-6 messages.py 5 端点鉴权 | 本次新发现 |
安全态势:本次 workbuddy 推送 反而引入了 6 个 P0 鉴权漏洞。workbuddy 后续推送需 强制走评审流程(本次评审堵住了批量漏洞)。
六、修复与待办
已完成(2026-06-14 本地代码)
- P0-1 ~ P0-6 共 6 个鉴权修复
- P2-1 SQL
== False→is_(False)(捎带修)
待 workbuddy 跟进
- P1-1 upload 路径改为 volume mount
- P1-2 补 Alembic 迁移脚本(对照
models/message.py新字段) - P1-3 docker-compose backend healthcheck 改 TCP 端口检查
- P1-4 实现 ws_manager 消息状态广播方法
- P2-2 upload 写文件改
*.tmp+ rename 原子化 - P2-3 upload 返回文件名做 XSS 过滤 / URL encode
待文档/流程
docs/智能IT支持服务台-版本更新说明-20250614.md4 处错误修订- workbuddy 推送流程:加 "PR 前 P0 强制评审" 环节
七、风险跟踪表更新
新增 6 项 P0(本次评审),3 项 P1,3 项 P2(详见 docs/风险跟踪表.md)。
评审结论: workbuddy 6-14 推送 P0 比例过高(6/13 = 46%),强烈建议加评审环节。本次评审发现的 6 个 P0 全部已修代码,待 workbuddy 跟进 P1/P2。