--- id: T-304 title: 代理配置库、实例选择与安全启动参数传递 phase: 3 deps: [T-303] status: DONE created: 2026-07-25 owner: codex --- ## 需求与背景 用户需要在“设置”中维护可复用的代理,并在创建或编辑实例时选择其中一项。代理必须在实际启动时转换为 Chromium 的 `--proxy-server` 参数,同时继续满足 Chub 的本地、安全和无秘密持久化边界。 ## 方案与边界 - 配置文件新增稳定 ID 的代理集合;每项仅有名称和无认证代理端点。实例只保存 `proxy_id`,原有非敏感 `LaunchSpec.ProxyServer` 仅用于兼容旧配置。 - 接受 `http`、`https`、`socks4`、`socks5` 的 `scheme://host:port` 端点;拒绝 userinfo、路径、query、fragment 与空 host/port。代理用户名、密码或其他认证秘密不得保存、记录或进入命令行。 - 设置页以紧凑的代理列表和就地表单完成新增、修改、删除。删除被实例引用的代理必须被拒绝并说明引用数量,不能隐式清空实例的选择。 - 新建抽屉与编辑对话框提供“代理”选择器,含“无代理”选项;选择器只暴露名称与端点,不要求用户重复输入代理地址。编辑活动实例时仍可修改后续启动使用的代理选择。 - 启动 adapter 在后台按 `proxy_id` 从当前配置解析端点,生成一次性的 `LaunchSpec.ProxyServer`;找不到代理时拒绝启动并保留稳定、无秘密的错误说明。UI frame 不做配置或进程 I/O。 - 代理配置更新后,下次启动立即使用最新端点;不修改已运行浏览器,也不尝试通过 CDP 接管外部实例。 ## 验收要点 - 设置页可新增、编辑和删除未被引用的无认证代理;格式错误、重复名称和删除已引用代理均有就地恢复提示。 - 新建和编辑实例可在“无代理”和已保存代理间选择;保存、重启后选择保持不变,旧的无 `proxy_id` 配置仍能加载。 - 选择代理后,Chrome/Edge 启动参数包含一次且仅一次正确的 `--proxy-server=`;无代理时不输出该参数。 - 配置、事件、错误和测试输出均不包含代理认证信息;含 userinfo 的输入被拒绝,不能写入配置或命令行。 - 覆盖配置序列化、端点校验、引用保护、实例保存、启动参数解析、选择器键盘操作和 UI 异步边界。 - `gofmt`、`go test ./...`、`go vet ./...`、`go build -o build/chub.exe ./cmd/chub`、`scripts/smoke-browser.ps1` 与 `scripts/smoke-windows.ps1` 通过。 ## 执行记录 - 状态:DONE - 变更:配置文件新增稳定 `proxyId` 实例关联和 `ProxyProfile` 无认证代理库;加载旧配置时把原有安全 `LaunchSpec.ProxyServer` 自动迁移为命名代理。domain 的统一端点校验同时保护配置和 Chromium 参数构造。Gio 设置页新增代理的就地新增、编辑、引用保护删除;新建和编辑实例通过持久代理选择弹层选择“无代理”或命名项。启动 adapter 在后台按 ID 解析最新端点并填入一次性 `LaunchSpec.ProxyServer`,找不到选择项时拒绝启动。 - 验证:`gofmt -w cmd/chub/main.go internal/ui/shell.go internal/platform/config/store.go internal/domain/browser.go internal/platform/browser/launch.go internal/domain/browser_test.go internal/platform/config/store_test.go cmd/chub/main_test.go internal/ui/shell_test.go`、`go test ./...`、`go vet ./...`、`go build -o build/chub.exe ./cmd/chub`、`scripts/smoke-browser.ps1`(真实 Chrome/Edge)和 `scripts/smoke-windows.ps1` 均通过。 - 阻塞:无。