# UtiliVera Capture 0.6.0 安装器独立审核（Round 1）

审核日期：2026-08-15  
审核角色：独立安装/发布审核员（未参与构建）  
审核边界：冻结 `dist`、Inno 源码、候选安装器、payload manifest、构建/安装/稳定性证据与持久日志；只读审核，未修改实现或 `static-dist`

## 结论

**内部安装工程：FAIL（P0=0，内部 P1=1）。正式公开发布：BLOCKED（另有外部 P1=2）。P2=4。**

安装体系的主体工程质量较高：冻结 EXE 与候选身份准确；258/258 payload 经本审核员独立复算无差异；.NET 4.8 注册表门禁存在；10 种安装语言均完成静默安装/卸载并留下 13 份持久日志；同版 repair、卸载与主要残留检查通过；完整的产品许可及 NAudio、ZXing.Net、Fluent UI Icons 许可文本被安装；10/10 构建得到唯一安装器哈希。

但 `.NET 4.8` 不满足时的 `DotNet48Required` 只有一条无语言前缀的英文 `CustomMessages`，因此简/繁中文等 9 个非英语安装语言在最关键的阻断路径仍显示英文；现有 10 语言测试只覆盖已具备 .NET 4.8 的成功路径，也没有验证缺少前置组件时确实在复制文件前失败。该缺口使“10 种安装语言 + .NET 4.8 gate”尚不能作为完整专业体验通过，列为内部 P1。

此外，安装器与主 EXE 均为 `NotSigned`，且 `/capture/` 与 `/capture/releases/0.6.0/` 尚未进入当前冻结站点产物。这两个外部 P1 独立阻断正式公开下载。当前候选只能用于内部整改和验证，不得称为正式发布版。

## 1. 冻结身份：PASS

| 对象 | 大小 | SHA-256 | Authenticode |
|---|---:|---|---|
| `UtiliVeraCapture.exe` | 293,888 bytes | `3832C20012F30B07C2D61ACECCAFC9949B4738F065C53D23D2C781D6BCCF5DB7` | `NotSigned` |
| `UtiliVeraCapture-Setup-0.6.0-Windows-x64.exe` | 3,004,187 bytes | `D055A376074ED6CF6EABE5F6294E460AAF5F75C9612E37F7C6BEA6553A4E4389` | `NotSigned` |

主 EXE 的 Win32 版本身份为 Product `UtiliVera Capture`、Version `0.6.0.0`；安装器为 Product `UtiliVera Capture`、Version `0.6.0`、Company `UtiliVera`。实测 bytes/SHA 与 `installer-build-evidence-0.6.0.json`、`installer-test-evidence-0.6.0.json`、payload manifest 和 `SHA256SUMS.txt` 一致。

## 2. 258-file payload 与安装嵌入：PASS

本审核员按 manifest 的每个 `relativePath` 对当前冻结 `dist` 独立复算：

- manifest entries：258
- 当前冻结 payload files（排除 `dist/installer`）：258
- missing：0
- extra：0
- bytes mismatch：0
- SHA-256 mismatch：0

manifest 的 `frozenExeSha256` 同样为 `3832C2...5DB7`。构建脚本对安装后的全部 258 项逐个检查存在性、长度与 SHA，并额外检查四份安装许可文件；build evidence 记录首次验证即成功，`validationFailuresBeforePass=0`。这一证据足以确认当前 D055A3...4389 候选嵌入的是同一冻结 payload，而非仅校验安装器文件名。

## 3. .NET Framework 4.8 门禁：功能存在，但本地化/负向证据 P1

Inno 的 `InitializeSetup` 在文件复制前同时查询 HKLM 64/32 位：

`SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\Release >= 528040`

EXE config 也明确声明 `.NETFramework,Version=v4.8`，两者一致。功能实现本身正确。

### P1-1：前置失败提示未覆盖 10 种语言，且缺少负向门禁测试

`[CustomMessages]` 只有无语言限定的英文 `DotNet48Required`。选择 `chinesesimplified`、`chinesetraditional`、Spanish、German、French、Japanese、Korean、Portuguese (Brazil) 或 Russian 时，缺少 .NET 4.8 的阻断提示仍回退英文。现有 10 语言矩阵只证明成功安装/卸载，未证明缺少 .NET 4.8 时的失败语义、退出状态和零文件复制。

