Files
Nexus/docs/changelog/2026-05-24-batch-review-fixes.md
T
Your Name cdd0be328a fix: 六轮深度扫描 — 47项Bug修复、安全加固、死代码清理
Critical runtime bugs:
- terminal.html WebSSH完全不可用(URL前缀/JSON解析/Content-Type三处错误)
- servers.py路由遮蔽:/logs被/{id}拦截,3个前端页面同步日志查询失败
- scripts.html startExecPoll()→startExecPolling(),长任务快速执行崩溃
- agent.py {value!r!s:.50}格式串非法,agent发非数值时ValueError
- alerts.html d.daily.reduce()无null检查,API返回空数据时TypeError

Resource leak / stability:
- websocket.py僵尸连接未关闭TCP,文件描述符泄漏
- websocket.py _last_alert_time字典无限增长(加1小时过期清理)
- asyncssh_pool.py全忙时超过MAX_CONNECTIONS无限增长
- self_monitor.py Telegram告警无冷却,宕机时每30秒刷屏
- schedule_runner.py一次性调度执行超60秒会重复触发
- 限速脚本EXPIRE每次重置窗口可绕过(改用Lua原子脚本)

Security:
- JWT access token加token_version声明,改密码后旧token立失效(零宽限)
- INSTALL_MODE导入时常量→动态函数,安装后JWT认证不再残留禁用
- install.py /lock端点加管理员存在性验证,防止阻断安装
- ServerUpdate schema移除connectivity只读字段,防止伪造连接状态

Frontend fixes:
- doExec()缺r.ok检查、commands.html null检查
- _server_to_dict()补last_checked_at+ssh_key_public
- _field_match()逗号cron表达式修复
- alerts类型显示、SSH会话名称、搜索高亮定位
- 一次性/循环定时任务(run_mode+fire_at+自动禁用)

Dead code removed (400+ lines):
- SyncService batch_push/_push_single等5个方法(零调用者)
- 5个未使用schema(SyncCommands/SyncConfig/SyncSftp/FileDeploy/PaginatedResponse)
- 6个零调用service方法、3个无前端API端点
- 4个未使用import

Schema migrations:
- push_schedules: run_mode + fire_at列,cron_expr改NULL
- servers: 7个新列 + ssh_key_private/public VARCHAR(500)→TEXT

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-24 16:26:40 +08:00

5.9 KiB
Raw Blame History

2026-05-24 批量审查修复 — 27项全部处理

日期: 2026-05-24 动机: 全面扫描项目,发现未实现/不完整/死代码问题 27 项,逐项沟通后全部处理 变更摘要:

Bug 修复

  • B-01: Agent API Key 验证完全失效 — verify_api_key() 参数传错,改为 Depends() 模式
  • B-02: upgrade-agent 不检查/更新依赖 — 增加 Python 版本预检 + 自动 pip install(锁版本)+ 备份回滚
  • B-03: POST /api/servers/push 死端点 — 删除端点 + ServerPush schema + ServerService.push_to_servers()

功能补全

  • U-01: POST /api/servers/check 无前端入口 — servers.html 批量操作栏加「健康检查」按钮
  • U-03: POST /api/sync/commands 无前端入口且与 scripts/exec 冗余 — 删除端点 + SyncCommands schema
  • U-04/U-05: POST /api/sync/config + config/rollback — 删除端点(sysctl 可通过脚本执行实现)
  • U-06: POST /api/sync/sftp 无前端入口 — 删除端点
  • C-03: Schedule script 类型缺少必填校验 — Pydantic model_validator 校验 script_id/script_content + push 模式 source_path
  • 定时任务支持一次性/循环模式 — Model 加 run_mode + fire_at,前端加切换 UI,执行后自动禁用

前端修复

  • FE-01: alerts.html getTopType() 硬编码"见详情" — API 加 top_types 查询,前端显示实际类型
  • FE-02: assets.html SSH 会话只显示 "Server #ID" — 加载服务器名称映射
  • FE-03: assets.html editNode sort_order 硬编码 0 — 回填原始值
  • FE-04: layout.js 搜索链接不定位到具体记录 — 加 ?highlight=id 参数,各页面自动定位

死代码清理

  • S-01: FileDeploy schema 零引用 — 删除
  • S-02: PaginatedResponse schema 零引用 — 删除
  • D-02: ServerService.list_servers() 零调用者 — 删除
  • D-03: ScriptService.test_credential_connection() 零调用者 — 删除
  • Engine: sync_commands()、sync_config()、_rollback_config()、sftp_transfer() 随端点删除

安全/质量

  • CFG-03: install.py 两处 silent pass — 改为 logger.warning

