# 审计 — 2026-06-07 BL-06 Agent per-server key 强制 ## 范围 移除 Agent 认证 global `API_KEY` legacy 回退;涉及 3 个后端文件 + 1 个新测试文件。 | 文件 | 行数 | Read 范围 | |------|------|-----------| | `server/api/agent.py` | 379 | L40-93(认证函数) | | `server/api/servers.py` | 2056 | L619-636, L1625-1640(安装链路) | | `server/application/services/script_service.py` | 735 | L44-50(回调 key) | | `tests/test_agent_per_server_key.py` | 88 | 全文 | | `tests/load_test.py` | 202 | 顶部 docstring | | `tests/quick_load.py` | 87 | 顶部 docstring | ## Step 3 规则扫描 | H | 规则 | 结论 | |---|------|------| | H1 | Agent 认证 fail-closed | FIXED 移除 global 回退;无 per-server key → False | | H2 | 安装链路静默降级 | FIXED 无 key 明确 400/批量错误项 | | H3 | 长任务回调 key 泄露面 | FIXED 仅用 per-server key,无 global 回退 | | H4 | compare_digest 时序安全 | SAFE 保留 `secrets.compare_digest` | | H5 | DB 查服异常 | SAFE 保持 fail-closed return False | ## Closure | H | 判定 | 依据 | |---|------|------| | H1 | FIXED | `agent.py:60-82` 仅 `agent_api_key` 匹配 | | H2 | FIXED | `servers.py:627-633`, `servers.py:1635-1637` | | H3 | FIXED | `script_service.py:44-50` ValueError | | H4 | SAFE | `agent.py:82` compare_digest | | H5 | SAFE | `agent.py:68-76` except → False | ## 入口表(agent.py 受影响路由) | 方法 | 路径 | 鉴权 | |------|------|------| | POST | `/api/agent/heartbeat` | X-API-Key + per-server `agent_api_key` | | POST | `/api/agent/script-callback` | 同上 + job secret | ## 巡检补修(同日) | 项 | 原问题 | 修复 | |----|--------|------| | H6 | `receive_heartbeat` 认证后再次 `get_server`(重复查库) | `_verify_server_api_key` 返回 `Optional[Server]`,handler 复用 | | H7 | 验 key 通过后 `unknown_server` discarded 分支为死代码 | 删除;不存在/无 key/错 key 统一 401 | | H8 | `script-callback` docstring 仍写「per-server or global」 | 改为仅 per-server | | H9 | 无回归测试约束 `get_server` 调用次数 | `test_verify_server_key_single_get_server_per_auth_check` + `assert_called_once_with` | ## 生产只读探测(2026-06-07) | 探测 | 结果 | |------|------| | `GET /health` | 200 | | `POST /api/agent/heartbeat` 假 key | 401 | | `security_probe_external.sh` heartbeat/WS | PASS | 注:BL-06 完整语义(global key 不可冒充)需部署本地改动后生产才生效;当前生产假 key 已 401。 ## DoD - [x] ruff 零错误(改动文件) - [x] import server.main - [x] pytest `test_agent_per_server_key.py` 9 passed(含 `assert_called_once`) - [x] changelog ≥10 行 - [x] 无静默吞错;无 global key 降级 - [x] 心跳路径单次 `get_server`(巡检补修)