# Hermes Full Review — 2026-05-27 - 仓库:`/home/long/project/user-system` - 分支:`main` - 基线提交:`82109ec Merge branch 'fix/status-review-sync-20260409'` - 审查方式:文档对齐 + 代码静态复核 + 本地构建/测试/审计实测 + 二次复核补查 - 结论:**❌ Not Ready / 当前不建议发布** --- ## 1. Executive Summary 当前仓库不是“完全不可运行”,但**不满足诚实发布条件**。阻断原因主要有三类: 1. **安全 / 权限 P0 问题** - 普通登录用户可枚举全部用户并读取任意用户详情 - TOTP 二次验证被降级成可单独换取登录态的入口 - 多个“未配置”认证/绑定接口返回 `200 + code:0`,形成假成功 2. **后端 clean-state 基线不绿** - `go build ./cmd/server` - `go vet ./...` - `go test ./... -count=1` - 三者在当前提交态均失败,并提示 `go mod tidy` 3. **文档状态比代码现实更乐观** - README / 状态文档存在“已闭环 / 已完成”表述 - 但实际仍有主链路契约漂移、假成功与 clean-state 基线不干净问题 --- ## 2. 审查范围与方法 ### 2.1 读取的关键文件 - `AGENTS.md` - `README.md` - `docs/PRD.md` - `docs/status/REAL_PROJECT_STATUS.md` - `go.mod` - `frontend/admin/package.json` ### 2.2 执行的关键命令 后端: - `go version` - `go build ./cmd/server` - `go vet ./...` - `go test ./... -count=1` - `go test -mod=mod ./internal/repository -count=1` - `go test -mod=mod ./... -count=1` - `go test ./... -coverprofile=/tmp/user-system-cover.out -count=1` - `go tool cover -func=/tmp/user-system-cover.out` 前端: - `npm ci` - `env -u NODE_ENV npm ci` - `env -u NODE_ENV npm run lint` - `env -u NODE_ENV npm run build` - `env -u NODE_ENV npm run test:run` - `env -u NODE_ENV npm run test:coverage` - `env -u NODE_ENV npm audit --omit=dev --json` - `env -u NODE_ENV npm audit --json` --- ## 3. 验证快照 ### 3.1 环境事实 - Go:`go1.26.3 linux/amd64` - Node:`v22.22.0` - npm:`10.9.4` - 观察到默认 shell 存在:`NODE_ENV=production` ### 3.2 环境风险 默认 `NODE_ENV=production` 会导致第一次 `npm ci` 只安装生产依赖,进而出现: - `eslint: not found` - `tsc: not found` - `@vitejs/plugin-react` not found 这说明 runbook / CI 若不显式控制环境变量,前端验证容易误判。 ### 3.3 后端实测 #### 当前提交态 / clean-state 以下命令均失败: - `go build ./cmd/server` - `go vet ./...` - `go test ./... -count=1` 统一报错: ```text go: updates to go.mod needed; to update it: go mod tidy ``` #### 探索性验证 为了区分“代码问题”与“模块清单漂移问题”,额外执行: - `go test -mod=mod ./internal/repository -count=1` → **PASS** - `go test -mod=mod ./... -count=1` → **PASS** 说明:核心代码不是全部跑不起来,但**提交态本身不干净**。 #### 覆盖率 - `go tool cover -func=/tmp/user-system-cover.out` - 总覆盖率:**52.4%** ### 3.4 前端实测 在显式移除 `NODE_ENV=production` 影响后: - `env -u NODE_ENV npm ci` → **PASS** - `env -u NODE_ENV npm run lint` → **PASS** - `env -u NODE_ENV npm run build` → **PASS** - `env -u NODE_ENV npm run test:run` → **PASS** - `82` 个 test files - `518` 个 tests - `env -u NODE_ENV npm run test:coverage` → **PASS** 前端 coverage: - Statements: **89.83%** - Branch: **80.38%** - Funcs: **88.24%** - Lines: **90.36%** ### 3.5 前端依赖审计 - `env -u NODE_ENV npm audit --omit=dev --json` → **0 漏洞** - `env -u NODE_ENV npm audit --json` → **5 漏洞** - 含 **1 个 high**:`vite 8.0.3` --- ## 4. Blockers(必须修复) ### P0-1 普通登录用户可枚举全部用户并读取任意用户详情 **证据** - `internal/api/router/router.go:206-215` - `internal/api/handler/user_handler.go:90-165` **问题** - `GET /api/v1/users` - `GET /api/v1/users/:id` 当前仅挂在 `protected.Use(r.authMiddleware.Required())` 下,未加: - `AdminOnly` - `RequirePermission` - 本人访问约束 **影响** 普通用户可读取其他用户列表 / 详情 / 邮箱等信息,属于明确数据越权。 --- ### P0-2 TOTP 验证接口可单独换取登录态,二次验证被降级为单因子登录 **证据** - `internal/api/handler/auth_handler.go:151-172` - `internal/service/auth.go:811-831` **问题** `POST /api/v1/auth/login/totp-verify` 只依赖: - `user_id` - `code` - `device_id` 没有要求: - 已完成密码登录 - 临时 challenge ticket - 短期 server-side login session **影响** 拿到 TOTP / 恢复码即可直接换取完整 token,安全模型错误。 --- ### P0-3 未实现的绑定 / OAuth 接口使用 `200 + code:0` 伪装成功 **证据** - `internal/api/handler/auth_handler.go:316-355` - `internal/api/handler/auth_handler.go:563-660` - `frontend/admin/src/lib/http/client.ts:274-279` - `frontend/admin/src/pages/admin/ProfileSecurityPage/ContactBindingsSection.tsx:141-216` **问题** 后端在以下场景仍返回成功语义: - OAuth not configured - email bind not configured - phone bind not configured - social binding not configured 前端只要 `code===0` 就按成功处理。 **影响** 用户会看到“已绑定 / 已解绑 / 已发送验证码”等成功反馈,但实际无状态变化。 --- ### P0-4 Bootstrap Admin 前后端契约冲突,首个管理员初始化默认不可用 **证据** 前端: - `frontend/admin/src/pages/auth/BootstrapAdminPage/BootstrapAdminPage.tsx:24-30,68-76` - `frontend/admin/src/services/auth.ts:61-63` 后端: - `internal/api/handler/auth_handler.go:504-527` **问题** 前端未满足后端强制契约: - 缺少 `X-Bootstrap-Secret` - `email` 前端可为空,但后端必填 **影响** 首次部署时最关键的 bootstrap 链路可能直接失败。 --- ### P0-5 clean-state 后端构建基线不绿 **证据** - `go build ./cmd/server` → fail - `go vet ./...` → fail - `go test ./... -count=1` → fail - 统一要求 `go mod tidy` **影响** 当前 `main` 不满足仓库 AGENTS 要求的最低验证矩阵,不能诚实宣称“始终可构建、可测试通过”。 --- ## 5. High / Important Issues ### P1-1 Logout fail-open,token 失效失败也返回成功 **证据** - `internal/service/auth.go:897-925` - `internal/api/handler/auth_handler.go:185-209` **问题** 黑名单写入错误被忽略,handler 仍返回 `200 logged out`。 --- ### P1-2 多个 handler 的管理员判断读错 context key **证据** middleware 写入: - `internal/api/middleware/auth.go:85-91` - 写入 `role_codes`, `permission_codes` handler 读取: - `internal/api/handler/user_handler.go:188-200` - `internal/api/handler/user_handler.go:374-383` - `internal/api/handler/avatar_handler.go:72-85` - 读取的是 `user_roles` **影响** 管理员代操作逻辑可能失效,权限模型与实际行为漂移。 --- ### P1-3 修改密码接口与注释声明不一致 **证据** - `internal/api/router/router.go:211-213` - `internal/api/handler/user_handler.go:275-297` **问题** 注释写“仅管理员或本人”,但 handler 没有显式按该规则做校验。 --- ### P1-4 密码历史记录异步写入,事务不完整 **证据** - `internal/service/user_service.go:128-145` **问题** 密码更新同步写库,但密码历史在 goroutine 中异步写入且错误吞掉。 --- ### P1-5 Avatar token 随机源错误未 fail-closed **证据** - `internal/api/handler/avatar_handler.go:35-39` **问题** `rand.Read(bytes)` 错误被忽略。 --- ## 6. 二次复核补充(第一次遗漏后补查) ### 6.1 前端测试绿,但没挡住真实 API 契约漂移 - 前端测试:`518 passed` - 但 bootstrap-admin、contact bindings、OAuth 与真实后端契约仍不一致 **判断** 这是测试体系盲点,不是“测试通过即可放心”。 ### 6.2 前端开发依赖存在 1 个 high 漏洞 - `vite 8.0.3` high - 另有 moderate 级别依赖漏洞 ### 6.3 `NODE_ENV=production` 造成验证误判风险 - 未显式控制环境变量时,devDependencies 可能缺失 - 容易把环境问题误判为代码问题 ### 6.4 后端总覆盖率仅 52.4% 在当前已有多条认证 / 权限高风险链路下,后端覆盖率偏低会放大回归风险。 ### 6.5 测试 warning 噪音较多 实测出现: - `act(...)` warning - React Router future flag warning - `danger` 非布尔 attribute warning - `addonAfter` deprecated warning - React list key warning 虽然不阻断当前前端测试通过,但说明测试基线不够干净。 --- ## 7. 文档真相审查 ### 结论:❌ 未闭环 当前 README 与 `docs/status/REAL_PROJECT_STATUS.md` 存在“闭环 / 已完成 / 当前绿色”等偏乐观表述,但 live review 证明: - 后端 clean-state 不绿 - bootstrap-admin 主链路漂移 - 绑定 / OAuth 存在假成功 - 权限模型存在 P0 建议文档至少降级为: > 前端 lint/build/test 当前可通过;后端代码在 `-mod=mod` 探索性测试下大体可运行,但 clean-state 构建基线未绿;认证 / 权限 / 绑定链路仍有 P0 阻断,不可宣称发布闭环。 --- ## 8. 四类闭环判断 ### 8.1 实现闭环 **状态:❌** - 权限越权未解决 - TOTP 流程模型错误 - bootstrap-admin 契约漂移 - binding / OAuth 实际未闭环 ### 8.2 证据闭环 **状态:✅/⚠️ 部分成立** - 前端构建 / 测试证据充分 - 后端 clean-state 失败证据明确 - 但这些事实尚未同步进主状态文档 ### 8.3 文档真相闭环 **状态:❌** - 当前对外状态文档比代码现实更乐观 ### 8.4 防复发闭环 **状态:❌** 尚未看到系统性防线去约束: - binding / OAuth 禁止 200 假成功 - bootstrap 前后端契约对齐校验 - `/users` 与 `/:id` 权限回归测试 - clean-state `go build/vet/test` gate - 真实 API contract 联调验证 --- ## 9. 最终评级 | 维度 | 评级 | 说明 | |---|---|---| | 需求 / 实现一致性 | C | 多条主链路契约漂移 | | 安全基线 | D | 存在 P0 权限 / 认证问题 | | 构建与测试基线 | C | 前端绿,后端 clean-state 红 | | 可维护性 | B- | 结构尚可,但存在 context key 漂移 / fail-open / 异步事务问题 | | 文档真相 | C- | 文档明显乐观于代码现实 | | 发布就绪度 | D | 当前不建议发布 | **综合评级:D / Not Ready** --- ## 10. 修复优先级建议 ### P0(先修) 1. 修复 `/api/v1/users` 与 `/:id` 越权 2. 重构 `totp-verify`,必须绑定密码登录 challenge 3. 所有未实现的 binding / OAuth 接口改为 fail-closed,并同步前端处理 4. 修复 bootstrap-admin 前后端契约 5. 清理 `go.mod/go.sum` 漂移,恢复 clean-state build/vet/test 绿灯 ### P1(紧随其后) 6. 修复 logout fail-open 7. 修复 `user_roles` / `role_codes` context key 漂移 8. 修复 password history 异步写入的事务缺口 9. 修复 avatar token 生成未检查错误 10. 升级前端 dev toolchain 漏洞(至少 vite) ### P2(收口) 11. 清理测试 warning 噪音 12. 补真实 API contract 集成测试 13. 更新 README / `docs/status/REAL_PROJECT_STATUS.md` --- ## 11. 本次二次 Review 的新增补充摘要 相较第一次结论,本次额外明确了以下问题: 1. 前端测试体系没有挡住真实 API 契约漂移 2. 前端 dev toolchain 存在 1 个 high 漏洞(Vite) 3. `NODE_ENV=production` 会导致 devDependencies 缺失,runbook / CI 易误判 4. 后端总覆盖率仅 52.4% 5. 测试输出 warning 噪音较多,质量门禁不够干净 --- ## 12. 最终结论 **当前建议:不要发布;先修两个 high blocker 类问题,再推进剩余 P0 / P1。** 其中最先收口的方向应是: - 认证 / 权限真安全 - clean-state 构建真绿色 - 文档真相与代码现实一致