--- id: T-403 title: 便携配置路径与安全 legacy 迁移 phase: 4 deps: [T-202, T-309] status: TODO created: 2026-07-27 owner: codex --- ## 需求与背景 当前实例、设置和代理统一保存在 `%APPDATA%\\chub\\config.json`。用户需要将配置与正在运行的 `chub.exe` 放在同一目录,以支持复制目录后的独立便携环境。当前 `run.bat` 运行 `build\\chub.exe`,因此其目标配置文件为 `build\\config.json`。 ## 方案与边界 - 新增 `config.DefaultPath()`:基于 `os.Executable()` 的目录返回 `\\config.json`;不使用当前工作目录、`PATH` 或启动脚本目录。 - 新增 `config.LegacyPath()` 与 `config.OpenDefault()`。`OpenDefault()` 先解析目标 Store:目标文件存在时绝不读取、覆盖或合并 legacy;目标缺失时,若 legacy 文件存在,则使用现有 Store decode/normalize 校验后原子写入目标。 - 迁移成功后保留旧 AppData 文件为恢复备份,不删除、不重命名、不继续作为活动来源;后续启动始终选择 exe 同级目标。跨卷迁移不使用 `Rename`,避免部分移动或数据丢失。 - legacy 缺失时不创建空目标;legacy 畸形、目标路径解析失败或目标目录不可写时返回稳定错误,不创建半成品文件,不静默回退 AppData。目标文件已存在时,即使 legacy 发生错误也不影响目标读取。 - CLI 和 GUI 都只经 `OpenDefault()` 取得 Store。GUI 启动失败必须记录安全诊断并在现有界面提供可恢复反馈;不得把配置内容、完整配置路径、URL、代理或凭据展示/写入诊断。 - 本任务不改变实例 schema、User Data Dir、日志目录、代理字段、文件加密、自动合并、配置路径选择 UI、CLI `--config` 参数或安装版策略。根目录可能存在 `config.json`,因此将其、`.bak` 和原子写入临时文件加入 `.gitignore`。 ## 验收要点 - 自动化命令:覆盖 exe 路径解析、legacy 路径解析、首次合法迁移、目标优先、缺失 legacy、畸形 legacy、目标父目录不可写/不可创建、迁移结果可 reload 和旧文件保留;覆盖 CLI 使用统一默认 Store。执行 `gofmt`、`go test ./...`、`go test -race ./cmd/chub ./internal/platform/config`、`go vet ./...`、`go build -o build/chub.exe ./cmd/chub`。 - Windows smoke:通过 `run.bat` 启动后,`build\\config.json` 由 GUI 创建/更新;将现有 `%APPDATA%\\chub\\config.json` 暂时作为 legacy 后首次启动,确认实例、代理和首选端口已进入 `build\\config.json`,旧文件仍可恢复;从不同当前工作目录启动同一 exe 仍使用同一个目标文件。 - 安全边界:不删除、移动或覆盖用户已有配置;不写入密码、Cookie、Token 或代理认证;迁移错误不导致浏览器启动/关闭或外部实例接管;文件写入保留 0600 权限与现有原子替换路径。 ## 执行记录 - 状态:TODO - 变更:已完成需求、架构、API、交互和迁移决策记录;待实施。 - 验证:待执行。 - 阻塞:无。 - 残余风险:程序安装到不可写目录时 strict portable 策略会拒绝保存;可配置路径/安装版回退留待后续任务。