fix: tolerate UTF-8 BOM in manifest; sync docs to app/app.old model

#1 BOM: PowerShell Set-Content -Encoding UTF8 writes a BOM that made the in-app
json.loads silently fail (banner never showed even with an update available).
- update_service: decode manifest with utf-8-sig (HTTP + local)
- build.ps1: write manifest.json without BOM (UTF8Encoding $false)
- tests: +2 covering BOM manifests (HTTP + local)

#2 docs: docs/10 §16 status synced to the implemented app/app.old/version.txt +
SHA-256 model (stages 2/3 done + e2e verified); tasks 17.18 updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 10:19:03 +08:00
co-authored by Claude Opus 4.8
parent ba8daaccdd
commit 54e42670f7
5 changed files with 34 additions and 7 deletions
+3 -3
View File
@@ -248,11 +248,11 @@ HTTP 在线更新比内网共享面临更高风险,按以下层次防护:
分阶段落地,每阶段可独立验证:
1. **地基**:数据目录分离(第 5 节)。任何更新方案的前提。✅ 已实现。
2. **只读通知**:启动时读取 `manifest.json` 比对版本,有新版仅提示。🚧 已实现本地文件版——`services/update_service.py`(`check_for_update` / 版本比较,纯逻辑可测)+ 主窗口顶部通知横幅,后台线程检查(不可达不阻塞启动),更新源由 `update_source` 配置。**待补:`check_for_update` 支持 `http(s)://` 源 + Basic Auth**(当前只会 `open()` 本地路径,填 URL 会静默返回 None)。
3. **自动安装**:启动器完整流程(下载 → 校验 → `app` 目录切换 → 启动 → `app.old` 回滚)。🚧 `scripts/update.ps1` 已实现并以假版本目录验证旧版全流程(含降级路径);**当前为 UNC/robocopy + `versions/current.txt` 版,待改为 HTTP + `app/app.old` 目录切换**:用带凭据的 HTTP 下载 zip + SHA-256 校验 + 解压到 `staging\app.new\`,再重命名切换。尚未接入真实安装结构(`build.ps1` 仍产出扁平 onedir,无生成 `app\` 安装布局的步骤)。
2. **只读通知**:启动时读取 `manifest.json` 比对版本,有新版仅提示。✅ 已实现——`services/update_service.py`(`check_for_update` / 版本比较,纯逻辑可测,支持 **`http(s)://` 源 + Basic Auth** 及本地路径;manifest 用 `utf-8-sig` 解码以容忍 BOM)+ 主窗口顶部通知横幅,后台线程检查(不可达不阻塞启动),更新源 / 凭据由 `update_source` / `update_user` / `update_pass` 配置。
3. **自动安装**:启动器完整流程(下载 → 校验 → `app` 目录切换 → 启动 → `app.old` 回滚)。✅ 已实现并端到端验证——`scripts/update.ps1`(HTTP 下载 zip + SHA-256 + 解压 + `app/app.old` 切换);`scripts/build.ps1` 产出 `version.txt` + zip + 写 `manifest.json`(无 BOM)+ 可选发布;`scripts/install_local.ps1` 在 `%LOCALAPPDATA%\CMBot` 铺出 `app/app.old/data/staging` 布局并迁移用户配置。已用本地 HTTP server 假发布包验证「拉清单 → 下载 → 校验 → 切换」全流程通过。**待办**:真实环境端到端实测;接入正式发布流水线。
4. **强制更新与保留策略**:补全 `mandatory` / `min_supported` 与 `app.old` 回滚策略。⛔ 未做。
启动器(`scripts/update.ps1`,HTTP 版目标)要点:
启动器(`scripts/update.ps1`)要点:
- 入口参数 `-InstallRoot`(默认脚本所在目录)、`-NoLaunch`(测试用,只更新不启动)。
- 从 `<InstallRoot>\data\config\app_config.json` 读 `update_source` / `update_user` / `update_pass`,与 stage ② 同源。