Files
soft_quay/docs/tasks/T-401.md
T

73 lines
8.7 KiB
Markdown
Raw Normal View History

2026-07-19 20:47:45 +08:00
---
id: T-401
title: 进程检测、受控启动与切换临界区复查
phase: 4
deps: [T-303, T-615]
2026-07-19 21:10:59 +08:00
status: DONE
2026-07-19 20:47:45 +08:00
created: 2026-07-19
issue: null
2026-07-19 21:10:59 +08:00
context_ref: d0cf3333946af1eaace7b9c7f1edc58c38891f4d
2026-07-19 20:47:45 +08:00
claim_branch: null
2026-07-19 21:10:59 +08:00
work_branch: agent/codex/T-401
2026-07-19 20:47:45 +08:00
write_paths:
- docs/tasks/T-401.md
- core/application/install/
- core/application/launch/
- core/installer/
- core/storage/
- app-modern/platform/windows/
- app-win7/platform/windows/
2026-07-19 21:10:59 +08:00
- app-modern/go.mod
- app-win7/go.mod
- app-win7/go.work.sum
2026-07-19 20:47:45 +08:00
- app-modern/cmd/softbox/
- app-win7/cmd/softbox/
- docs/api.md
- docs/04-architecture.md
- docs/00-ai-start-here.md
- docs/06-tasks.md
- docs/current-state.md
- schemas/installed-app.schema.json
---
## 问题 / 背景
T-303 已定义 `TargetStateChecker` 并在 staging 前拒绝运行中的旧版本,但当前只有测试构造者;两个 `platform/windows` 仅返回 edition,未实现 Toolhelp 进程快照,也没有启动器。更重要的是,解压结束到 `current → backup` 之间仍可能启动旧版本。Phase 3 交叉复核要求在 rename 紧邻前显式复查;只有该检查明确返回运行中,才可映射 `app_running`,不得把权限、杀毒或目录错误的 rename 失败误归因。
当前 `installed-app.json` 只有 ID、版本和 payload files,未保留已验证 entrypoint、working directory、min_os 与 requires_admin;因此启动器不能在脱离 Catalog/下载任务时从本地可信记录安全推导启动路径,也不能做系统兼容与 elevation 预检。Gio shell 目前只展示“实际操作将在后续用例接入”,命令层也尚未装配安装或启动工作流;本任务必须如实保持这一现实,不能因此把未完成的下载→安装消费链或授权实现伪装为已完成。
## 方案
1. 在两个 `platform/windows` 增加相同的进程与启动适配边界。Windows 实现以 Toolhelp32 进程快照枚举并以规范化的绝对 entrypoint 身份匹配,不按可碰撞的 exe basename 匹配;通过内部 snapshot seam 覆盖枚举、条目和错误。非 Windows stub 对运行状态与启动返回明确“不支持/不可用”错误,绝不把无法检测伪装为“不在运行”。启动实现只执行已验证的绝对 EXE,显式设置 working directory,不经 shell、URL、PATH 搜索或任意 UI 字符串拼接;需要 elevation 时由 Windows 平台边界按既定 `requires_admin` 语义处理。
2. 扩展 `installed-app.json` v1 的可选启动元数据(`entrypoint`、`working_directory`、`min_os`、`requires_admin`):新安装必须从已比对的 Catalog/app manifest 写入并严格复用安全相对路径与已知 OS/布尔规则;旧 v1 记录保持可读,但没有完整启动元数据时启动 fail closed,不臆测默认 EXE 或工作目录。同步 schema、storage 校验、T-302 写记录路径和文档。
3. 新建纯 core 的 `application/launch` use case,只通过明确接口读取本地记录/受控 current 路径、检查系统兼容、授权和当前运行状态,再调用平台 launcher。它必须验证 `current`/working directory 为真实受控目录、entrypoint 为普通非 symlink 文件且仍位于 current 内;启动请求只含 app ID,不能接受任意 exe/path/args。授权是必需注入边界,T-401 只定义/消费它,不实现许可证策略、更不能使用 allow-all 生产实现。稳定 launch 结果码、错误和 `AppStarted` 事件只携带安全的 app ID/PID/码,原始错误留给后台诊断。
4. `InstallService` 显式消费既有 `TargetStateChecker`,通过 installer 的可注入 pre-switch hook 在存在旧 `current` 时、`current → backup` rename 紧邻前复查。明确返回运行中时清理本次 staging 并返回 `app_running`;检测错误返回 `target_state_unavailable`;其他 rename 错误仍保持原有 switch/rollback 归因。首次安装没有旧 current 时不执行第二次检查。这个 hook 不 import Windows API,也不等待、强杀或启动进程。
5. 两端 cmd 只装配可复用的 platform/core 启动依赖与后台提交边界,Gio Layout 仅提交 app ID,不做磁盘、进程或启动 I/O。若现有命令缺少 Catalog/许可证/下载消费的生产源,必须保留显式未装配状态并在 `current-state.md` 记录,不能伪称端到端闭环;T-402 只在 T-401 完整验证和提交后再落成。
## 验收要点
- Toolhelp 适配在 Windows 以完整 entrypoint 身份判断运行状态;snapshot 创建、迭代或路径查询失败可由调用者识别,并在 core 映射 `target_state_unavailable`。两个 workspace 均有相同 public contract、Windows build 与非 Windows stub 测试。
- 解压期间第二次检查发现旧 current 正在运行时,安装返回 `InstallStageSwitch` + `app_running`,旧 `current` 与 `installed-app.json` 字节不变,本次 staging/journal 被安全清理;第二次检查故障返回 `target_state_unavailable`。首次安装只走 staging 前检查。
- 新安装写入完整启动元数据;缺失/非法元数据、unsafe current/entrypoint、缺文件、系统不兼容、未授权、已运行与启动器失败均有稳定 launch 结果且不启动任何进程。启动器接收的 entrypoint/working directory 必须是 current 内的绝对路径;测试证明不调用 shell/PATH 且工作目录正确。
- 授权、兼容、进程和启动 I/O 均在后台 use case/平台层;Gio Layout 不做 I/O。`AppStarted` 只使用 app ID/PID,UI 不显示 raw error。没有真实许可证实现时,cmd 不得注入 allow-all 或宣称授权闭环完成。
- `go -C core vet ./...`、`go -C core test -count=1 ./...`、`go -C core test -count=10 ./application/install ./application/launch ./installer`、两个 Windows 交叉编译、`./scripts/verify_phase0.ps1`、`python scripts/validate_agent_context.py` 与 `python scripts/validate_harness_governance.py` 全部通过;执行记录写明是否存在尚未装配的真实 Catalog/许可证/下载消费来源。
## 边界(不改什么)
- 不实现下载 completed 文件的安全消费、失败保留或删除协议,不让 `InstallService` 删除任意 `DownloadPath`(O3 留给后续正式下载→安装编排)。
- 不实现等待退出、提示保存、超时、强杀、命名管道 `prepare_update/ready` 或物理 Windows 文件锁结论;前四项属于后续更新协议,锁/杀毒/断电真机验证属于 T-601。
- 不实现许可证签发、机器指纹、试用、导入或 allow-all 授权策略;这些属于 T-501~T-503。不得修改 Catalog、package、下载任务协议或 Gio 版本/Go 工具链。
- 不将 Windows API、Gio、SQLite 或第三方依赖引入 core;不执行 package 内任意脚本,不开放 UI/CLI 传入任意 exe、路径、参数或 shell command。
## 协作约束
- 当前项目为单 Agent 串行模式;当前 Agent 独占全部 `write_paths`,自行完成设计、安全复核、测试和提交,不启动子 Agent。
- 先提交本任务规格及路线图/状态文档;领取后将本文件改为 `DOING`,填写当前 HEAD `context_ref` 与 `work_branch: agent/codex/T-401`,再运行基线和实现。
- T-402 仅在本任务 `DONE`、验证和实现提交后再正式落成;若生产 cmd 仍无可信 Catalog/许可证/下载消费装配,必须在状态文档中明确其非闭环事实而非擅自扩展本任务。
## 执行记录
- 2026-07-19:正式落成。依据 Phase 3 交叉复核冻结 Toolhelp 身份匹配、启动元数据、受控启动、授权注入和 switch 临界区复查;明确 O3、退出协议、许可证策略与 T-601 真机验证的边界。
2026-07-19 21:10:59 +08:00
- 2026-07-19:领取任务,基于 `d0cf3333946af1eaace7b9c7f1edc58c38891f4d` 在 `agent/codex/T-401` 执行;先重新记录基线,再按任务规格实现。
- 2026-07-19:完成。`installed-app.json` 新安装写入受验证启动元数据;`application/launch` 只接受 app ID,按受控 current/普通 entrypoint、兼容、授权、精确运行状态和平台启动器顺序 fail closed。双端 Windows 平台以 Toolhelp32 + 完整映像绝对路径匹配、`RtlGetVersion` 兼容判断和无参数受控启动(管理员包固定 `runas`)实现,非 Windows stub 明确返回不支持。更新在 current→backup 紧邻前复查并清理拒绝的 staging,旧 current/记录不变;首次安装跳过复查。当前 cmd 没有可信 Catalog、许可证或 download 消费源,因此未注入 allow-all 授权、未伪装端到端启动按钮;Gio Layout 仍无 I/O。验证通过:`go -C core vet ./...`、`go -C core test -count=1 ./...`、`go -C core test -count=10 ./application/install ./application/launch ./installer`、两端 Windows amd64 构建、`./scripts/verify_phase0.ps1`、`python scripts/validate_agent_context.py`、`python scripts/validate_harness_governance.py`。