**验收标准：**为 10 个 Inno language name 分别提供地道的 `DotNet48Required` 文案；增加可重复的前置缺失测试（隔离 VM 或可控注册表测试夹具），逐语言至少断言提示资源可解析，并在一个真实缺失 .NET 4.8 的干净 Windows 环境断言安装器非成功退出、安装目录未创建、产品注册表与快捷方式未写入。修复后重建并重新冻结 installer bytes/SHA、258 manifest、10/10 稳定性及安装矩阵。

## 4. 10 种安装语言与持久日志：成功路径 PASS

Inno 配置包含：English、简体中文、繁体中文、Spanish、German、French、Japanese、Korean、Portuguese (Brazil)、Russian。简/繁中文 `.isl` 使用官方 jrsoftware/issrc 文件并固定 SHA：

- ChineseSimplified：`E0B0B350E2245F3C5E65586DFE43D574F6E7F06F2261149ABA284954B3FC9A8D`
- ChineseTraditional：`031684FC769259291FD563338B5ABE20B7753C88AB5A2976B83A80788DEB8455`

test evidence 对 10 个 `/LANG=` 值逐项记录 install exit 0、uninstall exit 0 和目录已删除。持久目录中恰有 13 个非空日志：install、repair、uninstall 和 10 个 language install logs，总计 1,582,585 bytes。成功路径可以通过；P1-1 只针对前置失败路径的完整性。

## 5. 静默安装、repair、功能 smoke 与卸载：PASS，存在 P2 覆盖边界

证据与脚本绑定同一个 D055A3...4389 候选，记录：

- `/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-` install exit 0；
- 安装后主 EXE SHA 等于冻结 EXE；
- 安装后 `--settings-json` smoke exit 0，版本 0.6、MP4 上限 1800 秒、双轴滚动能力符合预期；
- 同版本 silent repair exit 0，主 EXE 哈希不变；
- silent uninstall exit 0；
- 安装目录删除；
- HKCU、HKLM 与 WOW6432Node 的 `UtiliVera Capture*` uninstall registration 删除；
- 当前用户开始菜单快捷方式删除；
- 10 个语言临时安装目录全部删除。

用户设置与诊断位于 `%LOCALAPPDATA%\UtiliVera\Capture`，卸载时有意保留；用户创建的 captures、profiles 和 `.uvcap` projects 不删除。这是数据保护策略，不应被误报为程序残留。

## 6. 许可与第三方通知：PASS

安装器交互式展示产品 `LICENSE.txt`，并把它安装到应用目录；`THIRD-PARTY-NOTICES.md` 随 258-file payload 安装。另安装完整文本：

- NAudio MIT：1,112 bytes；
- ZXing.Net Apache-2.0：10,207 bytes；
- Microsoft Fluent UI System Icons MIT：1,078 bytes。

test script 明确断言这五个面向用户的法律文件均存在，第三方 notices 也标明项目、用途和许可。当前证据未发现被引用二进制或图标缺少对应完整许可文本。

## 7. 10/10 deterministic stability：PASS

`installer-build-stability-0.6.0.json` 记录 requested=10、passed=10、uniqueInstallerHashes=1、deterministic=true，10 次均产出 `D055A3...4389`。每次构建都重新执行 payload 安装验证，最终候选的 build evidence 还记录零验证失败。该结果支持当前未签名候选的可重复性；签名后因 PE 字节和时间戳变化，必须针对最终签名字节重新冻结和审计，不能沿用此 SHA 作为公开包身份。

## 8. 外部发布 P1

### P1-2：安装器与主 EXE 均未签名

独立 `Get-AuthenticodeSignature` 实测两者均为 `NotSigned`；build/test evidence 也诚实标记 `releaseGate=BLOCKED_NOT_SIGNED`。

