Files
opsxshell/docs/testing-acceptance.md
T
Logan.LiandCursor 08696896f9 feat: harden local shell, SFTP, and desktop session reliability
Finder-launched terminals now inherit a login PATH so tools like ollama resolve, destructive SFTP/editor actions require confirmation, and terminal search plus window dragging work again. SSH forwards and RDP sessions keep listeners and survive reconnect without FastPath crashes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-16 16:08:11 +08:00

132 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 测试与验收
## 本地门禁
日常开发执行:
```bash
npm run acceptance:quick
```
依次检查界面类型、测试 API 契约、全部 Vitest 测试、Rust 格式和 Rust 编译。
提交或发包前执行:
```bash
npm run acceptance:full
```
完整门禁额外执行 ESLint、Clippy 零警告、Rust 测试、前端生产构建和发布脚本测试。任何步骤失败都会立即返回非零状态。
## 覆盖重点
- 应用壳在原生 API 可用和不可用时都能稳定渲染
- 会话新建、密码/私钥认证、代理和跳板配置
- SSH Config 解析和会话导出真实写盘
- 批量打开终端、SFTP 和批量命令
- Tauri 事件监听注册/销毁竞态
- SSH 连接关闭后的状态回收
- HTTP CONNECT、SOCKS5 和断点复制
- 转发规则不持久化运行状态,复制产生新 ID;原生隧道可启动、查询、停止并在 SSH 断开时清理
- 状态栏「转发」抽屉启停动态 `127.0.0.1:1080`,右键复制 SOCKS 地址;每台 SSH 主机仅一条动态规则
- i18n:全部 APP_LANGUAGES(zh-CN / zh-TW / en / ja / ko / vi / ru)的 namespace key 对齐(`test/i18n/localeKeys.test.ts`)
- RDP / VNC 仅原生可用;非 Tauri 环境不得显示为可连接;桌面会话不参与批量命令
- SFTP 本地/远程路径参数方向、原生路径上传、选中文件下载、双栏双向拖拽、目录落点、远程文本读写和错误反馈
- 终端分屏、剪贴板、快捷键、分片 UTF-8 解码、高输出背压和异步输入错误
- `ssh://` 安全解析、冷启动队列、IPv6 格式和快速连接预填充
- AI Provider 的 OpenAI Chat、Responses、Anthropic 响应解析和 HTTP Endpoint 限制
- models.dev 多种 JSON 形态归一化、目录源部分失败降级和 new-api `/models` 列表
- API Key 只进入 Rust secrets,不出现在 `ai-providers-v1`、日志或 WebView 返回值中
- Agent CLI 单任务入口、回车发送、选区上下文、本地脱敏、单行命令协议和最终结论
- 新 Provider 测试前不落盘,真实测试成功后才启用保存;任一连接字段变化会使验证快照失效
- Agent 固定当前 SSH connection;达到当前安全模式确认阈值时,确认前不得调用 `ssh_exec`;退出码与真实输出反馈下一轮且不进入历史
- Agent 五级命令风险、critical 硬拒绝、连续失败换路、相同命令循环拦截和长输出 `analyze_output`
- 远程 Shell EOF/TMOUT 事件不得误判为整个 SSH 连接断开;只为对应分屏提供一键重开
- macOS 原生“编辑”菜单以及所有输入框的复制、剪切、粘贴、全选、撤销;应用快捷键不得覆盖这些系统操作
- 普通界面右键不出现 WebView 的 Reload/Inspect Element;输入框仍保留系统编辑菜单,自定义右键不受影响
测试替身必须完整实现 `DesktopApiContract`。新增或删除桌面接口后,`typecheck:test` 必须能发现未同步的契约。
## AI 助手验收
自动验收不得使用真实个人 API Key。可以用本机 mock OpenAI Compatible 服务验证以下边界:
1. Provider 没有 Key 时返回明确错误;保存 Key 后普通设置 JSON 中搜索不到明文。
2. HTTPS 为默认要求,任意公网 HTTP Endpoint 被拒绝;只有显式允许后才能访问可信本机 HTTP 服务。
3. OpenAI Chat、OpenAI Responses 和 Anthropic 三种响应都能提取文本,错误响应显示 HTTP 状态和供应商消息。
4. `Authorization: Bearer`、密码字段、AWS Key 和私钥在请求发出前被替换,并显示脱敏计数。
5. 有选区时只发送选区;无选区时不抓取当前整屏。
6. 面板不再出现“解释 / 生成命令 / 排障 / 执行任务”切换;回车触发执行,`Shift+回车` 不触发。
7. 关闭再打开 AI 面板,之前的提示词和回答不存在。
8. models.dev 三个源全部失败时不影响已保存 Provider;部分成功时仍能生成可导入目录。
9. 新增 Provider 后测试前“保存”禁用;测试实际发送“你是什么模型?请简短回答。”,期间 settings 与 secrets 均无写入;只有非空成功回答显示 HTTP 200,随后保存才写入加密 Key。
10. 切换 Endpoint、模型、协议或 API Key 后“保存”立即重新禁用。
11. 每一轮只接受唯一单行命令;默认均衡模式下 safe/low/medium 自动执行、high 先确认;严格模式从 medium 起确认;宽松模式不允许绕过 critical 硬拒绝。需要确认时,对话框打开前和用户取消后 `ssh_exec` 调用次数必须为 0。
12. 确认后只向当前 connectionId 执行;真实输出和 exit code 必须交给下一轮,直到 FINAL 或 8 步上限。
13. `rm -rf /`、`mkfs`、对磁盘覆盖的 `dd` 等 critical 命令必须在确认对话框前硬拒绝。
14. 相同命令第 3 次必须在执行前拦截;连续失败的下一轮 Prompt 必须要求更换路径。
15. 超长工具输出必须限长,`analyze_output` 保留总行数、错误行和首尾;关闭面板后命令与输出消失。
## 真实 SSH/SFTP 探针
真实探针默认标记为 ignored,必须显式提供测试服务器:
```bash
OPSX_TEST_SSH_HOST=example.com \
OPSX_TEST_SSH_PORT=22 \
OPSX_TEST_SSH_USER=root \
cargo test --manifest-path src-tauri/Cargo.toml \
real_ssh_exec_and_sftp_probe -- --ignored --nocapture
```
该探针会执行 SSH 命令、创建 SFTP 通道,并在远端 `/tmp` 完成一个临时文件的上传、下载、逐字节比对和清理。只有列目录成功不算 SFTP 基础传输验收通过。
ProxyJump 探针额外设置 `OPSX_TEST_SSH_JUMP_HOST`、`OPSX_TEST_SSH_JUMP_PORT`;使用 `OPSX_TEST_SSH_JUMP_COUNT=2` 可验证两级链。
动态 SOCKS5 真实探针使用同一组 SSH 环境变量:
```bash
OPSX_TEST_SSH_HOST=example.com \
OPSX_TEST_SSH_PORT=22 \
OPSX_TEST_SSH_USER=root \
cargo test --manifest-path src-tauri/Cargo.toml \
real_dynamic_forward_probe -- --ignored --nocapture
```
它会创建随机本地 SOCKS5 监听,通过 SSH `direct-tcpip` 再连回测试主机,读取 `SSH-` 协议头,最后停止监听并确认运行状态已清理。
## 端口转发验收
Rust 单元测试会用随机本地端口验证动态监听器的唯一 ID、运行查询、重复启动拒绝和真实停止。实机验收还必须包含:
1. 在状态栏打开「转发」抽屉,启动 `127.0.0.1:1080`,用 `curl --proxy socks5h://127.0.0.1:1080 https://example.com` 验证(出口 IP 应为当前 SSH 服务器)。
2. 右键状态栏「转发」复制 `socks5://127.0.0.1:1080`,确认剪贴板正确。
3. 确认连接数和流量会变化(若界面展示统计)。
4. 停止后确认端口无法再连接,不能只检查 UI 颜色。
5. 重启应用后规则仍在,但状态必须为未运行。
6. 断开 SSH 主连接后,关联的本地、远程和 SOCKS5 监听器全部清理。
7. 复制规则后确认新规则 ID 独立且状态为未运行;编辑运行中的规则必须先停止原 Listener。
8. 同一 SSH 主机不得出现第二条动态规则。
## 远程桌面验收
1. 非 Tauri / 浏览器预览中,RDP / VNC 不得表现为可连接。
2. 原生应用中分别建立 RDP、VNC 会话,确认画面、键盘鼠标与断开清理。
3. RDP:验证剪贴板同步与共享盘放入/打开本机下载目录。
4. 批量命令入口不得包含桌面会话。
## ssh:// 验收
macOS 安装版先检查 `Info.plist` 包含 `ssh` URL scheme,然后分别验证冷启动和运行中唤起:
```bash
plutil -p OpsXShell.app/Contents/Info.plist | grep -A8 CFBundleURLTypes
open -a OpsXShell 'ssh://root@opsbase.cn:55555'
```
必须确认只存在一个 OpsXShell 进程、原窗口被聚焦、快速连接目标为 `root@opsbase.cn:55555`。`ssh://root:password@host` 和包含远程路径的链接必须被拒绝。Windows 需要在安装后的注册表和浏览器唤起场景重复验证,macOS 结果不能代替 Windows 验收。
## 发版验收
候选发布必须在目标系统完成:安装、首次启动、窗口操作、SSH、SFTP、代理、跳板、端口转发、RDP/VNC、串口枚举、休眠恢复、卸载及重新安装。CI 构建成功不能替代 Windows 或 macOS 实机验收。