# 2026-06-04 — Code Review P1/P2 修复批次 3

## 摘要

接续批次 2，修复脚本并行 SSH 共用 AsyncSession、Settings 敏感项 API 脱敏、Telegram Token 前端留空不覆盖、Agent 未知 server 不再回退全局 Key、WebSocket/WebSSH 无效 JWT 关闭码统一为 4401。

## 动机

全量 review 剩余项：脚本批量下发并行 `get_by_id` 竞态；`GET /settings/` 仍返回 Telegram token 明文前缀；空字符串 PUT 可能误清空 token；未知 server_id 用 global key 通过认证；无效 JWT 与缺失 token 关闭码混用 4001。

## 涉及文件

| 区域 | 文件 |
|------|------|
| 脚本 | `script_service.py`（预加载 server_map，并行 SSH 前隔离 DB） |
| 设置 API | `settings.py`（`_format_setting_response`、`value_set`、敏感项空 PUT 跳过） |
| Agent | `agent.py`（server 必须存在；unknown id 拒绝；legacy global 仅无 per-server key） |
| WebSocket | `websocket.py`、`webssh.py`（无效 JWT → 4401，缺失 token 仍 4001） |
| 前端 | `SettingsPage.vue`、`types/api.ts`（Telegram token draft + reveal + value_set） |

## 行为变更

- **Settings 列表/单项**：`telegram_bot_token` 等敏感项返回 `value=""` + `value_set: true`，不再带部分明文。
- **Settings PUT**：敏感 key 提交空字符串时保留原值（未配置则 400）。
- **Settings 页**：Bot Token 留空不提交；眼睛图标经 `/settings/telegram/reveal-token` 二次验证后填入 draft。
- **Agent**：不存在的服务器 ID 一律 401；DB 查服异常 fail-closed。
- **WS/WebSSH**：过期/无效 JWT 关闭码 4401，便于前端区分「未登录」与「会话失效」。

## 未纳入本批次（需协议变更）

- WebSocket JWT 移出 query 字符串（需前后端首帧鉴权协议）。
- 完全禁用 Agent global API_KEY 回退（会破坏未分配 per-server key 的旧 Agent）。

## 迁移 / 重启

- 重启 `nexus` Supervisor 服务。
- 前端重新 `vite build` 部署。

## 验证

```bash
.venv/bin/ruff check server/application/services/script_service.py server/api/settings.py server/api/agent.py server/api/websocket.py server/api/webssh.py
.venv/bin/python -c "import server.main"
.venv/bin/pytest tests/test_security_unit.py tests/test_retry_runner_outcome.py -q
cd frontend && npm run type-check
```

结果：ruff ✅ · import ✅ · pytest 28 passed ✅ · vue-tsc ✅

进度：`☑实现 ☑WSL验证 ☑审计8步 □部署 □健康检查 □浏览器验证 ☑changelog`