**验收标准：**使用受信代码签名证书签署冻结主 EXE 与最终 Inno 包并加 RFC 3161 时间戳；在干净 Windows 10/11 环境验证两者均为 `Valid`；按签名后的最终字节重新生成 bytes/SHA、258 payload manifest、10/10 stability 和完整 install/repair/uninstall/10-language 证据；网站只能引用最后一次独立审核通过的签名包。

### P1-3：产品与版本 URL 尚未部署

Inno 固定：

- `https://utilivera.com/capture/`
- `https://utilivera.com/capture/releases/0.6.0/`
- 支持页：`https://utilivera.com/support/`

当前冻结 `utilivera-site/static-dist` 中前两个 Capture 路由均不存在，虽已有 `app/capture-product.tsx` 开发源，但不能把源码存在误写为生产部署完成。

**验收标准：**先部署两个 HTTPS 200 页面；release 页展示 Windows/.NET 要求、签名后最终 installer bytes/SHA、审计结论和准确的公开下载状态；验证安装后 Publisher/Support/Updates 链接指向正确页面。在签名前可部署无二进制预发布页，但不得提供当前未签名包或 SoftwareApplication `Offer`/download URL。

## 9. 非阻断 P2

### P2-1：默认权限/安装范围矩阵未覆盖

Inno 使用 `PrivilegesRequired=lowest`，同时允许 dialog/commandline 覆盖权限；现有测试都通过 `/DIR=` 安装到临时目录，没有分别验证标准用户默认路径与管理员覆盖后的注册表、开始菜单和卸载所有权。

**验收：**在标准用户默认模式和管理员 override 模式各跑一次安装/卸载，断言实际目录、HKCU/HKLM uninstall key、当前/公共开始菜单位置和清理结果。

### P2-2：可选桌面快捷方式路径未覆盖

`desktopicon` 默认不勾选，现有测试未通过 `/TASKS=desktopicon` 验证桌面链接创建与卸载删除。

**验收：**增加选中桌面任务的 install/uninstall 矩阵并断言链接目标、WorkingDir 与卸载后无残留。

### P2-3：同版 repair 不能替代跨版本升级

当前固定 AppId、`UsePreviousAppDir` 和同版覆盖证明基础 repair，但没有旧正式版本可执行 N-1→0.6.0 的文件淘汰、设置/项目保留与卸载所有权验证。

**验收：**保留首个签名版本，在下一版本执行真实跨版本升级与降级策略测试，断言旧文件删除、用户数据保留和最终卸载干净。

### P2-4：用户数据保留说明主要存在于内部 evidence

保留策略合理，但当前 README 未向最终用户清楚列出 `%LOCALAPPDATA%\UtiliVera\Capture` 的保留内容和手动清理步骤。

**验收：**在安装后的 README、支持页或卸载说明中公开保留原因、路径和安全删除步骤，并由自动测试断言该说明随包可达。

## 10. 门禁摘要

| 门禁 | 结果 |
|---|---|
| EXE/installer bytes、SHA、版本 | PASS |
| 258/258 manifest 独立复算 | PASS（0 mismatch） |
| 安装后逐文件嵌入验证 | PASS |
| .NET 4.8 功能 gate | PASS（源码） |
| .NET 失败路径 10 语言/负向测试 | **内部 P1** |
| 10 语言成功安装/卸载 | PASS |
| 13 份持久日志 | PASS |
| 静默安装/repair/功能 smoke/卸载 | PASS |
| 安装目录/registry/开始菜单主要残留 | PASS |
| 产品与完整第三方许可 | PASS |
| 10/10 deterministic build | PASS |
| Capture 产品/版本 URL | **外部 P1，未部署** |
| 安装器与主 EXE 签名 | **外部 P1，BLOCKED_NOT_SIGNED** |

## 最终判定

**UtiliVera Capture 0.6.0 安装器 Round 1 未通过内部完整门禁，也未获正式公开发布批准。** Builder 应先关闭 `.NET 4.8` 阻断路径的 10 语言与负向测试 P1，再由同一独立审核员复审。即使内部工程随后 PASS，未签名和未部署 URL 仍分别阻断正式公开下载；只有三个 P1 全部按可测标准关闭后，才能考虑公开发行和启动 Capture 独立的 30 天 1,000 有效下载计时。
