7.3 KiB
7.3 KiB
id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
| id | title | phase | deps | status | created | issue | context_ref | claim_branch | work_branch | write_paths | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T-403 | SoftBox 自更新助手与健康确认恢复 | 4 |
|
TODO | 2026-07-19 | null | null | null | null |
|
问题 / 背景
Phase 4 的子软件更新已能在用户关闭子软件后安全委托既有安装事务,但 SoftBox 主程序自身不能在运行中替换 EXE。当前架构/API 只描述了 SoftBoxUpdater.exe --pid --staging --target 的目标形状,仓库没有独立 updater、主进程退出等待、受限自更新目录布局、健康确认或中断恢复。因此下载到 staging 的新版无法安全激活,也不能在新版未正常启动时可靠保留旧版恢复路径。
自更新更新的是盒子 app/,不是 apps/<id>/。若助手接受任意 target/staging、跟随 symlink,或把“子进程已创建”误当成健康,可能覆盖 data/、licenses/ 或把不可用新版永久设为 current。当前没有可信自更新包下载/签名消费源,本任务只能提供独立、受约束的本地切换与恢复机制,不能伪称在线自更新已经接通。
方案
- 新建 Go 1.20 兼容的
core/updater,固定布局为<root>/app(target)、<root>/staging/<request-id>(已由可信外层准备的新目录)、<root>/backups/<request-id>、self-update-transaction.json与健康确认文件。请求只接受正主进程 PID、safe request ID、绝对且严格满足该布局的 staging/target;逐项Lstat拒绝 symlink、非目录、交叉 root、预存 backup/journal 异常,绝不接受 UI/CLI 传入可执行参数或任意移动路径。 - updater 先恢复上次未完成 transaction,再等待原主 PID 自然退出;取消、超时和等待错误均不触碰 target。退出后按 journal 栅栏执行
prepared → target_backed_up → staging_activated → launched → committed:只可把 oldapp改名为本 request 的 backup、把同 root staging 改名为app;每步用临时 JSON + 原子替换并同步目录。任何启动前/启动失败路径尝试恢复 old app;无法恢复时保留可验证 journal/backup,下一次 updater 可恢复,绝不删除 data/licenses。 - 新版只能以已验证绝对
<root>/app/SoftBox.exe、固定工作目录和内部固定--softbox-update-health <request-id>参数启动。SoftBox.exe在 Gio Layout 之前(非 UI goroutine I/O)从自己的可执行路径推导同一 root,校验 request ID 和 health locator 后原子写入仅含 request ID 的健康确认;不得接受路径、URL 或任意命令。助手等待匹配确认后才 committed/清理 backup;超时、错误或错误 request ID 均返回稳定失败,保留恢复材料。新版已运行但未确认且 Windows 拒绝 rollback 时 fail closed 留 journal,不强杀;后续受控 updater 在主 PID 退出后恢复。 - 两端
platform/windows增加一致的主 PID 自然退出和固定内部健康启动边界。Windows 以OpenProcess(SYNCHRONIZE)+ 可取消的短WaitForSingleObject轮询实现,不将无权限/不存在 PID 当作“已退出”;启动不经 shell/PATH、只传固定 health flag。非 Windows stub 明确返回不支持。clock/process/launcher seam 覆盖已退出、正常退出、取消、超时、OpenProcess/wait 错误与参数固定性。 - 两端新增无 Gio 的
cmd/softboxupdater,严格解析--pid、--staging、--target(内部 request ID 由助手生成),装配 core/platform 后以非 0 退出失败;主 cmd 只识别内部 health flag 并继续正常启动,不增加用户可传的任意执行入口。验证脚本同时构建主 EXE 和 Updater EXE;文档定义内部健康文件、恢复语义、真实下载/签名未装配事实与 T-601 真机限制。
验收要点
- core updater 拒绝非法 PID/request ID、相对/跨 root/不匹配布局、symlink/非目录、缺 staging、已有冲突 backup/journal;失败不改 target、staging、data 或 licenses。成功路径等待原 PID 退出,正确 rename/sync/journal,固定启动新 app,收到匹配 health request ID 后才 committed 并清理 backup/journal。
- PID 等待的取消、超时、OpenProcess/Wait 错误、launcher 失败、health 超时/错误 ID、每个 rename/journal 故障和崩溃注入均有稳定错误;可恢复时 old app 恢复且可启动,无法立即恢复时 journal/backup 保留供下次
Recover,不强杀新/旧进程。 - 新主程序只响应固定内部 health flag,从自身
app/SoftBox.exe推导 root 并原子写入最小确认,不在 Gio Layout I/O;不匹配 flag/request/layout 不写文件。双端SoftBoxUpdater.exeCLI 拒绝多余/无效参数,使用平台 PID 等待和固定启动调用。 - core 无 Windows/Gio/第三方依赖;双端平台 public contract 与 non-Windows stub 一致;Windows amd64 交叉编译主程序和 Updater,脚本/CI 闸门覆盖两个 EXE。真实 Windows 文件锁、杀毒/断电以及 UAC/签名发布行为仍由 T-601/T-603 验证。
go -C core vet ./...、go -C core test -count=1 ./...、go -C core test -count=10 ./updater、两个主程序和 Updater 的 Windows amd64 构建、./scripts/verify_phase0.ps1、python scripts/validate_agent_context.py、python scripts/validate_harness_governance.py全部通过;执行记录如实写明未装配可信自更新包下载/签名来源。
边界(不改什么)
- 不实现自更新 Catalog/package 下载、Ed25519 签名、SHA-256 校验、版本检查或自动触发;staging 只可由后续可信外层提供,不能把任意下载文件解压/执行。
- 不触碰
apps/<id>/子软件安装事务、data/、licenses/、子软件更新、授权策略或 allow-all 注入;不实现 updater 自更新、MSI、服务、注册表、shell script、强杀、命名管道或 UI 进度窗口。 - 不把 Windows API/Gio/SQLite 引入 core,不升级 Go/Gio/依赖,不开放
SoftBox.exe的用户自定义 path/args/command;内部 health flag 仅由 updater 固定生成。 - 不把单元测试等同于断电、文件锁、杀毒和 Windows VM/真机结论;这些保留 T-601/T-603。
协作约束
- 当前项目为单 Agent 串行模式;当前 Agent 独占全部
write_paths,自行完成规格、实现、审查、测试和提交,不启动子 Agent。 - 先提交本任务规格和项目快照;领取后将本文件改为
DOING,填写当前 HEAD 的context_ref与work_branch: agent/codex/T-403,再重新记录基线和实现。 - 本任务完成后停止;后续 Phase 5 许可证任务仍需按路线图另行正式落成,不能因自更新程序存在而假定下载、签名或发布流水线已完成。
执行记录
- 2026-07-19:正式落成。以 T-402 完成后的 Phase 4 依赖为基线,冻结独立 updater、受限根目录、PID 自然退出、健康确认 journal 和可恢复 rollback 的最小自更新协议;明确可信 self-update 下载/签名、真机故障和发布签名继续后置。