# Phase 1 Delta 审计 — Wave D2（认证 / 安装 / WS / Agent）

**日期**: 2026-06-04  
**范围**: Code Review batch2 后 delta — 认证与 Agent 路径  
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步

## 登记

| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/install.py` | Python | 746 | 1–746 全文 |
| 2 | `server/api/auth.py` | Python | 374 | 1–374 全文 |
| 3 | `server/api/auth_jwt.py` | Python | 274 | 1–274 全文 |
| 4 | `server/api/websocket.py` | Python | 552 | 1–552 全文 |
| 5 | `server/api/agent.py` | Python | 378 | 1–378 全文 |

## 入口表

### install.py

| 方法 | 路径 | 鉴权 |
|------|------|------|
| GET | `/api/install/status` | 无（已锁定 404） |
| GET | `/api/install/env-check` | 安装模式 + 未 lock |
| POST | `/api/install/init-db` | 无 .env + 未 lock |
| POST | `/api/install/create-admin` | `install_token` |
| POST | `/api/install/lock` | 需已有 admin |
| GET | `/api/install/state` | 未 lock |

### auth.py

| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST | `/api/auth/login` | 公开 |
| POST | `/api/auth/refresh` | Cookie/body refresh |
| POST | `/api/auth/logout` | Cookie |
| POST | `/api/auth/totp/*` | JWT + self admin_id |
| PUT | `/api/auth/password` | JWT + 当前密码 (+TOTP) |
| POST | `/api/auth/webssh-token` | JWT + server 存在 |
| GET | `/api/auth/me` | JWT |

### websocket.py

| 类型 | 路径 | 鉴权 |
|------|------|------|
| WS | `/ws/alerts` | Query `?token=` JWT |
| WS | `/ws/sync` | 同上 |

### agent.py

| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST | `/api/agent/heartbeat` | X-API-Key +  per-server key |
| POST | `/api/agent/script-callback` | X-API-Key + job secret + rate limit |

## Closure 表

| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Install-lock | install.py:344-350 | SAFE | `_reject_if_locked` 阻断突变 |
| H-Install-token | install.py:314-327 | SAFE | `secrets.compare_digest` 一次性 token |
| H-Install-token | install.py:601 | SAFE | create-admin 必须 token |
| H-Install-SQL | install.py:540-544 | SAFE | 参数化 INSERT settings |
| H-Install-DDL | install.py:489-503 | SAFE | DDL 幂等 except pass |
| H-Install-subprocess | install.py:273-293 | SAFE | crontab/supervisor 固定 argv |
| H-Auth-brute | auth.py:125-138 | SAFE | 429/202 由 AuthService |
| H-Auth-cookie | auth.py:38-54 | SAFE | HttpOnly + Secure(HTTPS) + SameSite=Lax |
| H-Auth-TOTP-IDOR | auth.py:223-259 | SAFE | admin_id 必须等于 JWT sub |
| H-Auth-password | auth.py:288-305 | SAFE | bcrypt + token_version 失效 |
| H-Auth-webssh | auth.py:330-349 | SAFE | 短效 server-bound token |
| H-JWT-middleware | auth_jwt.py:78-146 | SAFE | ASGI 层拦截 /api/* |
| H-JWT-public | auth_jwt.py:38-50 | SAFE | 公开前缀含 agent/install/ws |
| H-JWT-tv | auth_jwt.py:222-226 | SAFE | token_version 精确匹配 |
| H-WS-auth | websocket.py:303-311 | SAFE | 无 token → 4001；无效 → 4401 |
| H-WS-auth | websocket.py:366-407 | SAFE | tv + updated_at 双检 |
| H-WS-ADR011 | websocket.py:9,300 | RISK | JWT 在 query；单人运维已接受 ADR-011 |
| H-Agent-key | agent.py:40-57 | SAFE | compare_digest；handler 二次验 per-server |
| H-Agent-unknown | agent.py:193-199 | SAFE | 未知 server 200 discard，不写入 |
| H-Agent-global | agent.py:84-92 | RISK | legacy global API_KEY；risk-acceptance 文档 |
| H-Agent-callback | agent.py:324-347 | SAFE | rate limit + job secret |
| H-Agent-no-exec | agent.py:378 | SAFE | 控制面无 shell exec |

**len(H)=22, Closure=22**

## FINDING

无 P0/P1 新 FINDING。RISK：WS query JWT、Agent global key — 见 `docs/project/risk-acceptance-single-operator.md`。

## DoD

- [x] len(H) == Closure
- [x] Read 1..N 全文
- [x] 入口表 + sink
- [x] 逐行完成 ✓（D2 五文件）

## 验证

```bash
bash scripts/local_verify.sh   # 预期全绿
```
