Preserve staging I/O failure causes (T-615)

This commit is contained in:
ila
2026-07-19 20:28:56 +08:00
parent d1603c52b6
commit df6c243b21
14 changed files with 551 additions and 76 deletions
+6 -3
View File
@@ -160,6 +160,7 @@ T-102 Phase 1 原型进一步固定:
- entrypoint 使用 payload 内相对路径表示,不得自带 `payload/` 前缀,且必须精确对应 ZIP 中的普通文件。
- 所有输出路径在创建 staging 前完成规划,并在逐段名称校验后再次验证 native `filepath.Join` 结果仍位于 destination 内;包含性检查是纵深防御,不能替代 Windows 名称规则。
- `app.json` 必须是 ZIP 根目录唯一普通文件,读取上限 1 MiB;严格 JSON 解析拒绝未知字段和尾随值,完整 v1 字段/常量必须通过运行时校验。`id`、`version`、`channel`、`min_os`、`architecture`、`entrypoint`、`requires_admin` 必须与可信 Catalog selection 一致;只有这一比对成功后才可创建 staging 并提取 payload。
- T-615 将 ZIP 输入与 staging 输出错误分开:ZIP entry 的 open/read/CRC/close 失败保留为 `ErrArchiveCorrupt`;创建目录/文件、write、sync、close 与 staging-tree sync 失败保留 `ErrStagingOutput` 和底层错误链,不能误报为 ZIP 损坏。提取失败后的本次 staging 清理必须可观察;主失败和清理失败同时发生时,两者都可由 `errors.Is` 识别。
### 2.4 安装记录 installed-app.json(本地)
@@ -218,13 +219,15 @@ T-613 为该原型建立了 fail-closed 的耐久顺序:每个 payload 先完成
T-302 在 Switcher 的 health 阶段先运行必需的注入 health check,再原子写入新 `installed-app.json`;health 或记录写失败都必须触发既有 rollback,使旧 current/记录保持可用。只有 health 与记录均成功后才写 committed 并清理 backup/journal。
若无 transaction 但存在残留 `staging/`,Recover 只会在 app root 已通过真实目录布局校验后删除该受控同级目录并返回 `aborted`;`staging` 不是目录或布局不安全时 fail closed。此恢复不得覆盖 `current/`、`installed-app.json`、`data/` 或 `licenses/`。
这些栅栏与注入失败测试只证明代码层面的调用顺序和 fail-closed 行为,不证明断电后硬件/驱动缓存、网络文件系统、文件锁或杀毒软件的物理表现。T-302 已完成代码整合;T-601 仍须在目标 Windows VM/真机执行断电与干扰故障注入。
### 2.6 安装预检与失败码
在同句柄 size/SHA、ZIP 预扫描和严格 `app.json` 身份比对均通过后,提取器会在创建 `staging/` 前提供已规划 payload 的准确展开字节数、普通文件数和安全 entrypoint。安装 use case 必须以 `payload_bytes + 64 MiB` 查询 app root 所在卷的可用空间;可用空间不足时不创建 staging。预检不能替代写入、同步、切换或回滚阶段的 fail-closed I/O 错误处理。
安装 use case 同时在上述位置检查当前 `current/<entrypoint>` 是否正在运行。容量与运行状态均通过 core 接口注入;检查失败按不可安全继续处理。v1 不强杀、不启动、不等待进程退出。Windows Toolhelp 枚举、正常退出等待与启动协议属于后续 T-401,不能进入 core。
安装 use case 同时在上述位置检查当前 `current/<entrypoint>` 是否正在运行。容量、storage failure classifier 与运行状态均通过 core 接口注入,且均为必需依赖;classifier 只对已带 `ErrStagingOutput` 的原始 I/O 链识别磁盘满,core 不导入 Windows API。检查失败按不可安全继续处理。v1 不强杀、不启动、不等待进程退出。Windows Toolhelp 枚举、正常退出等待与启动协议属于后续 T-401,不能进入 core。
安装结果面向调用方的错误码为下表的稳定英文枚举;UI 负责本地化,原始错误只保留给 `errors.Is`、日志和诊断,不得进入 UI payload。
@@ -234,11 +237,11 @@ T-302 在 Switcher 的 health 阶段先运行必需的注入 health check,再
| `zip_path_escape` | ZIP/app manifest 路径违反共享 Windows 安全相对路径规则 |
| `zip_corrupt` | ZIP 结构、CRC 或受限读取/提取不完整,不能作为有效包 |
| `package_invalid` | package/app manifest 身份或协议不符合可信 selection |
| `disk_full` | 可用空间小于 `payload_bytes + 64 MiB` |
| `disk_full` | 可用空间小于 `payload_bytes + 64 MiB`,或平台 classifier 识别 staging write/sync/close 的底层 I/O 为磁盘满 |
| `disk_check_failed` | 无法可靠取得可用空间或得到非法容量值 |
| `app_running` | 当前目标程序仍在运行,更新不能替换 |
| `target_state_unavailable` | 无法可靠取得目标运行状态 |
| `install_failed` | 其他未细分的安装、健康、记录、切换或回滚失败 |
| `install_failed` | 其他未细分的安装、健康、记录、切换、回滚或非磁盘满 staging 输出 I/O 失败 |
上述任一预检或验证失败都发生在 switch 前;已有版本的 `current` 和 `installed-app.json` 必须保持可用,首次安装不得留下 executable `current`。