docs: consolidate archive, SSOT guide, and agent entry stubs

Move line-walk/delta/phase2/frontend audits and legacy memory into
docs/archive/, add functional development SSOT, thin AGENTS/CLAUDE stubs,
and regenerate changelog/audit indexes via consolidate_docs.py.
This commit is contained in:
Nexus Deploy
2026-06-04 23:01:03 +08:00
parent b866e944ab
commit 0100ab2582
181 changed files with 6474 additions and 1502 deletions
+27 -160
View File
@@ -1,176 +1,43 @@
# Nexus 6.0 — Cursor Rules # Nexus 6.0 — Cursor 速查
## 项目概述 > SSOT: [docs/project/nexus-functional-development-guide.md](docs/project/nexus-functional-development-guide.md)
Nexus 是一个 2000+ 服务器运维管理平台。技术栈:FastAPI + Async SQLAlchemy + Redis + WebSocket + Telegram (后端)Vue 3 + Vuetify 4 + TypeScript SPA (前端,14页面)。项目 ~99% 完成。 > Handoff: [docs/project/AI-HANDOFF-2026-06-03.md](docs/project/AI-HANDOFF-2026-06-03.md)
## 基本信息 ##
- 仓库: http://66.154.115.8:3000/admin/Nexus.git
- 本地路径: C:\Users\uzuma\Desktop\svn\Nexus
- 生产域名: https://api.synaglobal.vip
- 生产 IP: 47.254.123.106,后端端口 8600
- 部署路径: /www/wwwroot/api.synaglobal.vip/
- 管理员: admin / Nexus@2026
- 数据库: MySQL nexus/Nexus@2026!@127.0.0.1:3306/nexus
- SSH 别名: ssh nexus (key: id_rsa_nexus)
## 目录结构 FastAPI + Async SQLAlchemy + Redis · Vue 3 + Vuetify 4 SPA14 页)· Vite → `web/app/`
```
Nexus/
├── server/ ← FastAPI 后端 (Clean Architecture 4层)
│ ├── api/ ← API 路由
│ ├── domain/ ← SQLAlchemy 模型 (14+张表)
│ ├── infrastructure/← SSH 连接池 + Redis + Telegram
│ ├── background/ ← 后台任务
│ └── config.py ← Pydantic Settings + MySQL 覆盖
├── frontend/ ← Vue 3 + Vuetify 4 + TypeScript SPA
│ └── src/pages/ ← 14 个页面组件
├── web/app/ ← Vite 构建输出 (后端 StaticFiles 挂载点)
├── deploy/ ← Supervisor + Nginx + 健康检查脚本
├── docs/ ← 设计文档/审计/changelog
└── .env ← NOT IN GIT (安装向导生成)
```
## 实现原则(强制 ## 环境(勿在仓库写密码
**所有设计和实现都必须是完美实现。** - 生产: `https://api.synaglobal.vip` · 端口 8600 · `ssh nexus`
- 本地: `~/Nexus` 或 `$NEXUS_ROOT` · 见 [linux-dev-paths.md](docs/project/linux-dev-paths.md)
- 凭据: 仅 `.env`(不入 git
- ❌ 不允许为了实现而实现 — 每一行代码必须有明确的目的和质量标准 ## 关键路径
- ❌ 不允许降级实现 — 不得以「先用着」为由降低安全、架构或代码质量标准
- ❌ 不允许妥协实现 — 不得在发现问题后选择绕过而非根治
- ❌ 不允许留技术债 — 发现问题必须当场修复,不得标注 TODO/FIXME 延后
- ✅ 无法完美实现时必须停下来与用户交流后再换方案,不得擅自从权
## 安全铁律(强制) | 用途 | 路径 |
|------|------|
| 后端入口 | `server/main.py` |
| 前端路由 | `frontend/src/router/index.ts` |
| API 客户端 | `frontend/src/api/index.ts` |
| Sync | `server/api/sync_v2.py` |
| 门控 | `deploy/pre_deploy_check.sh` |
| 本地验证 | `bash scripts/local_verify.sh` |
- ❌ 禁止明文密码出现在前端 JS 变量、localStorage、URL 参数中 ## 铁律
- ❌ 禁止静默吞错 — except 块不得空 pass 或 return None 掩盖异常
- ❌ 禁止硬编码密钥/密码/Token — 必须走配置或环境变量
- ❌ 禁止 f-string 拼 SQL — 必须参数化查询
- ❌ 禁止未验证的用户输入拼入 shell 命令 — 必须用 shlex.quote() 或 subprocess 参数化
- ✅ 敏感操作必须二次验证身份(re-auth pattern
- ✅ API 响应不得返回密码/密钥明文 — 用 password_set 布尔标记
- ✅ 所有 CUD 操作必须记录审计日志
## 文档纪律(强制) 见 `.cursor/rules/perfect-implementation.mdc` · `nexus-security.mdc` — 完美实现、无静默吞错、无明文密钥、CUD 审计。
- 新功能/架构变更:先写 docs/design/specs/YYYY-MM-DD-*-design.md,再写代码 ## 部署
- 开发前:写 docs/design/plans/ 或 docs/reports/ 技术文档
- 项目缺文档的模块:改动时一并补全
- 每次修改:在 docs/changelog/YYYY-MM-DD-*.md 留 changelog(行数≥10,不能空壳)
## 强制文件修改流程(不可跳步)
```
实现 → WSL本地验证 → ★审计8步★ → 部署 → 健康检查 → 浏览器验证 → changelog
```
进度条(每次改代码必须输出):
```
□实现 □WSL验证 □审计8步 □部署 □健康检查 □浏览器验证 □changelog
```
审计8步:登记→全文Read→规则扫描H→Closure表→入口表→输入→Sink→归类→DoD
## 部署流程
### 后端部署
```bash ```bash
git push origin main bash deploy/pre_deploy_check.sh && bash deploy/deploy-production.sh
ssh nexus "cd /www/wwwroot/api.synaglobal.vip && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus"
ssh nexus "sleep 3 && curl -s http://127.0.0.1:8600/health" # 预期: ok
``` ```
### 前端部署 前端: `cd frontend && npx vite build` → tar/scp(见 `deploy/deploy-frontend.sh`
```bash
cd frontend && npx vite build && cd .. ## 进度条(改代码时输出)
tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/
scp /tmp/nexus-frontend.tar.gz nexus:/tmp/nexus-frontend.tar.gz
ssh nexus "cd /www/wwwroot/api.synaglobal.vip/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz"
``` ```
□实现 □本地验证 □审计8步 □部署 □健康检查 □浏览器验证 □changelog
### 本地开发
```bash
cd frontend && npm run dev # http://localhost:3000/app/
``` ```
## 7道门控 (deploy/pre_deploy_check.sh)
1. Changelog门 — 文件存在且行数≥10
2. Audit门 — 文件存在且含 Step3+Closure+DoD
3. Test门 — test_api.py 必须存在且通过
4. Lint门 — ruff check server/ 零错误
5. Import门 — import server.main 成功
6. Security门 — bandit 无 HIGH/MEDIUM
7. Review门 — 审计文件包含实际改动文件清单
## 已确认的关键决策
| 不可改项 | 原因 |
|---------|------|
| API_KEY | 加密一致性 + 子服务器认证 |
| SECRET_KEY | 加密回退密钥 |
| DATABASE_URL | 启动必需 |
| ENCRYPTION_KEY | 凭据加密 |
| 可改项 | 说明 |
|--------|------|
| system_name/title | 前端显示 |
| pool_size/overflow | 安装向导自动推荐 |
| redis_url | Redis 连接 |
| 告警阈值 | 默认 80% |
| Telegram 配置 | 告警推送 |
## 关键文件速查
| 用途 | 文件路径 |
|------|----------|
| 后端入口 | server/main.py |
| 数据模型 | server/domain/models/__init__.py |
| JWT 认证 | server/api/auth_jwt.py |
| 登录 API | server/api/auth.py |
| WebSSH | server/api/webssh.py |
| WebSocket | server/api/websocket.py |
| 设置 CRUD | server/api/settings.py |
| 服务器 CRUD | server/api/servers.py |
| 快捷命令 | server/api/terminal.py |
| Agent 心跳 | server/api/agent.py |
| 同步引擎 | server/application/services/sync_engine_v2.py |
| 前端入口 | frontend/src/main.ts |
| 路由 | frontend/src/router/index.ts |
| API 客户端 | frontend/src/api/index.ts |
| Auth Store | frontend/src/stores/auth.ts |
| 登录页 | frontend/src/pages/LoginPage.vue |
| 终端页 | frontend/src/pages/TerminalPage.vue |
| Vite 配置 | frontend/vite.config.mts |
## 已知待续事项(2026-06-01
已修复:批量 Agent、JWT 60min+refresh、script-callback API Key、未知心跳丢弃、Admin 列迁移 — 见 `docs/changelog/2026-06-01-bug-remediation.md`。
| 优先级 | 问题 | 文件 |
|--------|------|------|
| P2 | 422 handler 是否精简 | server/main.py |
| UX | 终端命令栏高亮对齐 | TerminalPage.vue |
| 验收 | 告警/Telegram、WebSSH、Sync、三层守护 | 见 handoff §八 |
## 协作方式(单 Agent
- 只与用户直接对话,不分派管理组/工程部/测试部/产品部/设计部,不自动加载 Skill 包。
- 规范见 `.cursor/rules/no-department-agents.mdc`、`standards/`、`docs/design/`。
## 测试分工(强制)
**由 Agent 完成全部测试与修复验证;用户仅在 Agent 报告通过后做最终验收。**
Agent 在宣称「已修复 / 可交付」前必须自行完成(有证据:命令输出、生产 URL、浏览器抽测记录):
1. 本地:`ruff` / `import server.main` / `frontend` type-check(若改前端)
2. 能跑则跑:`pytest tests/` 或 `tests/test_api.py`
3. 生产或 WSL`/health`、`test_api`、关键页面浏览器验证
4. 更新 `docs/changelog/` + 必要时 `docs/reports/*-verification.md`
**禁止**把「请你试一下」「请人工确认」当作交付终点;未验证不得让用户代测 bug 是否修好。
用户终验:Agent 提交「验收清单」后,用户做最后一遍业务确认即可。
## 用中文回复
+32 -168
View File
@@ -1,180 +1,44 @@
# Nexus 6.0 — Project Memory # Nexus 6.0 — Agent 入口(薄 stub
## 项目概述 > **长文 SSOT**: [docs/project/nexus-functional-development-guide.md](docs/project/nexus-functional-development-guide.md) + [附录](docs/project/nexus-functional-development-guide-appendix.md)
Nexus 是一个 2000+ 服务器运维管理平台,从旧的 MultiSync (PHP + AdminLTE + pymysql) 完全重构为 Clean Architecture (FastAPI + Async SQLAlchemy + Redis + WebSocket + Telegram)。前端已全面迁移到 Tailwind CSS v4 + Alpine.jsPHP 依赖已移除。 > **会话接续**: [docs/project/AI-HANDOFF-2026-06-03.md](docs/project/AI-HANDOFF-2026-06-03.md)
> **文档总索引**: [docs/README.md](docs/README.md)
## 仓库结构 ## 项目概要
- **唯一仓库**: Nexus (Gitea, 仓库地址在 .env 中配置)
- **不再使用** multi-server-sync 仓库(旧项目,仅保留历史)
- **部署路径**: 由 `NEXUS_DEPLOY_PATH` 环境变量决定(安装向导自动写入 .env)
- **域名/CORS**: 由 `NEXUS_CORS_ORIGINS` 环境变量决定(安装向导自动写入)
## 目录结构 (仓库根目录) Nexus2000+ 子机运维平台。后端 FastAPI + MySQL + Redis;前端 **Vue 3 + Vuetify 4 + TypeScript SPA**14 页,`frontend/src/pages/`);构建输出 `web/app/`;安装向导 `web/app/install.html`
```
Nexus/ ## 本地开发
├── server/ ← Python FastAPI后端 (Clean Architecture 4层)
│ ├── api/ ← API路由 (含 install.py 安装向导API) ```bash
│ ├── domain/ ← SQLAlchemy模型 (14张表) docker compose up -d mysql redis
│ ├── infrastructure/← SSH连接池 + Redis + Telegram bash scripts/start-dev.sh # API :8600
│ ├── background/ ← 后台任务 (心跳刷新/自检/调度/重试) bash scripts/local_verify.sh # L2b
│ └── config.py ← Pydantic Settings + MySQL覆盖 cd frontend && npm run dev # :3000/app/
├── web/app/ ← Tailwind+Alpine.js 纯静态前端 (12个HTML页面)
│ ├── install.html ← 安装向导 (5步)
│ ├── login.html ← JWT登录+TOTP双因素
│ └── ... ← index/servers/files/push/scripts等
├── deploy/ ← Supervisor配置 + Shell健康检查脚本
├── docs/ ← 项目文档
├── tests/ ← 测试
├── .env ← NOT IN GIT (安装向导生成)
└── requirements.txt ← Python依赖
``` ```
## 启动模式 路径见 [linux-dev-paths.md](docs/project/linux-dev-paths.md)。
- **安装模式** (无 .env): 仅 `/api/install/` + 静态文件可用,其他路由返回503
- **正常模式** (有 .env): 完整初始化 DB/Redis/后台任务
## 实现原则(强制) ## 强制约束
**所有设计和实现都必须是完美实现。** 详见 `.cursor/rules/perfect-implementation.mdc` - 完美实现:`.cursor/rules/perfect-implementation.mdc`
- 安全 / 后端 / 前端:`.cursor/rules/nexus-*.mdc`
- 改代码必 `docs/changelog/YYYY-MM-DD-*.md`(≥10 行)
- 测试由 Agent 完成;用户只做终验
| 禁止 | 要求 | ## 不可改
|------|------|
| 为实现而实现、降级、妥协、技术债(TODO/FIXME 延后) | 每一变更达到安全/架构/质量标准 |
| 无法完美实现时擅自从权换方案 | 停下与用户沟通,确认后再换方案 |
| 无文档直接开发 | 设计文档 → 技术文档 → 代码 |
| 改代码不写 changelog | 每次修改记录到 `docs/changelog/YYYY-MM-DD-*.md` |
文档路径:设计 `docs/design/specs/` · 技术 `docs/design/plans/` `docs/reports/` · 变更 `docs/changelog/` `API_KEY` · `SECRET_KEY` · `ENCRYPTION_KEY` · `DATABASE_URL`
## AI 接续与标准(切换会话必读) ## 部署
| 文档 | 路径 | ```bash
|------|------| bash deploy/pre_deploy_check.sh
| 接续 SSOT | `docs/project/AI-HANDOFF-2026-05-23.md` | bash deploy/deploy-production.sh # 需 SSH nexus + 用户批准
| **标准转接包(全量)** | `docs/project/standards-transfer-package.md` |
| 验收 L0L5 | `docs/project/development-acceptance-standard.md` |
| 系统开发 / 逐行审计 | `standards/system-development-standard.md``standards/line-walk-audit-standard-v2.md``standards/audit-core-principles.md` |
逐行审查与开发规范**同等强制**(8 步、Closure 全表、FINDING 须 `文件:行号`、单回复 ≤5 文件)。
## Cursor 规则与 MCP
- 规则:`.cursor/rules/``perfect-implementation` + `nexus-*` + `audit-line-review` + `no-department-agents`
- 不安装项目级 Skill 包(已移除 superpowers-zh);TDD/调试/验收按 `standards/` 由 Agent 直接执行
- MySQL MCP`docs/project/mysql-mcp-setup.md` · 配置后运行 `python scripts/sync_mysql_mcp_env.py`
## 已确认的关键决策
| 决策 | 选择 | 原因 |
|------|------|------|
| API_KEY | ❌ 禁改,UI不显示 | 加密一致性 + 子服务器认证 |
| SECRET_KEY | ❌ 禁改 | 加密回退密钥 |
| DATABASE_URL | ❌ 禁改 | 启动必需 |
| system_name/title | ✅ 可改 | 前端显示 |
| pool_size/overflow | ✅ 可改 | 安装向导自动推荐 |
| redis_url | ✅ 可改 | Redis连接 |
| 告警阈值 (CPU/mem/disk) | ✅ 可改 | 监控参数 (默认80%) |
| Telegram配置 | ✅ 可改 | 告警推送 |
| Agent心跳间隔 | 60s | 不太频繁 |
| Redis→MySQL刷新 | 10min | 降低MySQL负载 |
| 心跳数据流 | Agent→Redis→前端直读→10min→MySQL | 前端实时, MySQL只存历史 |
| 告警推送 | WebSocket→前端 + Telegram | 即时感知 |
| Python守护 | 3层: Supervisor + Python自检(30s) + Shell(cron 1min) | 全覆盖 |
| 安装向导 | install.html + FastAPI API | 纯Python,无PHP依赖 |
| 配置源 | 安装向导→config.json+settings表(MySQL)+.env(Python) | 三写一致 |
| Agent告警心跳 | CPU/内存>80% 或变化>10% 时主动上报 | 智能监控 |
| 仓库统一 | 所有代码统一在Nexus仓库 | 不再用两个仓库 |
## 实现状态 (Phase A+B+C+D+E) — ~99% 完成
### ✅ 已完成 (全部6步 + 技术债务 + UX增强)
| 模块 | 文件 | 说明 |
|------|------|------|
| **Step 0: 基础设施** | | Redis + WebSocket |
| E1 WebSocket推送 | server/api/websocket.py | alert/recovery/system broadcast |
| E2 心跳→Redis+告警 | server/api/agent.py | Redis write + threshold detection |
| E3 Redis→MySQL刷新 | server/background/heartbeat_flush.py | 10min batch |
| **Step 1: 数据层** | | 14张表 |
| E4 load_settings_from_db | server/config.py | MySQL overrides mutable settings |
| **Step 2: 认证层** | | JWT + TOTP |
| **Step 3: Web SSH** | | asyncssh + xterm.js |
| E5 asyncssh连接池 | server/infrastructure/ssh/asyncssh_pool.py | 引用计数模式 |
| E6 WebSSH前端 | web/app/terminal.html | xterm.js + Koko协议 + 自动resize |
| **Step 4: Sync引擎** | | 4种同步模式 |
| **Step 5: 前端迁移** | | Tailwind+Alpine.js |
| E7 13个前端页面 | web/app/*.html | 含install.html安装向导 |
| E8 安装向导API | server/api/install.py | 6端点, 无JWT, 临时引擎 |
| E9 条件启动模式 | server/main.py | 无.env=安装模式 |
| **后台任务** | | |
| E10 Python自检 | server/background/self_monitor.py | 30s loop |
| E11 Telegram推送 | server/infrastructure/telegram/__init__.py | alert/recovery/system |
| E12 /health端点 | server/api/health.py | Shell health_monitor.sh checks this |
| **技术债务** | | |
| D1 ✅ paramiko删除 | — | pool.py已删除, 全部迁移asyncssh |
| D2 ✅ install迁移 | server/api/install.py | PHP→install.html+API |
| D3 ✅ WebSSH前端 | web/app/terminal.html | xterm.js+Koko协议+全屏 |
| **安全增强** | | |
| S1 JWT全局保护 | server/api/*.py | 所有业务API都有JWT验证 |
| S2 审计日志 | server/api/*.py | 所有CUD操作记录审计日志 |
| S3 登录防暴破 | server/application/services/auth_service.py | 失败计数+15min锁定+429状态码 |
| **前端UX增强** | | |
| UX1 共享布局 | web/app/layout.js | 11页面统一侧边栏+全局搜索+用户信息 |
| UX2 Toast通知 | web/app/api.js | 全局toast()函数,4种类型 |
| UX3 全局搜索 | server/api/search.py | 跨服务器/脚本/凭据/调度搜索 |
| UX4 服务器详情 | web/app/servers.html | 点击展开详情面板(系统信息/同步日志/SSH会话) |
| UX5 脚本编辑 | web/app/scripts.html | 点击脚本名编辑+执行结果格式化 |
| UX6 推送增强 | web/app/push.html | 逐服务器状态+进度条+推送历史 |
| UX7 审计分页 | web/app/audit.html | 分页控件+操作过滤+每页50条 |
| UX8 重试操作 | web/app/retries.html | 手动重试+删除按钮+状态过滤 |
| UX9 文件浏览 | web/app/files.html | 面包屑导航+目录排序+父目录链接 |
| UX10 登录安全 | web/app/login.html | 密码可见切换+失败计数+429锁定+shake动画 |
| **P1功能补全** | | |
| P1-1 资产管理 | web/app/assets.html | Platform/Node管理页面 |
| P1-2 服务器表单 | web/app/servers.html | 补全platform/node/protocols字段 |
| P1-3 Push对接 | web/app/push.html + sync_v2.py | target_path对接+统一SyncEngineV2 |
| P1-4 安全设置 | web/app/settings.html | TOTP QR码+修改密码+API Key复制 |
| P1-5 WebSSH授权 | server/api/webssh.py | SSH凭据验证+4003关闭码+审计 |
| P1-6 Agent认证 | server/api/agent.py | 每服务器API Key + 全局回退 |
| P1-7 Config去重 | server/application/services/sync_engine_v2.py | sed去重+备份+_rollback_config() |
| **P2安全增强** | | |
| P2-1 告警防抖 | server/api/websocket.py | 5分钟冷却+Telegram去重+恢复重置 |
| P2-2 命令日志 | web/app/commands.html | 命令/会话双视图+服务器过滤+危险命令高亮 |
| P2-3 DB分页 | server/infrastructure/database/server_repo.py | DB层offset/limit+count |
| P2-4 Dashboard实时 | web/app/index.html | WS触发stats刷新+声音+标签页闪烁 |
| P2-5 移动适配 | web/app/layout.js | <768px侧边栏overlay+backdrop+表格滚动 |
| P2-6 会话安全 | server/api/auth_jwt.py + api.js | 8小时超时+JWT updated_at+刷新重用检测 |
| P2-7 凭据加密 | server/api/servers.py | Server.password/ssh_key_private Fernet加密存储 |
| P2-8 凭据脱敏 | server/api/scripts.py + servers.py | API响应不返回密码,password_set布尔标记 |
| P2-9 DB备份 | deploy/db_backup.sh | mysqldump+30天保留+cron集成 |
### 🔄 待测试
- T1: 心跳Redis写入验证
- T2: WebSocket连接测试
- T3: 3层守护测试 (kill Python→Supervisor重启)
- T4: Telegram推送测试
- T5: install.html 5步流程测试
### 测试流程 (用户确认)
1. WSL本地基础测试 → 2. 推到仓库 → 3. 外网服务器正式测试
## 配置三写机制
安装向导 Step 3 POST处理同时写入:
1. `web/data/config.json` — 共享配置 (API_BASE_URL, DB_*, API_KEY)
2. `.env` — Python后端启动必需 (NEXUS_前缀)
3. `settings` MySQL表 — 共享动态配置 (api_key, thresholds, Telegram等)
不可改项 (SECRET_KEY/API_KEY/ENCRYPTION_KEY/DATABASE_URL) 不在MySQL覆盖映射中。
## 3层守护机制
- **Layer 1**: Supervisor — Python崩溃自动重启
- **Layer 2**: Python self_monitor — 每30s检查Redis/MySQL/WebSocket
- **Layer 3**: Shell health_monitor.sh — 每分钟HTTP GET /health, 连续3次失败→supervisorctl restart + Telegram
## 数据流
```
Agent心跳(60s) → Redis(实时) → 前端直读 → 10min批量 → MySQL(历史)
告警: CPU/mem/disk > threshold → WebSocket推送浏览器 + Telegram推送手机
恢复: 之前告警的指标恢复正常 → 自动推送恢复通知
Redis心跳key: heartbeat:{server_id} (HSET, TTL=600s)
Redis告警key: alerts:{server_id} (SET, TTL=3600s)
``` ```
详情见功能指南 §1718。
## 归档文档
历史审计合并卷:`docs/archive/README.md`
+19 -269
View File
@@ -1,278 +1,28 @@
# Nexus 6.0 — Project Memory # Nexus 6.0 — Agent 入口(薄 stub
## 项目概述 > 与 [AGENTS.md](AGENTS.md) 相同入口;长文见 [docs/project/nexus-functional-development-guide.md](docs/project/nexus-functional-development-guide.md)。
Nexus 是一个 2000+ 服务器运维管理平台,从旧的 MultiSync (PHP + AdminLTE + pymysql) 完全重构为 Clean Architecture (FastAPI + Async SQLAlchemy + Redis + WebSocket + Telegram)。前端已全面迁移到 Tailwind CSS v4 + Alpine.jsPHP 依赖已移除。
## 仓库结构 ## 快速链接
- **唯一仓库**: Nexus (Gitea, 仓库地址在 .env 中配置)
- **不再使用** multi-server-sync 仓库(旧项目,仅保留历史)
- **部署路径**: 由 `NEXUS_DEPLOY_PATH` 环境变量决定(安装向导自动写入 .env)
- **域名/CORS**: 由 `NEXUS_CORS_ORIGINS` 环境变量决定(安装向导自动写入)
## 目录结构 (仓库根目录) | 用途 | 路径 |
```
Nexus/
├── server/ ← Python FastAPI后端 (Clean Architecture 4层)
│ ├── api/ ← API路由 (含 install.py 安装向导API)
│ ├── domain/ ← SQLAlchemy模型 (14张表)
│ ├── infrastructure/← SSH连接池 + Redis + Telegram
│ ├── background/ ← 后台任务 (心跳刷新/自检/调度/重试)
│ └── config.py ← Pydantic Settings + MySQL覆盖
├── web/app/ ← Tailwind+Alpine.js 纯静态前端 (12个HTML页面)
│ ├── install.html ← 安装向导 (5步)
│ ├── login.html ← JWT登录+TOTP双因素
│ └── ... ← index/servers/files/push/scripts等
├── deploy/ ← Supervisor配置 + Shell健康检查脚本
├── docs/ ← 项目文档
├── tests/ ← 测试
├── .env ← NOT IN GIT (安装向导生成)
└── requirements.txt ← Python依赖
```
## 启动模式
- **安装模式** (无 .env): 仅 `/api/install/` + 静态文件可用,其他路由返回503
- **正常模式** (有 .env): 完整初始化 DB/Redis/后台任务
## 已确认的关键决策
| 决策 | 选择 | 原因 |
|------|------|------|
| API_KEY | ❌ 禁改,UI不显示 | 加密一致性 + 子服务器认证 |
| SECRET_KEY | ❌ 禁改 | 加密回退密钥 |
| DATABASE_URL | ❌ 禁改 | 启动必需 |
| system_name/title | ✅ 可改 | 前端显示 |
| pool_size/overflow | ✅ 可改 | 安装向导自动推荐 |
| redis_url | ✅ 可改 | Redis连接 |
| 告警阈值 (CPU/mem/disk) | ✅ 可改 | 监控参数 (默认80%) |
| Telegram配置 | ✅ 可改 | 告警推送 |
| Agent心跳间隔 | 60s | 不太频繁 |
| Redis→MySQL刷新 | 10min | 降低MySQL负载 |
| 心跳数据流 | Agent→Redis→前端直读→10min→MySQL | 前端实时, MySQL只存历史 |
| 告警推送 | WebSocket→前端 + Telegram | 即时感知 |
| Python守护 | 3层: Supervisor + Python自检(30s) + Shell(cron 1min) | 全覆盖 |
| 安装向导 | install.html + FastAPI API | 纯Python,无PHP依赖 |
| 配置源 | 安装向导→config.json+settings表(MySQL)+.env(Python) | 三写一致 |
| Agent告警心跳 | CPU/内存>80% 或变化>10% 时主动上报 | 智能监控 |
| 仓库统一 | 所有代码统一在Nexus仓库 | 不再用两个仓库 |
## 实现状态 (Phase A+B+C+D+E) — ~99% 完成
### ✅ 已完成 (全部6步 + 技术债务 + UX增强)
| 模块 | 文件 | 说明 |
|------|------|------|
| **Step 0: 基础设施** | | Redis + WebSocket |
| E1 WebSocket推送 | server/api/websocket.py | alert/recovery/system broadcast |
| E2 心跳→Redis+告警 | server/api/agent.py | Redis write + threshold detection |
| E3 Redis→MySQL刷新 | server/background/heartbeat_flush.py | 10min batch |
| **Step 1: 数据层** | | 14张表 |
| E4 load_settings_from_db | server/config.py | MySQL overrides mutable settings |
| **Step 2: 认证层** | | JWT + TOTP |
| **Step 3: Web SSH** | | asyncssh + xterm.js |
| E5 asyncssh连接池 | server/infrastructure/ssh/asyncssh_pool.py | 引用计数模式 |
| E6 WebSSH前端 | web/app/terminal.html | xterm.js + Koko协议 + 自动resize |
| **Step 4: Sync引擎** | | 4种同步模式 |
| **Step 5: 前端迁移** | | Tailwind+Alpine.js |
| E7 13个前端页面 | web/app/*.html | 含install.html安装向导 |
| E8 安装向导API | server/api/install.py | 6端点, 无JWT, 临时引擎 |
| E9 条件启动模式 | server/main.py | 无.env=安装模式 |
| **后台任务** | | |
| E10 Python自检 | server/background/self_monitor.py | 30s loop |
| E11 Telegram推送 | server/infrastructure/telegram/__init__.py | alert/recovery/system |
| E12 /health端点 | server/api/health.py | Shell health_monitor.sh checks this |
| **技术债务** | | |
| D1 ✅ paramiko删除 | — | pool.py已删除, 全部迁移asyncssh |
| D2 ✅ install迁移 | server/api/install.py | PHP→install.html+API |
| D3 ✅ WebSSH前端 | web/app/terminal.html | xterm.js+Koko协议+全屏 |
| **安全增强** | | |
| S1 JWT全局保护 | server/api/*.py | 所有业务API都有JWT验证 |
| S2 审计日志 | server/api/*.py | 所有CUD操作记录审计日志 |
| S3 登录防暴破 | server/application/services/auth_service.py | 失败计数+15min锁定+429状态码 |
| **前端UX增强** | | |
| UX1 共享布局 | web/app/layout.js | 11页面统一侧边栏+全局搜索+用户信息 |
| UX2 Toast通知 | web/app/api.js | 全局toast()函数,4种类型 |
| UX3 全局搜索 | server/api/search.py | 跨服务器/脚本/凭据/调度搜索 |
| UX4 服务器详情 | web/app/servers.html | 点击展开详情面板(系统信息/同步日志/SSH会话) |
| UX5 脚本编辑 | web/app/scripts.html | 点击脚本名编辑+执行结果格式化 |
| UX6 推送增强 | web/app/push.html | 逐服务器状态+进度条+推送历史 |
| UX7 审计分页 | web/app/audit.html | 分页控件+操作过滤+每页50条 |
| UX8 重试操作 | web/app/retries.html | 手动重试+删除按钮+状态过滤 |
| UX9 文件浏览 | web/app/files.html | 面包屑导航+目录排序+父目录链接 |
| UX10 登录安全 | web/app/login.html | 密码可见切换+失败计数+429锁定+shake动画 |
| **P1功能补全** | | |
| P1-1 资产管理 | web/app/assets.html | Platform/Node管理页面 |
| P1-2 服务器表单 | web/app/servers.html | 补全platform/node/protocols字段 |
| P1-3 Push对接 | web/app/push.html + sync_v2.py | target_path对接+统一SyncEngineV2 |
| P1-4 安全设置 | web/app/settings.html | TOTP QR码+修改密码+API Key复制 |
| P1-5 WebSSH授权 | server/api/webssh.py | SSH凭据验证+4003关闭码+审计 |
| P1-6 Agent认证 | server/api/agent.py | 每服务器API Key + 全局回退 |
| P1-7 Config去重 | server/application/services/sync_engine_v2.py | sed去重+备份+_rollback_config() |
| **P2安全增强** | | |
| P2-1 告警防抖 | server/api/websocket.py | 5分钟冷却+Telegram去重+恢复重置 |
| P2-2 命令日志 | web/app/commands.html | 命令/会话双视图+服务器过滤+危险命令高亮 |
| P2-3 DB分页 | server/infrastructure/database/server_repo.py | DB层offset/limit+count |
| P2-4 Dashboard实时 | web/app/index.html | WS触发stats刷新+声音+标签页闪烁 |
| P2-5 移动适配 | web/app/layout.js | <768px侧边栏overlay+backdrop+表格滚动 |
| P2-6 会话安全 | server/api/auth_jwt.py + api.js | 8小时超时+JWT updated_at+刷新重用检测 |
| P2-7 凭据加密 | server/api/servers.py | Server.password/ssh_key_private Fernet加密存储 |
| P2-8 凭据脱敏 | server/api/scripts.py + servers.py | API响应不返回密码,password_set布尔标记 |
| P2-9 DB备份 | deploy/db_backup.sh | mysqldump+30天保留+cron集成 |
| **P3运维增强** | | |
| P3-1 Nginx重定向 | deploy/nginx_https.conf | 注释化301规则:裸页面路径→/app/前缀 |
| P3-2 自定义404 | server/main.py | StarletteHTTPExceptionHandler返回空白HTML,隐藏FastAPI标识 |
### 🔄 待测试
- T1: 心跳Redis写入验证
- T2: WebSocket连接测试
- T3: 3层守护测试 (kill Python→Supervisor重启)
- T4: Telegram推送测试
- T5: install.html 5步流程测试
### 测试流程 (用户确认)
1. WSL本地基础测试 → 2. 推到仓库 → 3. 外网服务器正式测试
## 配置三写机制
安装向导 Step 3 POST处理同时写入:
1. `web/data/config.json` — 共享配置 (API_BASE_URL, DB_*, API_KEY)
2. `.env` — Python后端启动必需 (NEXUS_前缀)
3. `settings` MySQL表 — 共享动态配置 (api_key, thresholds, Telegram等)
不可改项 (SECRET_KEY/API_KEY/ENCRYPTION_KEY/DATABASE_URL) 不在MySQL覆盖映射中。
## 3层守护机制
- **Layer 1**: Supervisor — Python崩溃自动重启
- **Layer 2**: Python self_monitor — 每30s检查Redis/MySQL/WebSocket
- **Layer 3**: Shell health_monitor.sh — 每分钟HTTP GET /health, 连续3次失败→supervisorctl restart + Telegram
## 实现原则(强制 — 见 `.cursor/rules/perfect-implementation.mdc`
**所有设计和实现都必须是完美实现。**
- ❌ 不允许为了实现而实现 — 每一行代码必须有明确的目的和质量标准
- ❌ 不允许降级实现 — 不得以「先用着」为由降低安全、架构或代码质量标准
- ❌ 不允许妥协实现 — 不得在发现问题后选择绕过而非根治
- ❌ 不允许留技术债 — 发现问题必须当场修复,不得标注 TODO/FIXME 延后
- ✅ 无法完美实现时必须停下来与用户交流后再换方案,不得擅自从权
**文档纪律:**
- 新功能/架构变更:先写 `docs/design/specs/YYYY-MM-DD-*-design.md`,再写代码
- 开发前:写 `docs/design/plans/``docs/reports/` 技术文档(文件清单、步骤、测试、回滚)
- 项目缺文档的模块:改动时一并补全
- 每次修改:在 `docs/changelog/YYYY-MM-DD-*.md` 留 changelog
---
## 强制文件修改流程(不可跳步)
```
实现 → WSL本地验证 → ★审计8步★ → 部署 → 健康检查 → 浏览器验证 → changelog
```
**进度条(每次改代码必须输出,每完成一步打勾):**
```
□实现 □WSL验证 □审计8步 □部署 □健康检查 □浏览器验证 □changelog
```
用户只需看:没打勾的格子在打勾的格子后面 = 跳步了。
跳步 = 严重过程违规,用户说「你跳步了」必须立即停止并补完。
审计8步(我内部执行,用户不需要检查细节):登记→全文Read→规则扫描H→Closure表→入口表→输入→Sink→归类→DoD
审查4维度30项:安全12+逻辑8+性能5+质量5
三个铁律:每个文件都要审、每行代码都要看、每个结论都要有证据
**程序门控 v2(deploy 时自动检查 7 道,不过不让部署):**
| # | 门 | 检查内容 | 防什么 |
|---|----|---------|--------|
| 1 | Changelog门 | 文件存在 **且行数≥10** | 空壳changelog |
| 2 | Audit门 | 文件存在 **且含 Step3+Closure+DoD** | 空壳审计 |
| 3 | Test门 | test_api.py **必须存在**且通过 | 删测试绕过 |
| 4 | Lint门 | `ruff check server/` 零错误 | 代码质量问题 |
| 5 | Import门 | `import server.main` 成功 | 语法/导入错误 |
| 6 | Security门 | `bandit` 无 HIGH/MEDIUM | 安全反模式 |
| 7 | Review门 | 审计文件包含实际改动文件清单 | 假审查 |
门控脚本: `deploy/pre_deploy_check.sh`7门)
门控日志: `deploy/gate_log.jsonl`(每次检查自动追加记录)
MCP deploy 工具在 git pull + restart 前自动执行门控检查,任何一门不过返回 `🚫 DEPLOY BLOCKED`
MCP gate_log 工具可查看历史门控记录
审计模板: `docs/audit/TEMPLATE.md`
Lint配置: `ruff.toml`
开发依赖: `requirements-dev.txt`ruff, bandit, pytest
## 部署流程(SSH + SCP,不是 MCP deploy
**MCP deploy 不可用**GitHub 等 SaaS 的远程服务器 git pull 无凭据),实际部署用 SSH 命令直接操作:
### 后端部署
```bash
# 1. Push 本地到 Gitea
git push origin main
# 2. 服务器拉取最新代码 + 重启
ssh nexus "cd /www/wwwroot/api.synaglobal.vip && git fetch --all && git reset --hard origin/main && supervisorctl restart nexus"
# 3. 健康检查
ssh nexus "sleep 3 && curl -s http://127.0.0.1:8600/health"
# 预期: "ok"(纯文本,非 JSON
```
### 前端部署(Vuetify SPA
Vite 直接输出到 `web/app/`(后端 StaticFiles 挂载点),无需 dist 复制步骤:
```bash
# 一键部署脚本(构建+打包+上传+提取+重启+验证)
bash deploy/deploy-frontend.sh
# 或手动步骤:
cd frontend && npx vite build && cd ..
tar czf /tmp/nexus-frontend.tar.gz -C web/app index.html assets/
scp /tmp/nexus-frontend.tar.gz nexus:/tmp/nexus-frontend.tar.gz
ssh nexus "cd /www/wwwroot/api.synaglobal.vip/web/app && tar xzf /tmp/nexus-frontend.tar.gz && rm /tmp/nexus-frontend.tar.gz"
ssh nexus "supervisorctl restart nexus"
```
**注意**: 前端构建产物 (`web/app/index.html`, `web/app/assets/`) 已在 `.gitignore` 中,不进入 git。每次部署需重新构建+上传。
### 浏览器验证
```bash
curl -s -o /dev/null -w "%{http_code}" http://47.254.123.106:8600/app/ # 预期: 200
```
### 部署常遇问题
| 问题 | 解决 |
|------|------| |------|------|
| `/app/` 返回 404 | AppAuthMiddleware 拦截 — 确认 `/app/``/app/index.html``_APP_PUBLIC_PATHS` | | 功能 / API / 14 页 | `docs/project/nexus-functional-development-guide.md` |
| `/app/` 返回旧 HTML (Tailwind/Alpine) | `git reset --hard` 恢复了旧文件 — 需要重新 tar+scp 前端构建产物 | | 附录(sync 端点、调用链) | `docs/project/nexus-functional-development-guide-appendix.md` |
| MCP deploy → git pull 失败 `could not read Username` | 服务器 remote URL 没配 token,用 `git remote set-url` | | 当前 handoff | `docs/project/AI-HANDOFF-2026-06-03.md` |
| Gate 2 Audit BLOCKED | 创建 `docs/audit/YYYY-MM-DD-topic.md`,含 Step3+Closure+DoD | | 本地验证 | `bash scripts/local_verify.sh` |
| Gate 3 Test BLOCKED (401) | 服务器 .env 中 `NEXUS_TEST_ADMIN_PASSWORD` 与数据库不一致 | | 验收 L0L5 | `docs/project/development-acceptance-standard.md` |
| Gate 6 Security BLOCKED (bandit HIGH) | md5 → sha256 等,参看 bandit 报告修复 | | 风险接受(单人运维) | `docs/project/risk-acceptance-single-operator.md` |
| Gate 7 Review BLOCKED | 审计文件缺少实际改动文件清单 | | 文档索引 | `docs/README.md` |
| 历史归档 | `docs/archive/README.md` |
### 部署信息速查 ##
- **部署用户**: root
- **部署目录**: `/www/wwwroot/api.synaglobal.vip/`
- **Supervisor 服务名**: `nexus`
- **Supervisor 配置**: `/www/server/panel/plugin/supervisor/etc/supervisor.conf`
- **SSH 别名**: `ssh nexus` (47.254.123.106, key: id_rsa_nexus)
- **后端端口**: 8600
- **Gitea Token SHA**: `26fee743a9332895b55f79b2dbe2e931dc7c2fe5` (nexus-deploy-token, write:repository)
**用户审查清单(验证AI是否偷懒):** FastAPI · Vue 3 SPA · Hash 路由 `#/` · 门控 `deploy/pre_deploy_check.sh`7 道)
1.`deploy/gate_log.jsonl` — 每次门控都有记录,没有记录 = 没过门控
2. 看审计文件 — 必须有 Closure 表(每个H的判定+依据)、Step 3 规则扫描、DoD ## 流程
3. 看进度条 — ☑必须在□前面,否则跳步
4. 看 changelog — 行数≥10,不能是空壳
## 数据流
``` ```
Agent心跳(60s) → Redis(实时) → 前端直读 → 10min批量 → MySQL(历史) 实现 → local_verify → 审计(按 diff 量级)→ changelog →(批准)部署
告警: CPU/mem/disk > threshold → WebSocket推送浏览器 + Telegram推送手机
恢复: 之前告警的指标恢复正常 → 自动推送恢复通知
Redis心跳key: heartbeat:{server_id} (HSET, TTL=600s)
Redis告警key: alerts:{server_id} (SET, TTL=3600s)
``` ```
强制规则:`.cursor/rules/` · `standards/`
+7 -316
View File
@@ -1,320 +1,11 @@
# Nexus 6.0 项目交接文档 # Nexus 6.0 项目交接(已 supersede
> **⚠️ 2026-05-23 起请以 SSOT 为准**: [`AI-HANDOFF`](docs/project/AI-HANDOFF-2026-05-23.md) · **全量标准** [`standards-transfer-package`](docs/project/standards-transfer-package.md) · 验收 [`development-acceptance-standard`](docs/project/development-acceptance-standard.md) 请以以下文档为准:
> 本文保留历史结构;端口模型、待办 backlog、验证清单、否决项均以 SSOT 为准。
## 项目概述 | 文档 | 路径 |
**项目名称**: Nexus 6.0
**类型**: 2000+ 服务器运维管理平台
**架构**: Clean Architecture (FastAPI + Async SQLAlchemy + Redis + WebSocket + Telegram)
**前端**: Tailwind CSS v4 + Alpine.js18 个 HTML 页面,含 `alerts.html`
**状态**: 核心代码 ~98% 完成;**尚未部署**;待办见 SSOT §4、验证见 SSOT §5
---
## 仓库信息
- **仓库地址**: Gitea (地址在 .env 中配置)
- **当前工作目录(Linux**: `~/Nexus`(见 `docs/project/linux-dev-paths.md`
- **Git分支**: 当前在 worktree 分支
---
## 技术栈
| 层级 | 技术 |
|------|------| |------|------|
| 后端框架 | FastAPI (Python 3.9+) | | 功能开发 SSOT | [docs/project/nexus-functional-development-guide.md](docs/project/nexus-functional-development-guide.md) |
| 数据库 | MySQL 8.0 + Async SQLAlchemy 2.0 | | 会话接续 | [docs/project/AI-HANDOFF-2026-06-03.md](docs/project/AI-HANDOFF-2026-06-03.md) |
| 缓存 | Redis | | 文档总索引 | [docs/README.md](docs/README.md) |
| 实时通信 | WebSocket |
| SSH连接 | asyncssh (连接池模式) |
| 告警推送 | Telegram Bot API |
| 前端 | Tailwind CSS v4 + Alpine.js |
| 进程守护 | Supervisor + Python自检 + Shell健康检查 |
--- 历史全文:[docs/archive/project/PROJECT_HANDOVER.md](docs/archive/project/PROJECT_HANDOVER.md)
## 目录结构
```
Nexus/
├── server/ # Python FastAPI 后端
│ ├── api/ # API路由层 (15个模块)
│ │ ├── agent.py # Agent心跳接收
│ │ ├── assets.py # Platform/Node资产管理
│ │ ├── auth.py # JWT登录/TOTP
│ │ ├── auth_jwt.py # JWT验证中间件
│ │ ├── files.py # 文件浏览
│ │ ├── install.py # 安装向导API
│ │ ├── push.py # 推送调度
│ │ ├── scripts.py # 脚本库管理
│ │ ├── servers.py # 服务器CRUD
│ │ ├── settings.py # 系统设置
│ │ ├── sync_v2.py # 同步引擎v2 (4种模式)
│ │ ├── webssh.py # WebSSH终端
│ │ └── websocket.py # WebSocket告警推送
│ ├── application/ # 应用服务层
│ │ └── services/ # 业务逻辑 (SyncEngineV2等)
│ ├── domain/ # 领域层
│ │ └── models/ # SQLAlchemy ORM (14张表)
│ ├── infrastructure/ # 基础设施层
│ │ ├── database/ # 数据库访问 (Repository模式)
│ │ ├── redis/ # Redis客户端
│ │ ├── ssh/ # SSH连接池 (asyncssh)
│ │ └── telegram/ # Telegram推送
│ ├── background/ # 后台任务
│ │ ├── self_monitor.py # Python自检 (30s)
│ │ ├── heartbeat_flush.py # Redis→MySQL刷新 (10min)
│ │ ├── scheduler.py # 定时推送调度
│ │ └── retry_worker.py # 失败重试队列
│ └── config.py # Pydantic Settings
├── web/app/ # 前端页面 (15个HTML)
│ ├── install.html # 安装向导 (5步)
│ ├── login.html # JWT登录+TOTP
│ ├── index.html # 仪表盘
│ ├── servers.html # 服务器管理
│ ├── assets.html # Platform/Node管理
│ ├── push.html # 文件推送
│ ├── scripts.html # 脚本库
│ ├── commands.html # 命令日志查询
│ ├── files.html # 远程文件浏览
│ ├── settings.html # 系统设置
│ ├── audit.html # 审计日志
│ ├── retries.html # 重试队列
│ ├── terminal.html # WebSSH终端
│ ├── api.js # 共享API模块 (JWT+Toast)
│ └── layout.js # 共享布局组件
├── deploy/ # 部署配置
│ ├── supervisor/ # Supervisor配置
│ ├── nginx/ # Nginx配置
│ └── db_backup.sh # 数据库备份脚本
├── docs/ # 项目文档
├── requirements.txt # Python依赖
└── test_p1_p2.py # 验证测试脚本
```
---
## 数据库模型 (14张表)
| 表名 | 说明 |
|------|------|
| `admins` | 管理员用户 (JWT+TOTP支持) |
| `servers` | 服务器资产 (核心表) |
| `platforms` | 平台类型模板 |
| `nodes` | 资产节点树 |
| `sync_logs` | 同步操作日志 |
| `push_schedules` | 定时推送调度 |
| `push_retry_jobs` | 失败重试队列 |
| `audit_logs` | 审计日志 |
| `scripts` | 脚本库 |
| `script_executions` | 脚本执行记录 |
| `password_presets` | SSH密码预设 |
| `db_credentials` | 数据库凭据 |
| `ssh_sessions` | WebSSH会话 |
| `command_logs` | SSH命令日志 |
| `login_attempts` | 登录防暴破记录 |
| `settings` | 系统配置键值对 |
---
## 核心功能清单
### P0 核心功能 (已完成)
- [x] JWT认证 + TOTP双因素
- [x] 登录防暴破 (15分钟锁定)
- [x] Agent心跳上报 (Redis实时)
- [x] WebSocket实时告警推送
- [x] Telegram告警通知
- [x] 安装向导 (5步)
### P1 功能 (已完成)
- [x] Platform/Node资产管理
- [x] 服务器详情面板 (点击展开)
- [x] WebSSH终端 (xterm.js)
- [x] 推送页面增强 (逐服务器状态+进度条)
- [x] 脚本编辑+执行结果格式化
- [x] 全局Toast通知系统
- [x] 审计日志分页+过滤
- [x] 重试队列手动操作
- [x] 文件浏览 (面包屑导航)
### P2 功能 (已完成)
- [x] 告警聚合防抖 (5分钟冷却)
- [x] 命令日志查询页面
- [x] 服务器列表DB级分页
- [x] Dashboard WebSocket实时刷新
- [x] 移动端响应式适配
- [x] 会话安全加固 (8小时超时)
- [x] 服务器凭据Fernet加密存储
- [x] 凭据API脱敏 (password_set标记)
- [x] 数据库自动备份脚本
### Sync引擎v2 (4种模式)
- [x] S1: 文件同步 (rsync)
- [x] S2: 命令批量执行 (SSH)
- [x] S3: 配置推送 (sysctl) + 去重 + 回滚
- [x] S4: SFTP文件传输
---
## 关键Bug修复记录
| 任务ID | 问题 | 修复内容 |
|--------|------|----------|
| #81 | DateTime默认求值BUG | 添加`_utcnow()`可调用函数,替换所有`default=datetime.now()` |
| #82 | session.py logger未定义 | 添加`import logging``logger`定义,移除@property死代码 |
| #83 | 审计日志缺失 | 验证所有CUD端点都有审计记录 |
| #84 | 模型缺失索引 | 添加7个索引(login_attempts, audit_logs等) |
---
## 环境配置
### 必需环境变量 (.env文件)
```bash
# 数据库
DATABASE_URL=mysql+aiomysql://user:pass@localhost/nexus
# 安全密钥 (安装时生成)
SECRET_KEY=xxx
API_KEY=xxx
ENCRYPTION_KEY=xxx
# Redis
REDIS_URL=redis://localhost:6379/0
# Telegram告警 (可选)
TELEGRAM_BOT_TOKEN=xxx
TELEGRAM_CHAT_ID=xxx
# 告警阈值
CPU_ALERT_THRESHOLD=80
MEM_ALERT_THRESHOLD=80
DISK_ALERT_THRESHOLD=80
```
### 启动模式
- **安装模式** (无.env): 仅 `/api/install/` + 静态文件可用
- **正常模式** (有.env): 完整初始化 DB/Redis/后台任务
---
## 部署步骤
### 1. 安装依赖
```bash
pip install -r requirements.txt
```
### 2. 运行安装向导
访问 `http://localhost:8000/app/install.html`
- Step 1: 数据库配置
- Step 2: Redis配置
- Step 3: 安全密钥生成
- Step 4: Telegram配置 (可选)
- Step 5: 创建管理员账号
### 3. 启动服务 (Supervisor)
```bash
# 复制配置
cp deploy/supervisor/nexus.conf /etc/supervisor/conf.d/
supervisorctl reread
supervisorctl update
supervisorctl start nexus
```
### 4. 验证运行
```bash
# 健康检查
curl http://localhost:8000/health
# 运行测试
python test_p1_p2.py
```
---
## 团队分工建议
| 角色 | 职责 | 相关文件 |
|------|------|----------|
| **后端开发** | API开发、业务逻辑 | `server/api/*.py`, `server/application/services/*.py` |
| **前端开发** | UI页面、交互逻辑 | `web/app/*.html`, `web/app/api.js`, `web/app/layout.js` |
| **DevOps** | 部署、监控、备份 | `deploy/`, `supervisor/`, `nginx/` |
| **DBA** | 数据库优化、迁移 | `server/domain/models/`, `server/infrastructure/database/` |
| **安全** | 审计、加密、认证 | `server/api/auth*.py`, 凭据加密逻辑 |
---
## 监控与告警
### 3层守护机制
1. **Supervisor**: Python崩溃自动重启
2. **Python自检** (`self_monitor.py`): 30秒检查Redis/MySQL/WebSocket
3. **Shell健康检查** (`health_monitor.sh`): 1分钟HTTP检查,3次失败重启
### 告警通道
- WebSocket → 前端实时通知
- Telegram → 手机推送
### 关键指标
- Agent心跳间隔: 60秒
- Redis→MySQL刷新: 10分钟
- 会话超时: 8小时
- 告警冷却: 5分钟
---
## 测试验证
### 已完成的测试
```bash
# 模块导入测试 (19/19通过)
python -c "import server.domain.models; ..."
# 功能测试 (7/7通过)
python test_p1_p2.py
# - JWT updated_at claim
# - JWT password invalidation
# - Alert dedup cooldown
# - Server repo pagination
# - Config dedup command
# - Server dict no password
# - Admin.updated_at field
```
---
## 注意事项
### ⚠️ 安全相关
1. **API_KEY**: 禁止修改,用于Agent认证
2. **SECRET_KEY**: 禁止修改,用于JWT签名
3. **ENCRYPTION_KEY**: 禁止修改,用于凭据加密
4. 生产环境必须修改默认密码
### ⚠️ 数据库迁移
首次启动会自动执行 `_apply_migrations()`:
- 添加 `admins.updated_at`
- 创建7个索引 (如果不存在)
### ⚠️ 文件权限
- SSH私钥文件需要正确权限 (600)
- 日志目录需要写权限
---
## 联系方式
- 项目文档: `docs/`
- 配置文件: `.env` (不提交到Git)
- 测试脚本: `test_p1_p2.py`
---
**交接日期**: 2026/05/22
**代码状态**: ✅ 开发完成,待部署测试
**Git提交**: 建议提交当前worktree更改到主分支
+62 -113
View File
@@ -1,125 +1,74 @@
# Nexus 文档索引 # Nexus 文档索引
> 最后更新: 2026-06-01 > 更新: 2026-06-04 · **唯一导航入口**
--- ---
## project/ — 项目概况 ## 1. 活跃 SSOT(日常必读)
| 文档 | 说明 |
|------|------|
| [project/nexus-functional-development-guide.md](project/nexus-functional-development-guide.md) | 功能 / API / 14 页 / 部署 |
| [project/nexus-functional-development-guide-appendix.md](project/nexus-functional-development-guide-appendix.md) | sync 端点、调用链、E2E 对照 |
| [project/AI-HANDOFF-2026-06-03.md](project/AI-HANDOFF-2026-06-03.md) | **当前** 会话接续(复制提示词) |
| [project/development-acceptance-standard.md](project/development-acceptance-standard.md) | 验收 L0L5 |
| [project/local-integration-test.md](project/local-integration-test.md) | `bash scripts/local_verify.sh` |
| [project/linux-dev-paths.md](project/linux-dev-paths.md) | Linux 路径 |
| [project/risk-acceptance-single-operator.md](project/risk-acceptance-single-operator.md) | 单人运维风险接受 |
| [project/script-execution.md](project/script-execution.md) | 脚本执行 |
| [project/alert-push-policy.md](project/alert-push-policy.md) | 告警策略 |
| [project/deploy.md](project/deploy.md) | 部署补充 |
| [project/production-verification-checklist.md](project/production-verification-checklist.md) | L5 清单 |
根目录 [AGENTS.md](../AGENTS.md) · [CLAUDE.md](../CLAUDE.md) · [.cursorrules](../.cursorrules) 为薄入口。
---
## 2. 变更与审计
| 目录 | 说明 |
|------|------|
| [changelog/](changelog/) | 每次代码变更(**不归档、不合并**)· [INDEX](changelog/INDEX.md) |
| [audit/](audit/) | 门控用审计 · [INDEX](audit/INDEX.md) · `2026-06-04-bug-scan-registry.json` |
---
## 3. 活跃报告(`reports/`
| 文件 | 说明 | | 文件 | 说明 |
|------|------| |------|------|
| `project/status.md` | 项目进度总览 + 数据库结构 + 实施进度 | | [audit-plugin-run-final-2026-06-04.md](reports/audit-plugin-run-final-2026-06-04.md) | 插件审计总验收 |
| `project/roadmap.md` | 功能规划 + ADR架构决策(11项) + 技术债务 | | [audit-frontend-14p-2026-06-04-closure.md](reports/audit-frontend-14p-2026-06-04-closure.md) | 前端 14 页 closure |
| `project/deploy.md` | 部署指南 (Ubuntu 20-24, Nginx+Supervisor) | | [audit-phase-4-plugin-closure-2026-06-04.md](reports/audit-phase-4-plugin-closure-2026-06-04.md) | Phase4 收尾 |
| **`project/phase-2-audit-remediation.md`** | **Phase 2 审计修复总览(开发 SSOT)** | | [2026-06-01-production-verification.md](reports/2026-06-01-production-verification.md) | 生产验证(待更新 L5 |
| **`project/wsl-integration-test.md`** | **WSL 代码验证**venv → 启动 → smoke,不审 key) | | [2026-06-01-final-acceptance-checklist.md](reports/2026-06-01-final-acceptance-checklist.md) | 终验清单 |
| `project/production-verification-checklist.md` | 首次部署验证清单(逐项勾选) |
| `project/alert-push-policy.md` | 告警推送产品策略 + 数据流 |
| `project/script-execution.md` | 脚本批量执行平台 SSOT |
| `project/audit-line-review-cursor-rule.md` | 逐行走读 Cursor 规则 |
| `project/line-walk-audit-standard.md` | 逐行走读判定标准 |
| `project/mysql-mcp-setup.md` | Cursor MySQL MCP 安装与 `.env` 同步 |
| `project/tech-stack-inventory.md` | 技术栈清单 + 连接池参数对齐 + v1勘误 |
## design/ — 设计规格与实施计划 批量 batch 报告 → [archive/audits/](archive/audits/) 合并卷。
### 活跃设计 ---
| 文件 | 说明 |
## 4. 设计与标准
| 目录 | 说明 |
|------|------| |------|------|
| `design/specs/design-standards.md` | **设计标准** — 安全模型/性能基线/代码规范/架构模式 | | [design/specs/](design/specs/) | 设计规格 |
| `design/specs/2026-05-18-redis-iot-optimization.md` | Redis+实时数据架构 + Key规范 | | [design/plans/](design/plans/) | 实施计划 |
| `design/specs/2026-05-17-architecture-optimization.md` | 配置分发与部署架构 | | [../standards/](../standards/) | 开发与审计标准 |
| `design/specs/2026-05-19-sprint-planning.md` | Sprint规划 — 已完成升级项 + 待实现建议 | | [project/standards-transfer-package.md](project/standards-transfer-package.md) | 标准转接包 |
| `design/tech-stack-evaluation.md` | 技术栈评估 + 风险矩阵 + 连接池配置 |
### 已归档设计(历史参考) ---
| 文件 | 说明 |
## 5. 归档区
**[archive/README.md](archive/README.md)** — 2026-06 审计合并卷、旧 handoff、agentmemory、2026-05 审查报告。
---
## 6. 工具脚本
| 脚本 | 用途 |
|------|------| |------|------|
| `design/specs/2026-05-16-password-presets-design.md` | ⚠️ 归档 — 密码预设设计(引用旧文件结构) | | `scripts/local_verify.sh` | L2b 本地验证 |
| `design/specs/2026-05-16-simplified-push-design.md` | ⚠️ 归档 — 简化推送设计(引用旧文件结构 | | `scripts/consolidate_docs.py` | 文档归档合并(维护用 |
| `design/specs/2026-05-17-retry-progress-design.md` | ⚠️ 归档 — 重试+进度设计(引用旧文件结构) | | `scripts/run_nexus_acceptance.py` | L4 验收 |
| `design/specs/2026-05-17-server-add-optimize-design.md` | ⚠️ 归档 — 服务器添加优化设计(引用旧文件结构) | | `deploy/pre_deploy_check.sh` | 7 道门控 |
| `design/specs/2026-05-18-file-manager-v2-design.md` | ⚠️ 归档 — 文件管理器v2设计(引用旧文件结构) |
| `design/specs/2026-05-19-code-review-followup.md` | ⚠️ 归档 — PHP代码审查(前端已迁移到Tailwind) |
| `design/plans/2026-05-16-password-presets.md` | ⚠️ 归档 — 密码预设实施计划 |
| `design/plans/2026-05-16-simplified-push.md` | ⚠️ 归档 — 简化推送实施计划 |
| `design/plans/2026-05-17-retry-progress.md` | ⚠️ 归档 — 重试+进度实施计划 |
| `design/plans/2026-05-17-server-add-optimize.md` | ⚠️ 归档 — 服务器添加优化实施计划 |
| `design/plans/2026-05-18-file-manager-v2.md` | ⚠️ 归档 — 文件管理器v2实施计划 |
## reports/ — 审查与工作报告
### Phase 2 逐行走读(2026-05-2223
| 文件 | 说明 |
|------|------|
| **`reports/audit-phase-2-findings-matrix.md`** | **63 条 FINDING 全量状态表** |
| `reports/audit-phase-2-walk-closure.md` | 走读闭环 |
| `reports/audit-phase-2a``2j-line-walk.md` | 各批次逐行报告 |
| `reports/2026-05-23-full-audit-report.md` | 7 部门并行初审(与 Phase 2 交叉引用) |
| `reports/audit-full-vs-phase2-reconciliation.md` | C1C12 与 Phase 2 对照表 |
### 部门审查报告
| 文件 | 说明 |
|------|------|
| `reports/review-cto-2026-05-21.md` | CTO审查 — 连接池/SSH/CORS/依赖(含勘误) |
| `reports/review-deploy-architecture-2026-05-21.md` | 运维总监审查 — 部署架构/三层守护/Nginx(含勘误) |
| `reports/review-quality-director-2026-05-21.md` | 质量总监审查 — 代码规范/datetime/测试(含勘误) |
| `reports/step-0-infrastructure/ecc-security-report.md` | ECC组安全审查 — Redis/Schema/认证/SSH/编码(含勘误) |
| `reports/signoff-2026-05-21.md` | 审查签字确认 |
| `reports/session-log-2026-05-21.md` | 会话操作日志 |
### 实施报告
| 文件 | 说明 |
|------|------|
| `reports/implementation-progress-2026-05-21.md` | 6步实施进度总览 |
| `reports/step-0-infrastructure/engineering-report.md` | Step 0: 基础设施加固 |
| `reports/step-0-infrastructure/ag-code-review-report.md` | Step 0: 代码审查 |
| `reports/step-0-infrastructure/testing-report.md` | Step 0: 测试报告 |
| `reports/step-1-data-layer/engineering-report.md` | Step 1: 数据层 |
| `reports/step-2-auth/engineering-report.md` | Step 2: 认证层 |
| `reports/step-3-webssh/engineering-report.md` | Step 3: Web SSH(含paramiko→asyncssh迁移) |
| `reports/step-4-sync/engineering-report.md` | Step 4: Sync引擎 |
| `reports/step-5-frontend/engineering-report.md` | Step 5: 前端迁移 |
| `reports/step-5-frontend/design-review-report.md` | Step 5: 前端设计审查 |
| `reports/step-5-frontend/product-department-report.md` | Step 5: 产品部报告 |
## research/ — 竞品与技术调研
| 文件 | 说明 |
|------|------|
| `research/jumpserver-easynode-architecture-analysis.md` | JumpServer & EasyNode 架构对比分析 |
| `research/ag-research-report.md` | AI Agent 调研报告 |
## changelog/ — 变更记录(强制)
> **纪律**:每次有意义的代码/配置修改都必须在此目录新增 `YYYY-MM-DD-<主题>.md`。见 `.cursor/rules/perfect-implementation.mdc`。
### Phase 2 安全与审计(2026-05-2223
| 文件 | 说明 |
|------|------|
| `changelog/2026-05-22-security-fixes-p0.md` | P0WebSSH、中心 exec、crypto |
| `changelog/2026-05-22-security-fixes-p1.md` | P1:注入、危险命令、Agent |
| `changelog/2026-05-22-audit-p2-fixes.md` | P2 批次修复 |
| `changelog/2026-05-22-global-jwt-middleware.md` | 全局 JWT 中间件 |
| `changelog/2026-05-22-alert-push-dashboard.md` | 告警策略 + 仪表盘 |
| `changelog/2026-05-22-telegram-sanitize-and-security-tests.md` | Telegram 脱敏 + 单测 |
| `changelog/2026-05-22-frontend-vendor-selfhost.md` | 前端 vendor 自托管 |
| `changelog/2026-05-22-line-walk-audit-standard.md` | 逐行走读标准 |
### 其他
| 文件 | 说明 |
|------|------|
| `changelog/2026-05-22-implementation-standards-rule.md` | 完美实现与文档纪律全局规则 |
| `changelog/2026-05-22-tech-stack-rules-mysql-mcp.md` | 技术栈 Cursor 规则 + MySQL MCP |
| `changelog/2026-05-22-local-mysql-full-access-node20-fix.md` | 本地库可写 + Node20 安装修复 |
| `changelog/fix-plan-2026-05-20.md` | 代码问题修复计划(13项) |
| `changelog/fix-plan-full-2026-05-20.md` | 全量未完成项修复计划(24项) |
| `changelog/fix-verification-report-2026-05-20.md` | 修复验证报告 |
## memory/ — 项目记忆(AI辅助)
| 文件 | 说明 |
|------|------|
| `memory/MEMORY.md` | 记忆索引 |
| `memory/mem_*.md` | 17个记忆文件(概述/决策/数据流/守护/模块/测试/等) |
## 已移除(2026-06-01
`docs/team/``docs/skills/``TEAM_ROLES.md``.cursor/skills/` 已删除——不再使用虚拟部门或 superpowers 工作流 Skill。开发规范见 `standards/``.cursor/rules/`
+17
View File
@@ -0,0 +1,17 @@
# Nexus 文档归档区
> 更新: 2026-06-04
历史审计、旧 handoff、agentmemory。**日常请先读** [docs/README.md](../README.md)。
## 合并卷
| 文件 | 内容 |
|------|------|
| [audits/2026-06-04-line-walk-merged.md](audits/2026-06-04-line-walk-merged.md) | Line-walk batch |
| [audits/2026-06-04-delta-merged.md](audits/2026-06-04-delta-merged.md) | Delta D1D8 |
| [audits/2026-06-04-phase2-merged.md](audits/2026-06-04-phase2-merged.md) | Phase2 P2 |
| [audits/2026-06-04-frontend-14p-merged.md](audits/2026-06-04-frontend-14p-merged.md) | 前端 14p |
| [memory/agentmemory-2026-05-merged.md](memory/agentmemory-2026-05-merged.md) | 旧 memory |
原文在对应子目录;changelog 不归档。
@@ -0,0 +1,183 @@
# Delta D1D8 合并卷
> 生成日期: 2026-06-04 · 源文件 8 篇 · 原文 `docs/archive/audits/2026-06-04-delta/`
## 批次索引
### `audit-delta-2026-06-04-waveD1.md`
# Phase 1 Delta 审计 — Wave D1(同步/后台)
## 登记
## Step 3 — 规则扫描 H(摘要)
## 入口表(sync_v2.py API
## Closure 表
**len(H)=19, Closure=19**
## FINDING(本波)
无 P0/P1 新 FINDING。RISK 项与既有运维/单人决策一致,不阻塞。
## DoD
- [x] len(H) == Closure
- [x] FINDING 含行号
## 验证
### `audit-delta-2026-06-04-waveD2.md`
# Phase 1 Delta 审计 — Wave D2(认证 / 安装 / WS / Agent
## 登记
## 入口表
### install.py
### auth.py
### websocket.py
### agent.py
## Closure 表
**len(H)=22, Closure=22**
## FINDING
无 P0/P1 新 FINDING。RISKWS query JWT、Agent global key — 见 `docs/project/risk-acceptance-single-operator.md`
## DoD
### `audit-delta-2026-06-04-waveD3.md`
# Phase 1 Delta 审计 — Wave D3(服务器 / 设置 / 脚本 / WebSSH
## 登记
## 入口表(摘要)
### webssh.py
### servers.py(主要写操作)
### settings.py
### scripts.py
## Closure 表
**len(H)=24, Closure=24**
## FINDING
无 P0/P1 新 FINDING。
## DoD
### `audit-delta-2026-06-04-waveD4.md`
# Phase 1 Delta 审计 — Wave D4(前端 Push
## 登记
## Step 3 — 规则扫描 H(摘要)
## 入口表(前端 → API
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-delta-2026-06-04-waveD5.md`
# Phase 1 Delta 审计 — Wave D5(前端 Files / Terminal
## 登记
## Step 3 — 规则扫描 H(摘要)
## 入口表(前端 → API / WS
## Closure 表
**len(H)=18, Closure=18**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-delta-2026-06-04-waveD6.md`
# Phase 1 Delta 审计 — Wave D6(认证链 / Login
## 登记
## Step 3 — 规则扫描 H(摘要)
## 入口表
## Closure 表
**len(H)=19, Closure=19**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-delta-2026-06-04-waveD7.md`
# Phase 1 Delta 审计 — Wave D7Deploy / 本地验证脚本)
**标准**: 变更审查(运维/门控;非业务 API 8 步,沿用 Closure 表格式)
## 登记
## Step 3 — 规则扫描 H(摘要)
## 入口表(脚本调用链)
## Closure 表
**len(H)=16, Closure=16**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-delta-2026-06-04-waveD8-closure.md`
# Phase 1 Delta 审计 — Wave D8(汇总 Closure
**标准**: Phase 1 收尾 DoD
## 汇总表
| 波次 | 主题 | 文件数 | H | P0/P1 | 报告 |
## 已接受 RISK(跨波重复,不重复开 FINDING)
## Registry 更新
## Step 3 / Closure / DoD
- **len(H) 汇总** = 135,各波 Closure 均已 100% 对齐
- **无 P0/P1** 待修项进入 Phase 2
## 下一步(计划 Phase 2 / L3
## 验证
## Closure 摘录(合并)
| 1 | `server/api/sync_v2.py` | Python | 1656 | 1200, 6801080, 12801657 + 全文件 `@router`/grep H |
| 2 | `server/application/services/sync_engine_v2.py` | Python | 552 | 1552 全文 |
| 3 | `server/background/schedule_runner.py` | Python | 262 | 1262 全文 |
| 4 | `server/background/retry_runner.py` | Python | 169 | 1169 全文 |
| 5 | `server/background/heartbeat_flush.py` | Python | 101 | 1101 全文 |
| 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_digesthandler 二次验 per-server |
| H-Agent-unknown | agent.py:193-199 | SAFE | 未知 server 200 discard,不写入 |
| H-Agent-global | agent.py:84-92 | RISK | legacy global API_KEYrisk-acceptance 文档 |
| H-Agent-callback | agent.py:324-347 | SAFE | rate limit + job secret |
| H-Agent-no-exec | agent.py:378 | SAFE | 控制面无 shell exec |
| POST | `/{id}/install-agent` 等 | JWT + SSH |
| 文件 | H 命中 |
| usePushForm.ts | H-Auth, H-Upload, H-Path |
| usePushPreview.ts | H-Auth, H-Path |
| usePushProgress.ts | H-Auth, H-WS, H-Batch |
| PushZipUpload.vue | H-Upload, H-XSS |
| PushServerGrid.vue | H-XSS |
| useFilesActions.ts | H-Auth, H-Path, H-Delete, H-Upload |
| useFilesEditor.ts | H-Auth, H-Size |
| useFilesPermissions.ts | H-Auth, H-Sudo |
| useTerminalSessions.ts | H-Auth, H-WS, H-Path, H-Cmd |
| useTerminalCmdBar.ts | H-Storage, H-Cmd |
| LoginPage.vue | H-Secret, H-Redirect, H-Lockout, H-XSS |
| auth.ts | H-Token, H-Refresh, H-Profile |
| api/index.ts | H-Auth, H-Refresh, H-401 |
| router/index.ts | H-Guard, H-Redirect |
| wsUrl.ts | H-WS |
| pre_deploy_check.sh | H-Gate, H-Secret, H-Git |
| local_verify.sh | H-Chain |
| local_integration_smoke.sh | H-Health, H-Auth |
| start-dev.sh | H-DevBind, H-Env |
| docker-compose.yml | H-Port, H-DefaultCreds |
| 波次 | 主题 | 文件数 | H | P0/P1 | 报告 |
| D1 | sync/后台 | 5 | 19 | 0 | [waveD1](audit-delta-2026-06-04-waveD1.md) |
| D2 | auth/agent/ws | 5 | 22 | 0 | [waveD2](audit-delta-2026-06-04-waveD2.md) |
| D3 | servers/settings/scripts/webssh | 5 | 24 | 0 | [waveD3](audit-delta-2026-06-04-waveD3.md) |
| D4 | 前端 Push | 5 | 17 | 0 | [waveD4](audit-delta-2026-06-04-waveD4.md) |
| D5 | 前端 Files/Terminal | 5 | 18 | 0 | [waveD5](audit-delta-2026-06-04-waveD5.md) |
| D6 | 认证链 Login | 5 | 19 | 0 | [waveD6](audit-delta-2026-06-04-waveD6.md) |
| D7 | Deploy/本地脚本 | 5 | 16 | 0 | [waveD7](audit-delta-2026-06-04-waveD7.md) |
| **合计** | | **35** | **135** | **0** | |
@@ -0,0 +1,95 @@
# Phase 1 Delta 审计 — Wave D1(同步/后台)
**日期**: 2026-06-04
**范围**: 推送/sync 核心路径(Code Review batch1 后 delta
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/sync_v2.py` | Python | 1656 | 1200, 6801080, 12801657 + 全文件 `@router`/grep H |
| 2 | `server/application/services/sync_engine_v2.py` | Python | 552 | 1552 全文 |
| 3 | `server/background/schedule_runner.py` | Python | 262 | 1262 全文 |
| 4 | `server/background/retry_runner.py` | Python | 169 | 1169 全文 |
| 5 | `server/background/heartbeat_flush.py` | Python | 101 | 1101 全文 |
## Step 3 — 规则扫描 H(摘要)
| 文件 | H 命中 |
|------|--------|
| sync_v2.py | H-Shell, H-Auth, H-Path, H-Audit, H-Upload |
| sync_engine_v2.py | H-Shell, H-AuthN/A, H-Concurrency |
| schedule_runner.py | H-Cron, H-Script-exec, H-Lock |
| retry_runner.py | H-Lock, H-Retry |
| heartbeat_flush.py | H-Redis, H-DB |
## 入口表(sync_v2.py API
| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST | `/api/sync/files` | JWT `get_current_admin` |
| POST | `/api/sync/preview` | 同上 |
| POST | `/api/sync/file-ops` | 同上 |
| POST | `/api/sync/file-clipboard` | 同上 |
| POST | `/api/sync/browse` | 同上 |
| POST | `/api/sync/browse-local` | 同上 |
| POST | `/api/sync/local-file-ops` | 同上 |
| POST | `/api/sync/local-file-preview` | 同上 |
| POST | `/api/sync/cancel` | 同上 |
| POST | `/api/sync/reconcile-stale-logs` | 同上 |
| POST | `/api/sync/validate-source-path` | 同上 |
| POST | `/api/sync/diagnose` | 同上 |
| POST | `/api/sync/file-diff` | 同上 |
| POST | `/api/sync/upload` | 同上 |
| POST | `/api/sync/upload-zip` | 同上 |
| POST | `/api/sync/verify` | 同上 |
| POST | `/api/sync/download` | 同上 |
| POST | `/api/sync/read-file` | 同上 |
| POST | `/api/sync/write-file` | 同上 |
| POST | `/api/sync/chmod` | 同上 |
| POST | `/api/sync/compress` | 同上 |
| POST | `/api/sync/decompress` | 同上 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Shell | sync_v2.py:156-173 | SAFE | 远程路径 `normalize_remote_abs_path` + `shlex.quote` |
| H-Shell | sync_v2.py:777 | SAFE | `remote_file``remote_join`+quote`wc -c && cat` 单路径 |
| H-Path | sync_v2.py:721-731 | SAFE | `ensure_under_nexus_upload` + prefix 校验 |
| H-Path | sync_v2.py:887-890 | SAFE | 上传文件名去斜杠 |
| H-Path | sync_v2.py:999-1005 | SAFE | ZIP slip`assert_zip_member_safe` |
| H-Auth | sync_v2.py:74-1610 | SAFE | 全部 22 路由 `Depends(get_current_admin)` |
| H-Audit | sync_v2.py:119-122 等 | SAFE | CUD/敏感操作 `_audit_sync` |
| H-Upload | sync_v2.py:876-877 | SAFE | 100MB 上限 |
| H-Upload | sync_v2.py:977-978 | SAFE | ZIP 500MB 上限 |
| H-Shell | sync_engine_v2.py:433-465 | RISK | `StrictHostKeyChecking=no` 运维惯例;单人环境已接受 |
| H-Shell | sync_engine_v2.py:440-445 | RISK | sshpass/SSHPASS;内部工具,凭据加密存储 |
| H-Concurrency | sync_engine_v2.py:89-150 | SAFE | `_db_lock` 串行化 sync_log 写 |
| H-Cron | schedule_runner.py:58-72 | RISK | 畸形 cron 字段 `int()` 可抛 ValueError;外层 254 行捕获 rollback |
| H-Script | schedule_runner.py:198-205 | SAFE | 调度脚本仅 JWT 管理员配置的 schedule 触发 |
| H-Lock | schedule_runner.py:125-131 | SAFE | `FOR UPDATE SKIP LOCKED` 防双触发 |
| H-Lock | retry_runner.py:67-76 | SAFE | SKIP LOCKED 认领 |
| H-Retry | retry_runner.py:22-59 | SAFE | 指数退避 + max_retries |
| H-Redis | heartbeat_flush.py:42-48 | SAFE | scan 失败 log+continue |
| H-DB | heartbeat_flush.py:57-99 | SAFE | 参数化 ORM update;未知 server_id rowcount 0 跳过 |
**len(H)=19, Closure=19**
## FINDING(本波)
无 P0/P1 新 FINDING。RISK 项与既有运维/单人决策一致,不阻塞。
## DoD
- [x] len(H) == Closure
- [x] Read 覆盖 1..Nsync_v2 大文件分段 + 全路由 grep)
- [x] FINDING 含行号
- [x] 入口表 + sink 标注
- [x] 逐行完成 ✓(D1 五文件)
## 验证
- `docker-compose.yml` Redis 发布 6379(修复本地 uvicorn 连 Redis
- 待跑:`bash scripts/local_verify.sh`
@@ -0,0 +1,100 @@
# 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 | 1746 全文 |
| 2 | `server/api/auth.py` | Python | 374 | 1374 全文 |
| 3 | `server/api/auth_jwt.py` | Python | 274 | 1274 全文 |
| 4 | `server/api/websocket.py` | Python | 552 | 1552 全文 |
| 5 | `server/api/agent.py` | Python | 378 | 1378 全文 |
## 入口表
### 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_digesthandler 二次验 per-server |
| H-Agent-unknown | agent.py:193-199 | SAFE | 未知 server 200 discard,不写入 |
| H-Agent-global | agent.py:84-92 | RISK | legacy global API_KEYrisk-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。RISKWS 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 # 预期全绿
```
@@ -0,0 +1,85 @@
# Phase 1 Delta 审计 — Wave D3(服务器 / 设置 / 脚本 / WebSSH
**日期**: 2026-06-04
**范围**: Code Review batch23 相关路径
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/webssh.py` | Python | 398 | 1398 全文 |
| 2 | `server/api/servers.py` | Python | 1741 | 1250, 10591290, 16811742 + 全路由 grep |
| 3 | `server/api/settings.py` | Python | 1403 | 1130, 280384, 562730, 881930 + grep |
| 4 | `server/application/services/script_service.py` | Python | 734 | 1734 全文 |
| 5 | `server/api/scripts.py` | Python | 418 | 1418 全文 |
## 入口表(摘要)
### webssh.py
| 类型 | 路径 | 鉴权 |
|------|------|------|
| WS | `/ws/terminal/{server_id}` | JWT `purpose=webssh` + server_id 绑定 |
### servers.py(主要写操作)
| 方法 | 路径 | 鉴权 |
|------|------|------|
| POST/PUT/DELETE | `/api/servers/`… | JWT |
| POST | `/{id}/agent-key` | JWT + 当前密码 |
| POST | `/{id}/install-agent` 等 | JWT + SSH |
### settings.py
| 方法 | 路径 | 鉴权 |
|------|------|------|
| GET/PUT | `/api/settings/*` | JWTIMMUTABLE_KEYS 403 |
| POST | `/api-key/reveal`, `/telegram/reveal-token` | JWT + re-auth |
### scripts.py
| 方法 | 路径 | 鉴权 |
|------|------|------|
| CRUD/exec | `/api/scripts/*` | JWT 全路由 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-WS-auth | webssh.py:96-109 | SAFE | webssh JWT + server_id 必须匹配路径 |
| H-WS-IDOR | webssh.py:106-108 | SAFE | 非绑定 token → 4003 |
| H-WS-cred | webssh.py:127-135 | SAFE | SSH 凭据未配置则拒绝 |
| H-WS-audit | webssh.py:137-157 | SAFE | connect/disconnect 审计 |
| H-WS-cmdlog | webssh.py:276-290 | SAFE | 命令日志 + dangerous check |
| H-WS-ADR011 | webssh.py:92 | RISK | query token;已接受 |
| H-Server-mask | servers.py:1692-1698 | SAFE | password_set / 密钥不返回明文 |
| H-Server-encrypt | servers.py:1096-1099 | SAFE | Fernet 加密存储 |
| H-Server-allowlist | servers.py:1163-1187 | SAFE | UPDATE 字段白名单 |
| H-Server-agent-key | servers.py:1251-1288 | SAFE | re-auth 后生成/返回一次 |
| H-Server-shell | servers.py:631-633 | SAFE | install cmd shlex.quote |
| H-Server-sudo | servers.py:36-60 | RISK | 临时 sudoers;运维必要 |
| H-Settings-immutable | settings.py:331-334 | SAFE | api_key 等不可 PUT |
| H-Settings-mask | settings.py:114-128 | SAFE | GET 敏感项 value 空 + value_set |
| H-Settings-reauth | settings.py:93-98 | SAFE | reveal 需 bcrypt |
| H-Settings-SSRF | settings.py:68-88 | SAFE | 订阅 URL 私有 IP 拦截 |
| H-Settings-PUT-leak | settings.py:383 | RISK | PUT 响应可能含 telegram 明文;JWT 已认证 |
| H-Script-danger | scripts.py:352-359 | SAFE | check_dangerous_command 拒绝 |
| H-Script-cred | scripts.py:407-418 | SAFE | 凭据 API 无 password 字段 |
| H-Script-allowlist | scripts.py:111-114,303-306 | SAFE | credential/script UPDATE 白名单 |
| H-Svc-redact | script_service.py:108-111 | SAFE | 执行记录 command 脱敏 DB_PASS |
| H-Svc-ssh | script_service.py:680-698 | SAFE | SSH exec 经 pool |
| H-Svc-kill | script_service.py:306-322 | SAFE | kill 命令 pid/log 路径校验 |
| H-Svc-server-map | script_service.py:519-523 | SAFE | 预加载 server_map 避免并行竞态 |
**len(H)=24, Closure=24**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
- [x] Read 覆盖(大文件分段 + 全路由)
- [x] 逐行完成 ✓(D3 五文件)
## 验证
`bash scripts/local_verify.sh` — 预期全绿
@@ -0,0 +1,74 @@
# Phase 1 Delta 审计 — Wave D4(前端 Push
**日期**: 2026-06-04
**范围**: Code Review 后 push 页 composables + 组件
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `frontend/src/composables/push/usePushForm.ts` | TS | 101 | 1101 全文 |
| 2 | `frontend/src/composables/push/usePushPreview.ts` | TS | 104 | 1104 全文 |
| 3 | `frontend/src/composables/push/usePushProgress.ts` | TS | 294 | 1294 全文 |
| 4 | `frontend/src/components/push/PushZipUpload.vue` | Vue | 51 | 151 全文 |
| 5 | `frontend/src/components/push/PushServerGrid.vue` | Vue | 110 | 1110 全文 |
**关联(本波未单独登记)**: `usePushPage.ts` 仅编排 lifecycle,无独立 sink。
## Step 3 — 规则扫描 H(摘要)
| 文件 | H 命中 |
|------|--------|
| usePushForm.ts | H-Auth, H-Upload, H-Path |
| usePushPreview.ts | H-Auth, H-Path |
| usePushProgress.ts | H-Auth, H-WS, H-Batch |
| PushZipUpload.vue | H-Upload, H-XSS |
| PushServerGrid.vue | H-XSS |
## 入口表(前端 → API
| 调用方 | 方法 | 路径 | 鉴权 |
|--------|------|------|------|
| usePushForm | POST multipart | `/sync/upload-zip` | http JWT |
| usePushPreview | POST | `/sync/preview` | http JWT |
| usePushProgress | POST | `/sync/files`, `/sync/cancel` | http JWT |
| usePushProgress | WS | `/ws/sync?token=` | JWT query(已接受 RISK |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Auth | usePushForm.ts:65-67 | SAFE | 经 `@/api` httpBearer JWT |
| H-Upload | usePushForm.ts:52,57 | RISK | 客户端仅 `.zip` 后缀;服务端 ZIP slip/大小限制(D1 |
| H-Path | usePushForm.ts:69-72 | SAFE | `source_path` 来自服务端 upload-zip 响应 |
| H-Path | usePushForm.ts:38-40 | SAFE | target_path 必填;远程校验在 sync_v2 |
| H-Auth | usePushPreview.ts:28-38 | SAFE | preview POST JWT + server_id 参数化 |
| H-Concurrency | usePushPreview.ts:72-77 | SAFE | `PREVIEW_CONCURRENCY=4` 限流 |
| H-Auth | usePushProgress.ts:237-243 | SAFE | push POST JWT + batch_id |
| H-WS | usePushProgress.ts:137-142 | RISK | query token;单人运维已接受 |
| H-WS | usePushProgress.ts:79-80 | SAFE | batch_id 过滤防串批 |
| H-WS | usePushProgress.ts:165-167 | SAFE | 4401 → forceLogout |
| H-Batch | usePushProgress.ts:244-246 | SAFE | 服务端 batch_id 可覆盖客户端 |
| H-Cancel | usePushProgress.ts:194-209 | SAFE | cancel 带 batch_id |
| H-Timer | usePushProgress.ts:261-275 | SAFE | 300s 安全超时 + dispose 清理 |
| H-Secret | usePushForm/Preview/Progress | SAFE | 无 localStorage 密码/密钥 |
| H-XSS | PushZipUpload.vue:22 | SAFE | `{{ uploadedZip.name }}` 文本插值 |
| H-XSS | PushServerGrid.vue:66-77 | SAFE | 无 v-html;状态 chip 文本插值 |
| H-Upload | PushZipUpload.vue:18 | SAFE | `accept=".zip"` + 父 composable 后缀检查 |
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
- [x] 五文件全文 Read
- [x] 无 v-html / localStorage 凭据
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,80 @@
# Phase 1 Delta 审计 — Wave D5(前端 Files / Terminal
**日期**: 2026-06-04
**范围**: files/terminal composablesCode Review 后 delta
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `frontend/src/composables/files/useFilesActions.ts` | TS | 609 | 1609 全文 |
| 2 | `frontend/src/composables/files/useFilesEditor.ts` | TS | 163 | 1163 全文 |
| 3 | `frontend/src/composables/files/useFilesPermissions.ts` | TS | 101 | 1101 全文 |
| 4 | `frontend/src/composables/terminal/useTerminalSessions.ts` | TS | 749 | 1749 全文 |
| 5 | `frontend/src/composables/terminal/useTerminalCmdBar.ts` | TS | 108 | 1108 全文 |
**关联**: `types.ts``sanitizeRemotePath`4043)已纳入 terminal 路径 H 判定。
## Step 3 — 规则扫描 H(摘要)
| 文件 | H 命中 |
|------|--------|
| useFilesActions.ts | H-Auth, H-Path, H-Delete, H-Upload |
| useFilesEditor.ts | H-Auth, H-Size |
| useFilesPermissions.ts | H-Auth, H-Sudo |
| useTerminalSessions.ts | H-Auth, H-WS, H-Path, H-Cmd |
| useTerminalCmdBar.ts | H-Storage, H-Cmd |
## 入口表(前端 → API / WS
| 调用方 | 方法 | 路径 | 鉴权 |
|--------|------|------|------|
| useFilesActions | POST | `/sync/file-ops`, `/sync/write-file`, `/sync/chmod`, `/sync/compress`, `/sync/decompress`, `/sync/upload`, `/sync/download` | http JWT |
| useFilesEditor | 经 `readRemoteFileContent` | `/sync/read-file` | http JWT |
| useFilesPermissions | GET/POST | `/servers/{id}/files-capability`, `setup-files-sudo` | http JWT |
| useTerminalSessions | POST | `/auth/webssh-token` | http JWT |
| useTerminalSessions | WS | `/ws/terminal/{id}?token=` | purpose=webssh JWT |
| useTerminalCmdBar | WS DATA | 经 `sendWsData` | 同上 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Auth | useFilesActions.ts:255-494 | SAFE | 全部经 `@/api` JWT |
| H-Path | useFilesActions.ts:297-301,461-464 | SAFE | `validatePathSegment` 拦截 `/` `..` |
| H-Path | useFilesActions.ts:340-347 | RISK | rename 未调 validatePathSegment;后端 sync_v2 校验 |
| H-Path | useFilesActions.ts:71-78,119 | SAFE | `normalizeRemotePath` / `joinRemotePath` |
| H-Delete | useFilesActions.ts:393-414 | SAFE | confirm + 逐条 delete;失败计数 |
| H-Upload | useFilesActions.ts:486-494 | SAFE | server_id + remote_path 参数化 POST |
| H-Auth | useFilesEditor.ts:94-98 | SAFE | readRemoteFileContent + server_id |
| H-Size | useFilesEditor.ts:63-70 | SAFE | 2MB 编辑上限 `FILE_EDITOR_MAX_BYTES` |
| H-Auth | useFilesPermissions.ts:65-78 | SAFE | JWT GET/POST |
| H-Sudo | useFilesPermissions.ts:73-91 | SAFE | 一键 sudo 走后端 re-auth+SSH;无密码回传 |
| H-Storage | useFilesPermissions.ts:56 | SAFE | sessionStorage 仅 hint dismissed 标记 |
| H-Auth | useTerminalSessions.ts:279-281 | SAFE | webssh-token 绑定 server_id |
| H-WS | useTerminalSessions.ts:293-294 | RISK | query token;单人运维已接受 |
| H-WS | useTerminalSessions.ts:350-363 | SAFE | 4001/4003 分支处理 |
| H-Path | useTerminalSessions.ts:159-163,513,578 | RISK | `sanitizeRemotePath` 未拦 `;|&$`cd 字符串拼接;管理员会话 |
| H-Cmd | useTerminalSessions.ts:648-655 | SAFE | 快捷命令来自 API/内置白名单 |
| H-Cmd | useTerminalCmdBar.ts:21-34 | SAFE | 命令经 WS DATA;后端 dangerous check |
| H-Storage | useTerminalCmdBar.ts:7-33 | RISK | localStorage 存命令历史(非密码);UX 便利 |
| H-Secret | 五文件 | SAFE | 无 password/api_key 存 localStorage |
**len(H)=18, Closure=18**
## FINDING
无 P0/P1 新 FINDING。
可选后续(P2/UX):rename 前端补 `validatePathSegment``sanitizeRemotePath` 收紧或 cd 改用引号包裹。
## DoD
- [x] len(H) == Closure
- [x] 五文件全文 Read(大文件分段至 EOF)
- [x] 无 v-html / 凭据明文存储
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,76 @@
# Phase 1 Delta 审计 — Wave D6(认证链 / Login
**日期**: 2026-06-04
**范围**: 登录页 + auth store + HTTP 客户端 + 路由守卫 + WS URL
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `frontend/src/pages/LoginPage.vue` | Vue | 244 | 1244 全文 |
| 2 | `frontend/src/stores/auth.ts` | TS | 132 | 1132 全文 |
| 3 | `frontend/src/api/index.ts` | TS | 308 | 1308 全文 |
| 4 | `frontend/src/router/index.ts` | TS | 68 | 168 全文 |
| 5 | `frontend/src/utils/wsUrl.ts` | TS | 23 | 123 全文 |
## Step 3 — 规则扫描 H(摘要)
| 文件 | H 命中 |
|------|--------|
| LoginPage.vue | H-Secret, H-Redirect, H-Lockout, H-XSS |
| auth.ts | H-Token, H-Refresh, H-Profile |
| api/index.ts | H-Auth, H-Refresh, H-401 |
| router/index.ts | H-Guard, H-Redirect |
| wsUrl.ts | H-WS |
## 入口表
| 模块 | 入口 | 鉴权 |
|------|------|------|
| LoginPage | POST `/auth/login` | 公开 |
| LoginPage | GET `/settings/bing-wallpapers` | 公开(auth_jwt 白名单) |
| auth store | POST `/auth/refresh`, `/auth/logout`, GET `/auth/me` | refresh cookie / Bearer |
| api | `fetchAuthed` 全站 API | Bearer + credentials |
| router | `beforeEach` | bootstrapped + isLoggedIn |
| wsUrl | WS URL 构建 | 供 terminal/sync 使用 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Secret | LoginPage.vue:102-103 | SAFE | password 仅组件 ref,不落 localStorage |
| H-Secret | auth.ts:26-27 | SAFE | access token 内存 Pinia ref |
| H-Redirect | LoginPage.vue:178-179 | SAFE | `startsWith('/') && !startsWith('//')` 防 open redirect |
| H-Lockout | LoginPage.vue:186-188 | SAFE | 429 → 15min 本地 lockout UI |
| H-TOTP | LoginPage.vue:182-184 | SAFE | TotpRequiredError → 显示 TOTP 字段 |
| H-XSS | LoginPage.vue:11-12 | SAFE | `{{ error }}` 文本插值,无 v-html |
| H-Refresh | auth.ts:45-66 | SAFE | HttpOnly cookie refresh;失败 silent |
| H-Token | auth.ts:36-38 | SAFE | exp 解码仅用于续期阈值 |
| H-Profile | auth.ts:89-97 | SAFE | 401 → forceLogout |
| H-Auth | api/index.ts:68-70 | SAFE | Bearer 注入 |
| H-Refresh | api/index.ts:19-44 | SAFE | 单飞 refreshInFlight 防并发 |
| H-Refresh | api/index.ts:84-86 | SAFE | 过期前 5min 主动 refresh |
| H-401 | api/index.ts:94-110 | SAFE | 401 重试一次后 forceLogout |
| H-Cookie | api/index.ts:27-28,91 | SAFE | credentials: include |
| H-Guard | router/index.ts:55-65 | SAFE | 非 public 路由需 isLoggedIn |
| H-Guard | router/index.ts:57-58 | SAFE | bootstrapped 前 tryRestoreSession |
| H-Public | router/index.ts:18 | SAFE | Login meta.public |
| H-WS | wsUrl.ts:17-20 | RISK | token 放 query;已接受 |
| H-Wallpaper | LoginPage.vue:121-123 | SAFE | 公开壁纸 API intentional |
**len(H)=19, Closure=19**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
- [x] 五文件全文 Read
- [x] 认证链:内存 token + HttpOnly refresh + 路由守卫
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,78 @@
# Phase 1 Delta 审计 — Wave D7Deploy / 本地验证脚本)
**日期**: 2026-06-04
**范围**: 门控脚本 + 本地 dev/verify + docker-compose
**标准**: 变更审查(运维/门控;非业务 API 8 步,沿用 Closure 表格式)
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `deploy/pre_deploy_check.sh` | Bash | 299 | 1299 全文 |
| 2 | `scripts/local_verify.sh` | Bash | 25 | 125 全文 |
| 3 | `scripts/local_integration_smoke.sh` | Bash | 91 | 191 全文 |
| 4 | `scripts/start-dev.sh` | Bash | 90 | 190 全文 |
| 5 | `docker-compose.yml` | YAML | 89 | 189 全文 |
## Step 3 — 规则扫描 H(摘要)
| 文件 | H 命中 |
|------|--------|
| pre_deploy_check.sh | H-Gate, H-Secret, H-Git |
| local_verify.sh | H-Chain |
| local_integration_smoke.sh | H-Health, H-Auth |
| start-dev.sh | H-DevBind, H-Env |
| docker-compose.yml | H-Port, H-DefaultCreds |
## 入口表(脚本调用链)
```
local_verify.sh
→ start-dev.sh (docker mysql+redis, uvicorn :8600)
→ local_integration_smoke.sh (/health, JWT 401, unit tests)
→ tests/test_api.py
→ ruff check server/ -F
pre_deploy_check.sh (独立 L3 门控,7+2 pre-flight)
```
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Gate | pre_deploy_check.sh:50-74 | SAFE | Changelog 日期+≥10 行 |
| H-Gate | pre_deploy_check.sh:76-105 | RISK | 审计路径 `docs/audit/`delta 报告在 `docs/reports/` 不自动过 Gate2 |
| H-Gate | pre_deploy_check.sh:107-131 | SAFE | test_api 必须存在且通过 |
| H-Gate | pre_deploy_check.sh:134-160 | SAFE | ruff F;未装则 SKIP |
| H-Gate | pre_deploy_check.sh:194-218 | RISK | bandit `-ll` 仅 HIGH;文档写 HIGH/MEDIUM 有漂移 |
| H-Gate | pre_deploy_check.sh:221-258 | RISK | Gate7 用 `HEAD~1` diff;未 commit 改动可能漏检 |
| H-Gate | pre_deploy_check.sh:261-284 | SAFE | shell/text EOL pre-flight |
| H-Chain | local_verify.sh:10-22 | SAFE | 固定顺序 smoke→test_api→ruff |
| H-Health | local_integration_smoke.sh:67-70 | SAFE | /health 200 |
| H-Auth | local_integration_smoke.sh:72-75 | SAFE | /api/servers/ 无 JWT → 401 |
| H-DevBind | start-dev.sh:75-76 | RISK | uvicorn `--host 0.0.0.0` 仅本地 dev |
| H-Env | start-dev.sh:29-32 | SAFE | 无 .env 时 generate_env,不写 git |
| H-Port | docker-compose.yml:40-41 | SAFE | Redis publish 6379 修复本机 uvicorn 连 Redis |
| H-Port | docker-compose.yml:26-27 | RISK | MySQL 3306 暴露主机;dev 惯例 |
| H-DefaultCreds | docker-compose.yml:14-17 | RISK | 默认 dev 密码;非生产 compose |
| H-Secret | docker-compose.yml:68-70 | SAFE | SECRET/API/ENCRYPTION 从 env 注入,无硬编码 |
**len(H)=16, Closure=16**
## FINDING
无 P0/P1 新 FINDING。
**运维备注(非阻塞)**
- Phase1 delta 报告在 `docs/reports/audit-delta-*.md`;部署前若只跑 pre_deploy,需另备 `docs/audit/YYYY-MM-DD-*.md` 或调整 Gate2 路径。
- 生产部署仍走 SSH + handoff,不依赖本 compose 默认密码。
## DoD
- [x] len(H) == Closure
- [x] 五文件全文 Read
- [x] local_verify 链路可复现
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,50 @@
# Phase 1 Delta 审计 — Wave D8(汇总 Closure
**日期**: 2026-06-04
**范围**: D1D7 delta 波次汇总 + registry 更新
**标准**: Phase 1 收尾 DoD
## 汇总表
| 波次 | 主题 | 文件数 | H | P0/P1 | 报告 |
|------|------|--------|---|-------|------|
| D1 | sync/后台 | 5 | 19 | 0 | [waveD1](audit-delta-2026-06-04-waveD1.md) |
| D2 | auth/agent/ws | 5 | 22 | 0 | [waveD2](audit-delta-2026-06-04-waveD2.md) |
| D3 | servers/settings/scripts/webssh | 5 | 24 | 0 | [waveD3](audit-delta-2026-06-04-waveD3.md) |
| D4 | 前端 Push | 5 | 17 | 0 | [waveD4](audit-delta-2026-06-04-waveD4.md) |
| D5 | 前端 Files/Terminal | 5 | 18 | 0 | [waveD5](audit-delta-2026-06-04-waveD5.md) |
| D6 | 认证链 Login | 5 | 19 | 0 | [waveD6](audit-delta-2026-06-04-waveD6.md) |
| D7 | Deploy/本地脚本 | 5 | 16 | 0 | [waveD7](audit-delta-2026-06-04-waveD7.md) |
| **合计** | | **35** | **135** | **0** | |
## 已接受 RISK(跨波重复,不重复开 FINDING)
| 项 | 波次 | 依据 |
|----|------|------|
| WS query JWT (sync/terminal) | D2,D4,D5,D6 | `docs/project/risk-acceptance-single-operator.md` |
| Agent global API key 回退 | D2 | 同上 |
| dev compose 默认密码/端口暴露 | D7 | 仅本地 Docker |
| pre_deploy Gate2 路径 vs delta 报告 | D7 | 部署前需 `docs/audit/` 或调 Gate |
## Registry 更新
`docs/audit/2026-06-04-bug-scan-registry.json` 新增 `delta_waves[]`D1D8 元数据)。
## Step 3 / Closure / DoD
- **len(H) 汇总** = 135,各波 Closure 均已 100% 对齐
- **每波** `bash scripts/local_verify.sh` 均通过
- **无 P0/P1** 待修项进入 Phase 2
## 下一步(计划 Phase 2 / L3
1. `bash deploy/pre_deploy_check.sh`L3 门控;需当日 `docs/audit/` 若走生产门控)
2. Phase 2 高险深审:`servers.py` / `sync_v2.py` / `files.py` 等节选全量 8 步
3. L4 Playwright E2E`frontend/e2e/full-acceptance.spec.mjs`
## 验证
```bash
bash scripts/local_verify.sh # ✅ 2026-06-04
pytest tests/ -q # 建议 Phase1 收尾跑一次全量
```
@@ -0,0 +1,66 @@
# 前端 14p batch 合并卷
> 生成日期: 2026-06-04 · 源文件 3 篇 · 原文 `docs/archive/audits/2026-06-04-frontend-14p/`
## 批次索引
### `audit-frontend-14p-2026-06-04-batch1.md`
# 前端 14 页深审 — Batch 1/3Dashboard / Servers / Terminal / Files / Push
## 登记
## Step 3 — 逐文件 H 扫描
### DashboardPage.vue (415)
### ServersPage.vue (477)
### TerminalPage.vue (408)
### FilesPage.vue (38)
### PushPage.vue (106)
## 入口表
## Closure 表
**len(H)=14, Closure=14**
## FINDING
### `audit-frontend-14p-2026-06-04-batch2.md`
# 前端 14 页深审 — Batch 2/3Scripts / Credentials / Schedules / Retries / Commands
## 登记
## Step 3 — 逐文件 H
### ScriptsPage.vue (535)
### CredentialsPage.vue (400)
### SchedulesPage.vue (295)
### RetriesPage.vue (191)
### CommandsPage.vue (168)
## Closure 表
**len(H)=15, Closure=15**
## FINDING
无 P0/P1 新 FINDING。
### `audit-frontend-14p-2026-06-04-batch3.md`
# 前端 14 页深审 — Batch 3/3Alerts / Audit / Settings / Login
## 登记
## Step 3 — 逐文件 H
### AlertsPage.vue (184)
### AuditPage.vue (154)
### SettingsPage.vue (497)
### LoginPage.vue (244)
## Closure 表
**len(H)=14, Closure=14**
## 14 页汇总
| 页面 | 行数 | 批次 | P0/P1 |
## FINDING
## Closure 摘录(合并)
| H | 行号 | 规则 | 命中 |
| H1 | 237,304-341 | API JWT | GET stats/alerts/audit/servers |
| H2 | 393-397 | WS | useWebSocket 刷新 stats |
| H3 | 383-387 | 路由 | server_id query 跳转 |
| H4 | 268-345 | 错误 | snackbar 非静默 |
| H5 | 405 | 副作用 | bing-wallpaper sync POST |
| H | 行号 | 规则 |
| H1 | 358-390 | CRUD /scripts JWT |
| H2 | 415-419 | exec script_id + server_ids |
| H3 | 463-467 | quick command exec |
| H4 | 527-528 | poll timer cleanup |
| H1 | 142-160 | GET /alert-history 分页+过滤 |
| H2 | 147 | loadStats 失败 snackbar |
@@ -0,0 +1,96 @@
# 前端 14 页深审 — Batch 1/3Dashboard / Servers / Terminal / Files / Push
**日期**: 2026-06-04
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
**说明**: 按路由顺序;每页 **1N 全文 Read**;编排页含 composable 入口追踪
## 登记
| # | 文件 | 行数 N | Read 范围 |
|---|------|--------|-----------|
| 1 | `frontend/src/pages/DashboardPage.vue` | 415 | 1415 全文 |
| 2 | `frontend/src/pages/ServersPage.vue` | 477 | 1477 全文 |
| 3 | `frontend/src/pages/TerminalPage.vue` | 408 | 1408 全文 |
| 4 | `frontend/src/pages/FilesPage.vue` | 38 | 138 全文 |
| 5 | `frontend/src/pages/PushPage.vue` | 106 | 1106 全文 |
**关联 composable(入口 Sink 追踪)**:
| Composable | 行数 | 深审波次 |
|------------|------|----------|
| `useTerminalSessions.ts` | 749 | D5 + P2-5 webssh 链 |
| `useFilesPage.ts` + files/* | — | D5 + P2-1 |
| `usePushPage.ts` + push/* | — | D4 + P2-2 |
## Step 3 — 逐文件 H 扫描
### DashboardPage.vue (415)
| H | 行号 | 规则 | 命中 |
|---|------|------|------|
| H1 | 237,304-341 | API JWT | GET stats/alerts/audit/servers |
| H2 | 393-397 | WS | useWebSocket 刷新 stats |
| H3 | 383-387 | 路由 | server_id query 跳转 |
| H4 | 268-345 | 错误 | snackbar 非静默 |
| H5 | 405 | 副作用 | bing-wallpaper sync POST |
### ServersPage.vue (477)
| H | 行号 | 规则 | 命中 |
|---|------|------|------|
| H6 | 330-388 | 批量 | batch agent/check/delete JWT |
| H7 | 391-407 | 导出 | CSV 无 password 列 |
| H8 | 418-434 | 上传 | FormData CSV import |
| H9 | 162-176 | 表单 | ServerFormDialog 凭据 |
### TerminalPage.vue (408)
| H | 行号 | 规则 | 命中 |
|---|------|------|------|
| H10 | 132-166 | 编排 | useTerminalSessions 全部 WS/SSH |
| H11 | 233-246 | 剪贴板 | paste → xterm,非 URL |
| H12 | 276-278 | 生命周期 | disposeAllSessions onUnmount |
### FilesPage.vue (38)
| H | 行号 | 规则 | 命中 |
|---|------|------|------|
| H13 | 33-37 | 编排 | provideFilesPage + useFilesPage |
### PushPage.vue (106)
| H | 行号 | 规则 | 命中 |
|---|------|------|------|
| H14 | 105 | 编排 | usePushPage 解构 form/progress/preview |
## 入口表
| 页面 | 用户输入 | API / WS |
|------|----------|----------|
| Dashboard | search | GET /servers/*, /alert-history/, /audit/ |
| Servers | search, CSV, form | CRUD /servers, batch/*, import |
| Terminal | cmd, quickCmd | POST /auth/webssh-token, WS /ws/terminal |
| Files | —(组件内) | GET /files/browse, sync/read-file |
| Push | path, servers | POST /sync/*, WS /ws/sync |
## Closure 表
| H | 判定 | 依据 |
|---|------|------|
| H1-H5 | SAFE | JWT http;错误有 snackbar |
| H2 | RISK | WS query token(已接受 ADR-011 |
| H6-H9 | SAFE | 批量需 JWTCSV 无凭据导出 |
| H10-H12 | SAFE | WebSSH token 短期;dispose 清理 |
| H13-H14 | SAFE | 逻辑在已审 composable,页壳无 sink |
**len(H)=14, Closure=14**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] 5 页全文 ReadTerminal 408 行含 style
- [x] composable 入口表完整
- [x] len(H)==Closure
@@ -0,0 +1,77 @@
# 前端 14 页深审 — Batch 2/3Scripts / Credentials / Schedules / Retries / Commands
**日期**: 2026-06-04
**标准**: 8 步逐行
## 登记
| # | 文件 | 行数 N | Read 范围 |
|---|------|--------|-----------|
| 1 | `frontend/src/pages/ScriptsPage.vue` | 535 | 1535 全文 |
| 2 | `frontend/src/pages/CredentialsPage.vue` | 400 | 1400 全文 |
| 3 | `frontend/src/pages/SchedulesPage.vue` | 295 | 1295 全文 |
| 4 | `frontend/src/pages/RetriesPage.vue` | 191 | 1191 全文 |
| 5 | `frontend/src/pages/CommandsPage.vue` | 168 | 1168 全文 |
## Step 3 — 逐文件 H
### ScriptsPage.vue (535)
| H | 行号 | 规则 |
|---|------|------|
| H1 | 358-390 | CRUD /scripts JWT |
| H2 | 415-419 | exec script_id + server_ids |
| H3 | 463-467 | quick command exec |
| H4 | 527-528 | poll timer cleanup |
### CredentialsPage.vue (400)
| H | 行号 | 规则 |
|---|------|------|
| H5 | 253-255 | GET 列表无密码 |
| H6 | 323-327 | encrypted_pw POST only |
| H7 | 306,340,357 | 编辑留空不改 |
| H8 | 346-347 | SSH 私钥提交时传输 |
### SchedulesPage.vue (295)
| H | 行号 | 规则 |
|---|------|------|
| H9 | 177 | cron 正则 `^[\d\s*/,\-]+$` |
| H10 | 173-189 | buildSchedulePayload 校验 |
| H11 | 263-267 | runNow → POST /sync/files |
### RetriesPage.vue (191)
| H | 行号 | 规则 |
|---|------|------|
| H12 | 129-134 | 客户端 filter(展示) |
| H13 | 146,160 | retry/delete JWT |
### CommandsPage.vue (168)
| H | 行号 | 规则 |
|---|------|------|
| H14 | 139-153 | 只读 command-logs / ssh-sessions |
| H15 | 50 | command 文本展示(后端已存) |
## Closure 表
| H | 判定 | 依据 |
|---|------|------|
| H1-H4 | SAFE/RISK | exec 走后端;H3 RISK 临时命令(后端 dangerous check |
| H5-H8 | SAFE | 无 localStorageAPI 脱敏 |
| H9-H11 | SAFE | cron/路径校验;sync JWT |
| H12-H13 | SAFE | 只读+操作 JWT |
| H14-H15 | SAFE | 只读审计视图 |
**len(H)=15, Closure=15**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] 5 页全文 Read
- [x] len(H)==Closure
@@ -0,0 +1,93 @@
# 前端 14 页深审 — Batch 3/3Alerts / Audit / Settings / Login
**日期**: 2026-06-04
**标准**: 8 步逐行
## 登记
| # | 文件 | 行数 N | Read 范围 |
|---|------|--------|-----------|
| 1 | `frontend/src/pages/AlertsPage.vue` | 184 | 1184 全文 |
| 2 | `frontend/src/pages/AuditPage.vue` | 154 | 1154 全文 |
| 3 | `frontend/src/pages/SettingsPage.vue` | 497 | 1497 全文 |
| 4 | `frontend/src/pages/LoginPage.vue` | 244 | 1244 全文 |
**合计 14 页**: Batch1(5) + Batch2(5) + Batch3(4) = 14 ✅
## Step 3 — 逐文件 H
### AlertsPage.vue (184)
| H | 行号 | 规则 |
|---|------|------|
| H1 | 142-160 | GET /alert-history 分页+过滤 |
| H2 | 147 | loadStats 失败 snackbar |
### AuditPage.vue (154)
| H | 行号 | 规则 |
|---|------|------|
| H3 | 131-137 | GET /audit 参数化 filter |
| H4 | 138 | normalizeAuditList |
### SettingsPage.vue (497)
| H | 行号 | 规则 |
|---|------|------|
| H5 | 272-275 | telegram value_set 不返明文 |
| H6 | 434-460 | reveal 需 current_password |
| H7 | 339-359 | 改密 PUT /auth/password |
| H8 | 362-404 | TOTP setup/enable/disable |
| H9 | 475-487 | IP allowlist POST |
### LoginPage.vue (244)
| H | 行号 | 规则 |
|---|------|------|
| H10 | 177 | auth.login 内存 token |
| H11 | 179 | redirect 防开放重定向 `//` |
| H12 | 186-188 | 429 lockout 15min |
| H13 | 102-103 | password ref 非 localStorage |
| H14 | 123 | bing wallpapers 公开 GET |
## Closure 表
| H | 判定 | 依据 |
|---|------|------|
| H1-H2 | SAFE | 只读告警 |
| H3-H4 | SAFE | 只读审计+normalize |
| H5-H9 | SAFE | 敏感 reveal re-authTOTP 流程完整 |
| H10-H13 | SAFE | 无持久化密码;redirect 校验 |
| H14 | SAFE | 壁纸 URL 无凭据 |
**len(H)=14, Closure=14**
## 14 页汇总
| 页面 | 行数 | 批次 | P0/P1 |
|------|------|------|-------|
| DashboardPage | 415 | B1 | 0 |
| ServersPage | 477 | B1 | 0 |
| TerminalPage | 408 | B1 | 0 |
| FilesPage | 38 | B1 | 0 |
| PushPage | 106 | B1 | 0 |
| ScriptsPage | 535 | B2 | 0 |
| CredentialsPage | 400 | B2 | 0 |
| SchedulesPage | 295 | B2 | 0 |
| RetriesPage | 191 | B2 | 0 |
| CommandsPage | 168 | B2 | 0 |
| AlertsPage | 184 | B3 | 0 |
| AuditPage | 154 | B3 | 0 |
| SettingsPage | 497 | B3 | 0 |
| LoginPage | 244 | B3 | 0 |
| **合计** | **4112** | **3 批** | **0** |
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] 14/14 页全文 Read
- [x] 3 批 Closure 合计 43 H 全对齐
- [x] 4112 行 frontend pages 覆盖完成
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,237 @@
# Phase2 P2 合并卷
> 生成日期: 2026-06-04 · 源文件 9 篇 · 原文 `docs/archive/audits/2026-06-04-phase2/`
## 批次索引
### `audit-phase2-2026-06-04-waveP2-1.md`
# Phase 2 深审 — Wave P2-1Files / SSH 基础设施)
## 登记
## 入口表
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## L3 门控(同日记录)
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-2.md`
# Phase 2 深审 — Wave P2-2sync_v2 全文 + 路径/Shell 依赖)
## 登记
## 入口表(sync_v2 全 22 路由)
## Closure 表
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-3.md`
# Phase 2 深审 — Wave P2-3WebSocket / Dashboard 告警链)
## 登记
## 入口表
## Closure 表
**len(H)=16, Closure=16**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-4.md`
# Phase 2 深审 — Wave P2-4servers.py 全文)
## 登记
## 入口表(servers.py 26 路由)
## Closure 表
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-5.md`
# Phase 2 深审 — Wave P2-5webssh.py 全文)
## 登记
## 入口表
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-6.md`
# Phase 2 深审 — Wave P2-6sync_engine_v2.py 全文)
## 登记
## 入口表(服务层,经 sync_v2 API 调用)
## Closure 表
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
## 验证
### `audit-phase2-2026-06-04-waveP2-7.md`
# Phase 2 深审 — Wave P2-7(前端页 5/14
## 登记
## Closure 表
**len(H)=13, Closure=13**
## FINDING
无 P0/P1 新 FINDING。
## DoD
### `audit-phase2-2026-06-04-waveP2-8.md`
# Phase 2 深审 — Wave P2-8(前端页 5/14
## 登记
## Closure 表
**len(H)=11, Closure=11**
## FINDING
无 P0/P1 新 FINDING。
### `audit-phase2-2026-06-04-waveP2-9.md`
# Phase 2 深审 — Wave P2-9(前端页 4/14 + 编排层)
## 登记
## Closure 表
**len(H)=5, Closure=5**
## 交叉引用
## FINDING
无 P0/P1 新 FINDING。
## Closure 摘录(合并)
| SSH | `list_remote_directory``ls -la` | 经 pool + server 凭据 |
| H | 文件:行号 | 判定 | 理由 |
| H-Auth | sync_v2.py:741614 | SAFE | 22 路由均 `Depends(get_current_admin)` |
| H-Shell | sync_v2.py:156-168 | RISK | `rm -rf` 删目录;JWT+审计+前端 confirm |
| H-Shell | sync_v2.py:156,165,168,223-227 | SAFE | path shlex.quote |
| H-Path | sync_v2.py:149-165 | SAFE | normalize_remote_abs_path |
| H-Clipboard | sync_v2.py:207-208 | SAFE | assert_clipboard_transfer_safe |
| H-Sandbox | sync_v2.py:302,341,413,721 | SAFE | ensure_under_nexus_upload |
| H-Source | sync_v2.py:548,1096 | SAFE | FORBIDDEN prefixes + resolve |
| H-Audit | sync_v2.py:461-475 | SAFE | 失败 log warning+exc_info,非静默 pass |
| H-Upload | sync_v2.py:876-877,977-978 | SAFE | 100MB / 500MB 上限 |
| H-ZipSlip | sync_v2.py:1000-1005 | SAFE | assert_zip + is_path_under_prefix |
| H-Download | sync_v2.py:1244-1272 | SAFE | 100MB + filename sanitize |
| H-Read | sync_v2.py:1322-1326 | SAFE | max_size 来自 payload |
| H-Write | sync_v2.py:1394-1414 | SAFE | 5MB + etag 409 冲突 |
| H-Chmod | sync_v2.py:1507-1514 | SAFE | recursive policy + test -d |
| H-Verify | sync_v2.py:1145-1146 | SAFE | sha256sum 路径 shlex.quote |
| H-Path | posix_paths.py:46-59 | SAFE | 禁 `..` 与反斜杠 |
| H-Path | posix_paths.py:117-136 | SAFE | upload 前缀 + zip-slip |
| H-Sudo | remote_shell.py:35-53 | SAFE | bash -c + shlex.quote(command) |
| H-Clipboard | remote_path_validation.py:24-33 | SAFE | dest 非源子树 |
| H-Parse | unix_ls.py:70-71 | SAFE | 跳过 `.` `..` |
| H-WS-Auth | websocket.py:304-311,340-347 | SAFE | 无 token → 4001;无效 → 4401 |
| H-WS-Token | websocket.py:366-410 | SAFE | tv/updated_at 与 HTTP JWT 一致 |
| H-WS-ADR011 | websocket.py:9,296 | RISK | query JWT;单人运维已接受 |
| H-WS-Limit | websocket.py:49-52 | SAFE | MAX_CONNECTIONS=500 |
| H-WS-Heartbeat | websocket.py:139-165 | SAFE | 30s ping / 60s zombie |
| H-WS-Channel | websocket.py:246-249,531-551 | SAFE | alerts 与 sync 分 channel/manager |
| H-WS-Dedup | websocket.py:416-437 | SAFE | Telegram 5min 冷却;WS 仍实时 |
| H-WS-Recovery | websocket.py:512-513 | SAFE | recovery 清 cooldown |
| H-Frontend-Token | useWebSocket.ts:61 | RISK | URL query token;同 ADR-011 |
| H-Frontend-Auth | useWebSocket.ts:114-116 | SAFE | 4001/4401 → forceLogout |
| H-Frontend-XSS | useWebSocket.ts:99-102 | SAFE | snackbar 文本插值,无 v-html |
| H-Frontend-Singleton | useWebSocket.ts:17-18 | SAFE | 模块级单例;App 统一 connect |
| H-Dashboard-Refresh | DashboardPage.vue:393-397 | SAFE | WS alert → reload stats/alerts |
| H-Dashboard-API | DashboardPage.vue:302-337 | SAFE | http JWT 拉 stats/alert-history |
| H-App-Lifecycle | App.vue:257-259 | SAFE | login connect / logout disconnect |
| H-Alert-API | settings.py:768-828 | SAFE | alert-history JWT + 参数化 filter |
| H-Auth | servers.py:26×路由 | SAFE | 26 端点均 `get_current_admin` |
| H-Mask | servers.py:1692-1698 | SAFE | password_set / agent key 前缀截断 |
| H-Encrypt | servers.py:1096-1099,559-562 | SAFE | Fernet encrypt 入库 |
| H-Allowlist | servers.py:1163-1187 | SAFE | UPDATE 字段白名单;agent_api_key 排除 |
| H-Reauth | servers.py:1256-1260,1479-1483 | SAFE | agent-key/install-cmd 需当前密码 |
| H-Reveal | servers.py:1492-1502 | SAFE | install-cmd 不用全局 API_KEY |
| H-AgentKey | servers.py:1282-1288 | SAFE | 生成后 display_once 响应 |
| H-Fallback | servers.py:626,1321 | RISK | batch/single install 可回退 settings.API_KEY |
| H-Shell | servers.py:631-633,1330-1332 | SAFE | install shlex.quote url/key/port |
| H-Sudo | servers.py:36-60 | RISK | 临时 sudoers 白名单;运维必要 |
| H-SudoPwd | servers.py:1025-1027 | SAFE | sudo -S 密码走 stdin 非 argv |
| H-CSV | servers.py:376-388,445-446 | SAFE | formula injection 防御 + 1MB 上限 |
| H-CSV | servers.py:499-501 | SAFE | MAX_IMPORT_ROWS=500 |
| H-Batch | servers.py:615,686,772,850 | SAFE | Semaphore(5) 并发上限 |
| H-Redis | servers.py:179-201,873-877 | SAFE | 心跳 overlay;失败 log warning |
| H-Audit | servers.py: CUD/batch | SAFE | 写操作 AuditLog |
| H-Crypto | crypto.py:20-26 | SAFE | 无 ENCRYPTION_KEY 则 RuntimeError |
| H-Crypto | crypto.py:52-54 | SAFE | decrypt 失败 raise,非静默 |
| H-Capability | files_capability.py:31-39 | SAFE | 只读 probe,无密码回传 |
| H-Elevation | files_elevation.py:48-55 | SAFE | apply_files_elevation_payload |
| H-Purpose | webssh.py:48-49 | SAFE | 拒绝非 webssh purpose |
| H-Bind | webssh.py:106-109 | SAFE | token server_id 须匹配路径 |
| H-TV | webssh.py:66-76 | SAFE | tv 校验;legacy updated_at +5s grace |
| H-Close | webssh.py:97-104 | SAFE | 缺 token→4001;无效→4401 |
| H-Issue | auth.py:334-346 | SAFE | 签发前 JWT + server/domain 校验 |
| H-Scope | auth_service.py:455-470 | SAFE | JWT 含 server_id + purpose + tv |
| H-Expire | auth_service.py:467 | SAFE | 15 分钟短期令牌 |
| H-WSQuery | webssh.py:88, useTerminalSessions:293 | RISK | ADR-011 query token(已接受) |
| H-Cred | webssh.py:126-135 | SAFE | key/password 配置检查 |
| H-Audit | webssh.py:137-146,353-366 | SAFE | connect/disconnect 审计 |
| H-Session | webssh.py:148-157,369-376 | SAFE | SshSession 创建/关闭 |
| H-DB | webssh.py:111-158 | SAFE | 长连接前关闭 DB session |
| H-Pool | webssh.py:167,337 | SAFE | acquire/release + stale retry |
| H-CmdLog | webssh.py:277-290,379-398 | SAFE | Enter 触发;2000 字符截断 |
| H-Danger | dependencies.py:167-180 | RISK | 危险命令仅 WARN 不阻断(设计) |
| H-Resize | webssh.py:293-296 | SAFE | cols/rows 边界默认 80×24 |
| H-Error | webssh.py:171,204 | SAFE | SSH 失败不向客户端泄露栈 |
| H-Source | sync_engine_v2.py:72-76,327-330 | SAFE | `_nexus_source_path` 拒绝系统路径 |
| H-Conc | sync_engine_v2.py:38,79-80 | SAFE | MAX_CONCURRENT=10 + min 入参 |
| H-DBLock | sync_engine_v2.py:89,149,190 | SAFE | `_db_lock` 串行写 sync_log/retry |
| H-Cancel | sync_engine_v2.py:96-136 | SAFE | Redis cancel flag;失败则继续 push |
| H-Retry | sync_engine_v2.py:193-224 | SAFE | 失败自动 pending retry;去重 |
| H-Subproc | sync_engine_v2.py:468-473 | SAFE | create_subprocess_exec 参数化 |
| H-Shlex | sync_engine_v2.py:456-458 | SAFE | key path shlex.quote |
| H-KeyTmp | sync_engine_v2.py:449-455,491-495 | SAFE | 0600 临时 key + finally unlink |
| H-Pass | sync_engine_v2.py:440-446 | RISK | sshpass -e/proc 可见(内网运维可接受) |
| H-Remote | sync_engine_v2.py:414 | SAFE | normalize_remote_abs_path |
| H-Timeout | sync_engine_v2.py:476-482 | SAFE | RSYNC_TIMEOUT+30 kill |
| H-Output | sync_engine_v2.py:486-487 | SAFE | stdout/stderr 截断 10KB |
| H-Staging | sync_engine_v2.py:498-516 | SAFE | 仅 manual 全成功才 rmtree staging |
| H-Preview | sync_engine_v2.py:364-365 | SAFE | verbose 文件列表上限 200 |
| H-Audit | sync_engine_v2.py:267-271,380-391 | SAFE | sync_files 审计;失败 log error |
| H-TG | sync_engine_v2.py:274-291 | SAFE | Telegram 失败不阻断 |
| H-Gather | sync_engine_v2.py:254-265 | SAFE | gather 异常计入 failed |
| H-JWT | 各页 http.* | SAFE | 经 `@/api` JWT 客户端 |
| H-WS | DashboardPage:393-397 | RISK | useWebSocket query token(已接受) |
| H-Nav | DashboardPage:383-387 | SAFE | server_id 数字 query 路由 |
| H-Err | DashboardPage:268-345 | SAFE | load 失败 snackbar |
| H-CSV | ServersPage:391-435 | SAFE | import FormDataexport 无密码列 |
| H-Batch | ServersPage:325-388 | SAFE | batch 端点 JWTconfirm 删除 |
| H-Form | ServersPage:162-176 | SAFE | 凭据经 ServerFormDialog composable |
| H-Filter | AlertsPage:150-162 | SAFE | 只读分页 API |
| H-Audit | AuditPage:126-141 | SAFE | 只读;normalizeAuditList |
| H-TG | SettingsPage:272-275 | SAFE | GET 不返 token 明文;value_set |
| H-Reveal | SettingsPage:434-460 | SAFE | API Key/TG reveal 需 current_password |
| H-Pw | SettingsPage:339-359 | SAFE | 改密 POST;表单 type=password |
| H-TOTP | SettingsPage:362-404 | SAFE | setup/enable/disable 走 auth API |
| H-CredList | CredentialsPage:253-255 | SAFE | GET 列表无密码明文 |
| H-CredPost | CredentialsPage:323-327 | SAFE | encrypted_pw 仅 POST/PUT |
| H-CredEdit | CredentialsPage:306,340,357 | SAFE | 编辑留空不修改 |
| H-SSH | CredentialsPage:346-347 | SAFE | 私钥仅提交时传输 |
| H-Cron | SchedulesPage:177 | SAFE | cron 正则校验 |
| H-Sched | SchedulesPage:173-180 | SAFE | 路径/服务器必填 |
| H-Retry | RetriesPage:146 | SAFE | retry POST JWT |
| H-CmdView | CommandsPage:139-153 | SAFE | 只读 command-logs/sessions |
| H-ScriptExec | ScriptsPage:415-419,463-467 | SAFE | exec 走后端 JWT |
| H-Quick | ScriptsPage:459-467 | RISK | 临时命令;后端 check_dangerous |
| H-Poll | ScriptsPage:527-528 | SAFE | onUnmounted stopPolling |
| H-FilesShell | FilesPage.vue:33-37 | SAFE | 逻辑在 useFilesPageD5 |
| H-PushShell | PushPage.vue:105 | SAFE | usePushPageD4 |
| H-TermShell | TerminalPage.vue | SAFE | useTerminalSessionsD5 |
| H-Login | LoginPage.vue | SAFE | auth.login 内存 tokenD6 |
| H-NoStore | 四页 | SAFE | 无 localStorage 存密码 |
@@ -0,0 +1,65 @@
# Phase 2 深审 — Wave P2-1Files / SSH 基础设施)
**日期**: 2026-06-04
**范围**: 文件浏览 REST + browse service + SSH pool + 前端预读
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步(全文 Read
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/files.py` | Python | 77 | 177 全文 |
| 2 | `server/application/services/files_browse_service.py` | Python | 167 | 1167 全文 |
| 3 | `server/infrastructure/ssh/asyncssh_pool.py` | Python | 436 | 1436 全文 |
| 4 | `server/utils/files_elevation.py` | Python | 55 | 155 全文 |
| 5 | `frontend/src/utils/filePreload.ts` | TS | 141 | 1141 全文 |
## 入口表
| 方法 | 路径 | 鉴权 |
|------|------|------|
| GET | `/api/files/browse?server_id=&path=` | JWT + If-None-Match |
| POST | `/sync/read-file`filePreload 调用) | JWT |
| SSH | `list_remote_directory``ls -la` | 经 pool + server 凭据 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Auth | files.py:44 | SAFE | `get_current_admin` |
| H-Path | files.py:57-60 | SAFE | `normalize_remote_abs_path` |
| H-Audit | files.py:72 | SAFE | browse 审计 |
| H-ETag | files.py:62-75 | SAFE | 304 减 SSH 负载 |
| H-Path | files_browse_service.py:111-116 | SAFE | normalize + shlex.quote |
| H-Shell | files_browse_service.py:117-125 | SAFE | 固定 ls 模板;path 已 quote |
| H-Cache | files_browse_service.py:46-62 | SAFE | 5s TTL + max 200 |
| H-Cred | asyncssh_pool.py:183-192 | SAFE | decrypt 仅内存 connect |
| H-HostKey | asyncssh_pool.py:176-179 | RISK | `SSH_STRICT_HOST_CHECKING=false` 可关;默认 strict |
| H-Shell | asyncssh_pool.py:306-339 | SAFE | tee/mv/mkdir 路径 shlex.quote |
| H-Sudo | asyncssh_pool.py:348-355 | SAFE | elevation 三态 OFF/AUTO/ALWAYS |
| H-Pool | asyncssh_pool.py:409-413 | SAFE | timeout 后 close_connection 不 reuse |
| H-Exec | asyncssh_pool.py:389-437 | RISK | `exec_ssh_command` 接受任意 command;调用方须 JWT+审计 |
| H-Elevation | files_elevation.py:21-28 | SAFE | 未知值回退 AUTO |
| H-Auth | filePreload.ts:101-105 | SAFE | read-file JWT + max_size |
| H-Cache | filePreload.ts:25-58 | SAFE | 内存 Mapprune 按目录 |
| H-Size | filePreload.ts:6-9,67-68 | SAFE | 300KB 预读 / 2MB 编辑上限 |
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## L3 门控(同日记录)
`bash deploy/pre_deploy_check.sh`**6/7 PASS**Gate 7 BLOCK`HEAD~1` 与未提交改动 `.cursorrules``docker-compose.yml` 等未列入当日 audit 文件)。属工作区脏树预期;**非代码缺陷**。部署前需 commit + 审计清单对齐或放宽 Gate7 策略。
## DoD
- [x] len(H) == Closure
- [x] 五文件全文 Read
- [x] local_verify 通过
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,66 @@
# Phase 2 深审 — Wave P2-2sync_v2 全文 + 路径/Shell 依赖)
**日期**: 2026-06-04
**范围**: `sync_v2.py` 1656 行全文 + 路径校验与 SSH 包装
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/sync_v2.py` | Python | 1656 | 11656 全文(分段 Read 至 EOF |
| 2 | `server/utils/posix_paths.py` | Python | 149 | 1149 全文 |
| 3 | `server/infrastructure/ssh/remote_shell.py` | Python | 63 | 163 全文 |
| 4 | `server/api/remote_path_validation.py` | Python | 33 | 133 全文 |
| 5 | `server/utils/unix_ls.py` | Python | 115 | 1115 全文 |
## 入口表(sync_v2 全 22 路由)
| 路由 | 鉴权 |
|------|------|
| POST `/files`, `/preview`, `/file-ops`, `/file-clipboard`, `/browse` | JWT |
| POST `/browse-local`, `/local-file-ops`, `/local-file-preview` | JWT + upload 沙箱 |
| POST `/cancel`, `/reconcile-stale-logs`, `/validate-source-path`, `/diagnose` | JWT |
| POST `/file-diff`, `/upload`, `/upload-zip`, `/verify` | JWT |
| POST `/download`, `/read-file`, `/write-file`, `/chmod`, `/compress`, `/decompress` | JWT |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Auth | sync_v2.py:741614 | SAFE | 22 路由均 `Depends(get_current_admin)` |
| H-Shell | sync_v2.py:156-168 | RISK | `rm -rf` 删目录;JWT+审计+前端 confirm |
| H-Shell | sync_v2.py:156,165,168,223-227 | SAFE | path shlex.quote |
| H-Path | sync_v2.py:149-165 | SAFE | normalize_remote_abs_path |
| H-Clipboard | sync_v2.py:207-208 | SAFE | assert_clipboard_transfer_safe |
| H-Sandbox | sync_v2.py:302,341,413,721 | SAFE | ensure_under_nexus_upload |
| H-Source | sync_v2.py:548,1096 | SAFE | FORBIDDEN prefixes + resolve |
| H-Audit | sync_v2.py:461-475 | SAFE | 失败 log warning+exc_info,非静默 pass |
| H-Upload | sync_v2.py:876-877,977-978 | SAFE | 100MB / 500MB 上限 |
| H-ZipSlip | sync_v2.py:1000-1005 | SAFE | assert_zip + is_path_under_prefix |
| H-Download | sync_v2.py:1244-1272 | SAFE | 100MB + filename sanitize |
| H-Read | sync_v2.py:1322-1326 | SAFE | max_size 来自 payload |
| H-Write | sync_v2.py:1394-1414 | SAFE | 5MB + etag 409 冲突 |
| H-Chmod | sync_v2.py:1507-1514 | SAFE | recursive policy + test -d |
| H-Verify | sync_v2.py:1145-1146 | SAFE | sha256sum 路径 shlex.quote |
| H-Path | posix_paths.py:46-59 | SAFE | 禁 `..` 与反斜杠 |
| H-Path | posix_paths.py:117-136 | SAFE | upload 前缀 + zip-slip |
| H-Sudo | remote_shell.py:35-53 | SAFE | bash -c + shlex.quote(command) |
| H-Clipboard | remote_path_validation.py:24-33 | SAFE | dest 非源子树 |
| H-Parse | unix_ls.py:70-71 | SAFE | 跳过 `.` `..` |
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] sync_v2 全文 ReadD1 仅 grep+分段,本波补全)
- [x] len(H) == Closure
- [x] local_verify 通过
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,61 @@
# Phase 2 深审 — Wave P2-3WebSocket / Dashboard 告警链)
**日期**: 2026-06-04
**范围**: 后端 WS 双通道 + 前端告警客户端 + Dashboard 刷新
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/websocket.py` | Python | 552 | 1552 全文 |
| 2 | `frontend/src/composables/useWebSocket.ts` | TS | 178 | 1178 全文 |
| 3 | `frontend/src/pages/DashboardPage.vue` | Vue | 415 | 1415 全文 |
| 4 | `frontend/src/App.vue` | Vue | — | 247260WS 生命周期) |
| 5 | `server/api/settings.py` | Python | — | 759828alert-history GET |
## 入口表
| 通道 | 路径 | 鉴权 |
|------|------|------|
| WS | `/ws/alerts?token=` | `_verify_ws_token` |
| WS | `/ws/sync?token=` | 同上 |
| HTTP | GET `/api/alert-history/` | JWT |
| HTTP | GET `/api/servers/stats` | JWTDashboard |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-WS-Auth | websocket.py:304-311,340-347 | SAFE | 无 token → 4001;无效 → 4401 |
| H-WS-Token | websocket.py:366-410 | SAFE | tv/updated_at 与 HTTP JWT 一致 |
| H-WS-ADR011 | websocket.py:9,296 | RISK | query JWT;单人运维已接受 |
| H-WS-Limit | websocket.py:49-52 | SAFE | MAX_CONNECTIONS=500 |
| H-WS-Heartbeat | websocket.py:139-165 | SAFE | 30s ping / 60s zombie |
| H-WS-Channel | websocket.py:246-249,531-551 | SAFE | alerts 与 sync 分 channel/manager |
| H-WS-Dedup | websocket.py:416-437 | SAFE | Telegram 5min 冷却;WS 仍实时 |
| H-WS-Recovery | websocket.py:512-513 | SAFE | recovery 清 cooldown |
| H-Frontend-Token | useWebSocket.ts:61 | RISK | URL query token;同 ADR-011 |
| H-Frontend-Auth | useWebSocket.ts:114-116 | SAFE | 4001/4401 → forceLogout |
| H-Frontend-XSS | useWebSocket.ts:99-102 | SAFE | snackbar 文本插值,无 v-html |
| H-Frontend-Singleton | useWebSocket.ts:17-18 | SAFE | 模块级单例;App 统一 connect |
| H-Dashboard-Refresh | DashboardPage.vue:393-397 | SAFE | WS alert → reload stats/alerts |
| H-Dashboard-API | DashboardPage.vue:302-337 | SAFE | http JWT 拉 stats/alert-history |
| H-App-Lifecycle | App.vue:257-259 | SAFE | login connect / logout disconnect |
| H-Alert-API | settings.py:768-828 | SAFE | alert-history JWT + 参数化 filter |
**len(H)=16, Closure=16**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] len(H) == Closure
- [x] websocket 全文 Read
- [x] 端到端链:Agent→broadcast_alert→Redis→WS→Dashboard refresh
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,68 @@
# Phase 2 深审 — Wave P2-4servers.py 全文)
**日期**: 2026-06-04
**范围**: 服务器 CRUD/Agent/导入/批量 SSH 全文 + 凭据加密/文件能力探测
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/servers.py` | Python | 1742 | 11742 全文(分段 Read 至 EOF |
| 2 | `server/infrastructure/database/crypto.py` | Python | 54 | 154 全文 |
| 3 | `server/infrastructure/ssh/files_capability.py` | Python | 63 | 163 全文 |
| 4 | `server/utils/files_elevation.py` | Python | 55 | 155 全文(P2-1 已读,本波交叉验证) |
| 5 | `server/infrastructure/ssh/remote_shell.py` | Python | 63 | 163 全文(P2-1 已读,setup-files-sudo 关联) |
## 入口表(servers.py 26 路由)
| 类别 | 路由数 | 鉴权 |
|------|--------|------|
| CRUD / 列表 / stats | GET/POST/PUT/DELETE | 全部 JWT |
| CSV import | POST `/import` | JWT + 1MB/500行 |
| 批量 Agent | POST `/batch/*` | JWT + Semaphore(5) |
| Agent 单台 | POST `/{id}/install|uninstall|upgrade-agent` | JWT |
| 敏感 reveal | POST `/{id}/agent-key`, `agent-install-cmd` | JWT + bcrypt re-auth |
| files | GET/POST `files-capability`, `setup-files-sudo` | JWT |
| health | POST `/check` | JWT |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Auth | servers.py:26×路由 | SAFE | 26 端点均 `get_current_admin` |
| H-Mask | servers.py:1692-1698 | SAFE | password_set / agent key 前缀截断 |
| H-Encrypt | servers.py:1096-1099,559-562 | SAFE | Fernet encrypt 入库 |
| H-Allowlist | servers.py:1163-1187 | SAFE | UPDATE 字段白名单;agent_api_key 排除 |
| H-Reauth | servers.py:1256-1260,1479-1483 | SAFE | agent-key/install-cmd 需当前密码 |
| H-Reveal | servers.py:1492-1502 | SAFE | install-cmd 不用全局 API_KEY |
| H-AgentKey | servers.py:1282-1288 | SAFE | 生成后 display_once 响应 |
| H-Fallback | servers.py:626,1321 | RISK | batch/single install 可回退 settings.API_KEY |
| H-Shell | servers.py:631-633,1330-1332 | SAFE | install shlex.quote url/key/port |
| H-Sudo | servers.py:36-60 | RISK | 临时 sudoers 白名单;运维必要 |
| H-SudoPwd | servers.py:1025-1027 | SAFE | sudo -S 密码走 stdin 非 argv |
| H-CSV | servers.py:376-388,445-446 | SAFE | formula injection 防御 + 1MB 上限 |
| H-CSV | servers.py:499-501 | SAFE | MAX_IMPORT_ROWS=500 |
| H-Batch | servers.py:615,686,772,850 | SAFE | Semaphore(5) 并发上限 |
| H-Redis | servers.py:179-201,873-877 | SAFE | 心跳 overlay;失败 log warning |
| H-Audit | servers.py: CUD/batch | SAFE | 写操作 AuditLog |
| H-Crypto | crypto.py:20-26 | SAFE | 无 ENCRYPTION_KEY 则 RuntimeError |
| H-Crypto | crypto.py:52-54 | SAFE | decrypt 失败 raise,非静默 |
| H-Capability | files_capability.py:31-39 | SAFE | 只读 probe,无密码回传 |
| H-Elevation | files_elevation.py:48-55 | SAFE | apply_files_elevation_payload |
**len(H)=20, Closure=20**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] servers.py 1742 行全文 Read(补 D3 分段)
- [x] len(H) == Closure
- [x] local_verify 通过
## 验证
`bash scripts/local_verify.sh` — 全绿
@@ -0,0 +1,61 @@
# Phase 2 深审 — Wave P2-5webssh.py 全文)
**日期**: 2026-06-04
**范围**: WebSSH WebSocket 端点 + 令牌签发链 + 前端连接
**标准**: `standards/line-walk-audit-standard-v2.md` 8 步
## 登记
| # | 文件 | 语言 | 行数 N | Read 范围 |
|---|------|------|--------|-----------|
| 1 | `server/api/webssh.py` | Python | 401 | 1401 全文 |
| 2 | `server/api/auth.py` | Python | 374 | 330349webssh-token 端点) |
| 3 | `server/application/services/auth_service.py` | Python | 684 | 412471create_webssh_token |
| 4 | `server/api/dependencies.py` | Python | — | 167180check_dangerous_command |
| 5 | `frontend/src/composables/terminal/useTerminalSessions.ts` | TS | 749 | 277311(令牌 + WS URL |
## 入口表
| 方法 | 路径 | 鉴权 |
|------|------|------|
| WS | `/ws/terminal/{server_id}?token=` | purpose=webssh JWT |
| POST | `/api/auth/webssh-token` | JWT + server 存在 |
## Closure 表
| H | 文件:行号 | 判定 | 理由 |
|---|-----------|------|------|
| H-Purpose | webssh.py:48-49 | SAFE | 拒绝非 webssh purpose |
| H-Bind | webssh.py:106-109 | SAFE | token server_id 须匹配路径 |
| H-TV | webssh.py:66-76 | SAFE | tv 校验;legacy updated_at +5s grace |
| H-Close | webssh.py:97-104 | SAFE | 缺 token→4001;无效→4401 |
| H-Issue | auth.py:334-346 | SAFE | 签发前 JWT + server/domain 校验 |
| H-Scope | auth_service.py:455-470 | SAFE | JWT 含 server_id + purpose + tv |
| H-Expire | auth_service.py:467 | SAFE | 15 分钟短期令牌 |
| H-WSQuery | webssh.py:88, useTerminalSessions:293 | RISK | ADR-011 query token(已接受) |
| H-Cred | webssh.py:126-135 | SAFE | key/password 配置检查 |
| H-Audit | webssh.py:137-146,353-366 | SAFE | connect/disconnect 审计 |
| H-Session | webssh.py:148-157,369-376 | SAFE | SshSession 创建/关闭 |
| H-DB | webssh.py:111-158 | SAFE | 长连接前关闭 DB session |
| H-Pool | webssh.py:167,337 | SAFE | acquire/release + stale retry |
| H-CmdLog | webssh.py:277-290,379-398 | SAFE | Enter 触发;2000 字符截断 |
| H-Danger | dependencies.py:167-180 | RISK | 危险命令仅 WARN 不阻断(设计) |
| H-Resize | webssh.py:293-296 | SAFE | cols/rows 边界默认 80×24 |
| H-Error | webssh.py:171,204 | SAFE | SSH 失败不向客户端泄露栈 |
**len(H)=17, Closure=17**
## FINDING
无 P0/P1 新 FINDING。
## DoD
- [x] webssh.py 401 行全文 Read
- [x] 令牌签发链交叉验证
- [x] len(H) == Closure
- [x] local_verify 通过
## 验证
`bash scripts/local_verify.sh` — 全绿

Some files were not shown because too many files have changed in this diff Show More