6.7 KiB
6.7 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-302 | 安装流程整合 | 3 |
|
TODO | 2026-07-18 | null | null | null | null |
|
问题 / 背景
T-301 只能把网络字节可靠地落为隔离的 .download;下载任务元数据、完成路径和文件内容仍可被本地篡改,不能直接作为安装身份或可信包。T-102/T-612/T-613 已分别具备 ZIP 预扫描/安全解压和可恢复的 staging → current → backup 切换原型,但尚未把已验签 Catalog、完整包 SHA-256、严格 app.json 身份比对、安装记录和健康失败回滚串成一个可调用的 core use case。
本任务关闭这条生产安装链的代码级信任边界。外层 Catalog 的 Ed25519 签名覆盖嵌套 packages[arch] 的 size、sha256 与 signature 字段;当前协议没有定义 package signature 的独立待签名字节、密钥或轮换域,T-302 不得臆造第二套包级验签。它只接受已经由 catalog.Client 验签、严格解析并按目标过滤后的 Catalog 选择,并以该选择中的精确 size/SHA-256 重新验证本地完成文件。
方案
- 在
core/application落地InstallService:请求包含已过滤的catalog.Entry、目标 architecture 和.download路径。服务必须拒绝不可安装 entry、缺失 package、architecture 与App.Packages[architecture]不一致的选择;不得从downloader.Task、DownloadCompletedPayload或本地 metadata 重新取得 app/version/size/hash。 - 在
core/installer增加经过验证的包提取入口。它以一次Lstat → open → fstat → Lstat得到普通文件句柄,先确认实际长度精确等于 Catalog size、再以同一文件句柄计算 SHA-256,并以常量时间比较 Catalog hash;哈希不符时不得构造zip.Reader、读取app.json或创建 staging。随后仍以同一句柄完成 EOCD/ZIP64/中央目录预扫描和zip.Reader构造,不能按路径重新打开。 - 安全读取 ZIP 根目录唯一的
app.json(最大 1 MiB,严格 JSON、无未知字段/尾随值),校验 v1 的全部字段与共享 Windows 安全相对路径规则。身份字段必须与 Catalog 选择一致:id、version、channel、min_os、architecture、entrypoint、requires_admin;其余 v1 常量和值也必须符合schemas/app.schema.json。只有通过比对后,才复用既有两阶段 ZIP 检查把payload/解压到全新的apps/<id>/staging。 - 解压复制时为每个实际 payload 文件计算 size/SHA-256,作为
ExtractResult的已观察文件清单。InstallService将此清单写入installed-app.json,不信任或依赖可选的files.json作为新的信任根;保留 v1files.json的协议语义和后续修复功能边界。 - 每次安装先对 app root 调用既有
installer.Recover。提取成功后以已有Switcher激活 staging;必需的注入 health check 先通过,随后在同一个 switch health 阶段原子写入新installed-app.json,使 health/记录写失败走既有 rollback,保留旧current与旧记录。成功才清理 backup/journal。返回的阶段化错误和结果要能让后台调用方区分验证、解压、切换/回滚和记录失败;UI 仍只通过 application 事件/结果更新状态,不在 Gio Layout 做 IO。 - 为上列顺序补齐隔离的单元/集成测试:成功安装、Catalog 选择不一致、非普通/替换的完成文件、size/SHA 不符(确认 ZIP/app.json/staging 未触及)、恶意或不匹配
app.json、完整安装记录文件清单、已有版本健康或记录写入失败后的回滚、安装前 transaction recovery。测试包只使用运行时生成的虚构 ZIP/哈希。
验收要点
InstallService的唯一可信输入是已验签/过滤 Catalog 的 entry + architecture;篡改下载 metadata、request/app ID 或 completed 路径不能改变实际验证的 package identity、size 或 SHA-256。- 普通完成文件的 Catalog size 和 SHA-256 均在同一打开句柄上通过后,才允许 ZIP 预扫描、
app.json读取、staging 创建和 payload 写入;所有失败保留errors.Is可识别的根因。 app.json严格符合 v1,并与 Catalog 的 ID、版本、通道、最低系统、架构、入口和管理员标记一致;安全路径、未知字段、重复/缺失入口或不匹配一律拒绝。- 成功链为
recover → verify → manifest compare → safe staging extract → switch → health → installed-app record → committed cleanup;记录含每个实际 payload 文件的安全相对路径、字节数和 SHA-256。 - health 或记录写失败时,已有版本的
current与旧installed-app.json恢复并保持;首次安装不留下可执行current。已有未完成 transaction 先按恢复状态机收敛。 go -C core vet ./...、go -C core test -count=1 ./...、./scripts/verify_phase0.ps1、python scripts/validate_agent_context.py与python scripts/validate_harness_governance.py全部通过;任务执行记录写明结果。
边界(不改什么)
- 不修改 Catalog 签名协议、Schema 或密钥;不为 nested package
signature虚构独立验签算法。外层已验签 Catalog 是本任务唯一的密码学身份来源。 - 不做磁盘空间预检、程序占用/退出等待、面向 UI 的完整错误码映射或下载重试策略(T-303/T-401);不强杀或自动启动包内程序。
- 不做 Gio 安装面板、下载完成到安装调用的 UI 编排或物理断电/杀毒软件/文件锁故障注入。T-302 只提供无头 core use case;真实 Windows VM/真机故障注入仍由 T-302/T-601 发布前环境验证完成。
- 不改变
files.json的 v1/v1.1 协议或实现修复功能,不引入数据库、第三方包、Gio、Windows API 或 Go 1.21+ API。
协作约束
- 当前项目为单 Agent 串行模式;当前 Agent 独占全部
write_paths,自行完成设计、安全复核、测试和提交,不启动子 Agent。 - 先提交本任务规格与关联协议/架构/状态文档;领取后将本文件改为
DOING,填写当前 HEADcontext_ref与work_branch: agent/codex/T-302,再运行基线和实现。 - T-303、T-401 及任何后置任务在本任务
DONE、验证与实现提交前不得领取或提前修改。
执行记录
- 2026-07-18:正式落成。冻结可信输入、同句柄 size/SHA/ZIP 顺序、严格 app.json 对齐、实际 payload 文件记录、health 内记录写入回滚语义和后续任务边界;待领取后执行基线验证与实现。