深度扫描第三轮 Bug 修复

  • BUG-1 [HIGH]: servers.py 路由遮蔽 — GET /logs 声明在 GET /{id} 之后,导致 /logs 被 /{id} 拦截(3个前端页面同步日志查询失败)。修复:将 /logs 移到 /{id} 之前
  • BUG-2 [CRITICAL]: terminal.html WebSSH 完全不可用 — 1) token URL 缺少 API 前缀 → 4042) apiFetch() 返回 Response 未调 .json() → TypeError3) 缺少 Content-Type header。三处全部修复
  • BUG-3 [MEDIUM]: schedule_runner.py _field_match() 提前返回 — 逗号分隔 cron 表达式(如 */5,1)遇到 */5 不匹配时直接 return False,不再检查后续 1。修复:step 不匹配时 continue 而非 return

深度扫描第四轮 Bug 修复

  • BUG-4 [CRITICAL]: scripts.html startExecPoll() 函数名错误 → startExecPolling(),长任务快速执行时 ReferenceError 崩溃
  • BUG-5 [HIGH]: agent.py {value!r!s:.50} 格式串语法非法,agent 发非数值时 ValueError — 修复为 {value!r:.50}
  • BUG-6 [HIGH]: alerts.html d.daily.reduce()d.top_servers[0] 无 null 检查,API 返回空数据时 TypeError — 加 ||[] 保护
  • BUG-7 [MEDIUM]: scripts.html doExec() 缺少 r.ok 检查,服务端错误被静默吞掉 — 加错误处理
  • BUG-8 [MEDIUM]: commands.html s.id.substring(0,8) 无 null 检查 — 改为 (s.id||'').substring(0,8)
  • BUG-9 [MEDIUM]: _server_to_dict() 缺少 last_checked_atssh_key_public 字段 — 补充返回
  • BUG-10 [MEDIUM]: 限速脚本 EXPIRE 每次请求重置窗口,精确间隔可绕过 — 改用 Lua 脚本原子 INCR+条件EXPIRE
  • N-06 [HIGH]: install.php 的 ssh_key 列 VARCHAR(500) 存不下加密密钥 — 迁移加 MODIFY COLUMN → TEXT
  • N-07 [HIGH]: servers 表新列缺迁移 (platform_id/node_id/protocols/extra_attrs/connectivity/last_checked_at/ssh_key_configured) — 迁移补全
  • 清理: agent.py 冗余内联 import、servers.py/scripts.py 未使用 List 导入

涉及文件: web/app/scripts.html, web/app/alerts.html, web/app/commands.html, server/api/agent.py, server/api/servers.py, server/api/scripts.py, server/infrastructure/redis/script_callback_rate.py, server/infrastructure/database/migrations.py

深度扫描第五轮 Bug + 安全修复

  • BUG-11 [HIGH]: self_monitor.py Telegram 告警无冷却,Redis/MySQL 宕机时每30秒刷屏 — 加5分钟冷却 + 恢复时清除冷却
  • BUG-12 [HIGH]: schedule_runner.py 一次性调度执行超60秒会重复触发 — 执行前先设 last_run_at + disable
  • BUG-13 [MEDIUM]: websocket.py 僵尸连接只从字典移除,TCP 未关 — disconnect() 中主动 close()
  • BUG-14 [MEDIUM]: websocket.py _last_alert_time 字典无限增长 — 加1小时过期清理
  • BUG-15 [HIGH]: asyncssh_pool.py 全忙时 pool 超过 MAX_CONNECTIONS 无限增长 — _evict_one 返回 bool + 全忙等待/拒绝
  • SEC-1 [HIGH]: auth_jwt.py + main.py INSTALL_MODE 是导入时常量,安装后 JWT 认证仍禁用 — 改为动态函数 _is_install_mode()/is_install_mode()
  • SEC-2 [MEDIUM]: install.py /lock 端点无保护,可在管理员创建前调用阻止安装 — 加管理员存在性验证

涉及文件: server/background/self_monitor.py, server/background/schedule_runner.py, server/api/websocket.py, server/infrastructure/ssh/asyncssh_pool.py, server/api/auth_jwt.py, server/main.py, server/api/install.py

是否需迁移: 是 — push_schedules 表新增 run_mode + fire_at 列,servers 表补全新列 + ssh_key 列类型修复(自动迁移)

验证方式:

  • 一次性调度:创建后到 fire_at 时间自动触发并禁用
  • 循环调度:cron 表达式匹配时触发,不自动禁用
  • 健康检查:选服务器 → 点击按钮 → 显示结果
  • 全局搜索:搜索结果点击跳转到对应页面并展开记录
  • WebSSH:点击服务器终端 → 正常连接
  • 路由遮蔽:服务器页面同步日志正常加载
  • Cron 表达式:*/5,1 在分钟=1 时正确匹配