feat(update): add verifiable release manifest

This commit is contained in:
chengma
2026-07-13 11:58:05 +08:00
parent d4a3df4df0
commit 567d4e7b68
7 changed files with 281 additions and 17 deletions
+8
View File
@@ -498,6 +498,7 @@ cmshopee/
│ ├── cdp.py # CDP 底座(由根目录 cdp.py 迁入)
│ ├── appconfig.py / db.py / excel.py / config.py / accounts.py / chrome.py
│ ├── editor.py / ai.py / prompts.py / gui.py / workers.py
│ ├── release_manifest.py # 发布包文件清单、zip哈希与服务端元数据模板
├── main.py # GUI 启动入口:from app.gui import main
├── shopee待处理任务模板.xlsx # 标准空 Excel 模板,可提交;业务填写后的副本不提交
├── data/ # 用户本地数据根(整体 gitignore;打包更新时保留)
@@ -520,6 +521,13 @@ cmshopee/
## 十、架构纪律
### 10.1 发布与自动升级边界
- `app/version.py` 是应用版本唯一来源;`app/release_manifest.py` 生成 `package-manifest.json` 和 `release-metadata.json`,构建脚本不得自行维护另一套 hash 或路径规则。
- 发布包格式固定为 `cmshopee-portable-v1`,入口为 `cmshopee.exe`,程序依赖集中在 `_internal/`。manifest 覆盖除自身外的所有程序文件,并记录规范化相对路径、字节数和 SHA-256。
- 发布包只能包含程序根项目,`data/` 和 `.cmshopee-update/` 永远在替换边界之外。第一阶段预留签名字段,但 SHA-256 只负责传输完整性,不等同于发布者身份认证。
- T-615 只提供可验证发布契约;启动门禁仍保持 T-544 的人工下载行为,直到后续下载、独立更新器、事务替换和失败熔断任务全部接入。
- CDP 交互事实变化同步第七节。
- 正式代码只放 `app/` 包;根目录只保留 `main.py`、配置/数据目录、文档和原型目录,不新增正式业务模块。
- `app` 包内模块优先用相对导入(如 `from .cdp import CDP`);根入口 `main.py` 用 `from app.gui import main`。
+10 -10
View File
@@ -1,6 +1,6 @@
# 打包与分发
> T-524 目标:先把当前 Windows 桌面工具打成免安装 onedir `.exe`,方便第一版交付使用。暂不做自动更新器、安装器、增量补丁或在线升级。
> 当前发布仍是免安装 onedir;T-615 已增加自动升级所需的机器可验证清单和发布元数据,但尚不下载或替换客户端程序。
## 一、打包前提
@@ -53,7 +53,7 @@ cmshopee\
## 三、版本号与发布目录
参考 `D:\chengma\cmbot` 的打包方式,版本控制采用“单一版本源 + 发布目录带版本号”的轻量方案,暂不引入启动器、自动更新或 manifest。
版本控制采用“单一版本源 + 发布目录带版本号 + 可验证 manifest”的方案。
### 3.1 单一版本源
@@ -86,7 +86,9 @@ release\
<PyInstaller 依赖文件和依赖目录>
version.txt
README.txt
package-manifest.json
蝦皮圈優化助手0.1.0.zip
release-metadata.json
```
说明:
@@ -96,6 +98,8 @@ release\
- `release\蝦皮圈優化助手<APP_VERSION>.zip` 是交付给用户的便携压缩包。
- `version.txt` 使用 ASCII/UTF-8 无 BOM 写入 `APP_VERSION`,用于人工排查和未来更新机制读取。
- `README.txt` 用中文写明启动方式、不要放入 `Program Files`、保留 `data\`、升级时覆盖程序文件但不覆盖 `data\`。
- `package-manifest.json` 记录包格式、版本、入口、更新器协议、允许替换根项目,以及除清单自身外每个程序文件的规范化路径、字节数和 SHA-256。
- `release-metadata.json` 记录整个 zip 的准确字节数和 SHA-256,并提供服务端发布字段模板;它不放进 zip。
当前 PyInstaller 6.11.1 的 onedir 为集中依赖结构,所以 `release\蝦皮圈優化助手<APP_VERSION>\` 必须包含 `cmshopee.exe` 和 `_internal\`,不得只复制单个 exe。
@@ -104,7 +108,7 @@ release\
1. 修改 `app/version.py` 中的 `APP_VERSION`。
2. 运行语法检查和单元测试。
3. 运行 `powershell -ExecutionPolicy Bypass -File scripts\build_exe.ps1`。
4. 检查 `release\蝦皮圈優化助手<APP_VERSION>\version.txt`、GUI 标题栏版本、压缩包文件名三者一致。
4. 检查 `version.txt`、GUI 标题栏、`package-manifest.json`、压缩包文件名和 `release-metadata.json` 的版本一致。
5. 在无 Python 环境的 Windows 10/11 机器上解压 `蝦皮圈優化助手<APP_VERSION>.zip` 并启动验证。
正式发布构建固定使用 Python 3.10。源码在 Python 3.7.9 上曾验证可运行,但发布包不再以 3.7.9 作为打包基线;脚本会直接调用 `py -3.10` 并校验返回版本必须是 `3.10.x`,避免同一个 `APP_VERSION` 在不同 Python 版本下打出不可比对的包。CI 仍可继续使用 Python 3.11 做自动测试。
@@ -166,15 +170,11 @@ T-544 第一版目标是**启动时检查是否必须升级**,但仍不做自
原因:Windows 下运行中的 `cmshopee.exe` 和 PyInstaller onedir 依赖目录很容易出现文件占用、半覆盖失败、权限不足或杀毒拦截。第一版只做“强制提示 + 下载新版 + 用户手动覆盖”,和当前便携包更新方式一致。
### 3.5 暂不引入自动覆盖升级
### 3.5 自动升级发布基础(T-615)
本阶段不迁移 `cmbot` 的 `Launcher.exe`、`manifest.json`、SHA-256 下载校验、自动替换程序目录或增量补丁。原因:
`app/release_manifest.py` 是发布清单与 zip 元数据的唯一生成逻辑。构建脚本按以下顺序执行:组装 release 目录、拒绝用户数据和未知根项目、生成 `package-manifest.json`、压缩 zip、计算 zip hash/大小、生成 `release-metadata.json`。允许的根项目仅为 `cmshopee.exe`、`_internal/`、`version.txt`、`README.txt`、清单和后续独立更新器;明确禁止 `data/` 与 `.cmshopee-update/`。
- 当前用户已验证“拷贝发布目录到无 Python 环境运行”的第一版交付路径。
- `cmshopee` 刚完成 `data\` 数据隔离,先把手动发版和版本号一致性做稳。
- 自动更新需要安装根可写、下载暂存、目录切换、回滚和安全校验,属于独立后续任务,不能混入当前打包版本号控制。
后续如果要做真正自动覆盖升级,再另起任务,参考 `cmbot` 的 `Launcher.exe + app\ + manifest.json + sha256 + version.txt` 设计。
T-615 不改变客户端行为:T-544 仍只打开浏览器下载。客户端下载、解压校验、独立进程替换、回滚和重启分别由 T-616 至 T-619 实现。清单预留签名字段,但当前只验证完整性,不宣称已验证发布者身份。
## 四、绝不打包的本地数据
+4 -2
View File
@@ -3,7 +3,7 @@ id: T-615
title: 自动升级发布契约与可验证发布清单
phase: 8
deps: [T-540, T-544]
status: TODO
status: DONE
created: 2026-07-13
---
@@ -43,4 +43,6 @@ created: 2026-07-13
## 执行记录
(完成后记录实现、验证命令与结果。)
- 2026-07-13:新增 `app/release_manifest.py`,统一生成程序文件清单与zip发布元数据;构建脚本在压缩前生成manifest、压缩后生成准确hash和大小。
- 2026-07-13:发布目录仅允许程序根项目,拒绝 `data/`、`.cmshopee-update/`、未知根项目、版本不一致、重复路径和符号链接;同步更新发布契约、打包文档与架构边界。
- 2026-07-13:干净worktree验证通过:`python -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`py -3.10 -m unittest discover -s tests`(394项)、`git diff --check`。
+16 -4
View File
@@ -1,7 +1,7 @@
# 版本检查接口契约(启动强制升级)
> 客户端在启动时请求版本接口,判断是否需要**强制升级**。本文是**服务端响应格式的权威契约**——字段以 `app/update_check.py` 的实际读取逻辑为准,服务端按此返回,避免格式漂移。
> 客户端逻辑已由 T-544 实现,本文不要求改客户端代码;发强制版时按「发版约定」配置服务端响应即可。
> T-544 已实现启动检查与浏览器下载引导;T-615 起增加自动安装所需的发布契约。T-615 只生成可验证发布包,客户端下载与替换由后续任务实现。
## 一、接口
@@ -22,8 +22,12 @@
| `version` / `latest_version` | string | 最新版本号。客户端取 `payload.latest_version` 或 `release.version`。**`latest_version` 与 `min_supported_version` 至少要有一个**,否则客户端判为"接口缺字段"、按失败放行 |
| `force_update` | bool | 是否强制升级。`true`/`1`/`yes`/`y`/`on`(大小写不敏感)都识别为真 |
| `min_supported_version` | string | 最低支持版本;本地低于它一律强制 |
| `download_url` | string(URL) | 「下载新版」按钮打开的地址(用系统浏览器打开)|
| `sha256` | string | 安装包校验值;**第一版不校验,可留空** |
| `download_url` | string(URL) | 下载地址;自动安装时必须是 HTTPS |
| `sha256` | string | zip 的 SHA-256;自动安装时必须是 64 位十六进制且不可为空 |
| `size_bytes` | integer | zip 的准确字节数;自动安装时必须大于 0 |
| `package_format` | string | 自动安装固定为 `cmshopee-portable-v1` |
| `updater_protocol` | integer | 发布包要求的更新器协议版本,当前为 `1` |
| `min_updater_protocol` | integer | 可安装此包的最低更新器协议,当前为 `1` |
| `release_notes` / `message` | string | 升级说明,显示在强制升级弹窗里。客户端取 `message` 或 `release_notes` |
版本号比较用**语义化数字段比较**(`compare_versions`,逐段比数字),不是字符串字典序:`0.1.10 > 0.1.9`。
@@ -45,6 +49,8 @@
## 五、发版约定(服务端据此控制)
自动安装使用的全部字段必须放在同一个 `release` 对象内,不得把版本取自一个对象、hash 取自另一个对象。构建脚本生成的 `release/release-metadata.json` 是服务端录入模板;发布人员只补 HTTPS `download_url`、强制策略和中文发布说明,不得手工改写 hash、大小、包格式或协议版本。
| 想要的效果 | 服务端返回 |
| --- | --- |
| **强制升到最新**(方案 A) | `release.force_update: true` + `release.version` 高于要淘汰的客户端版本 |
@@ -61,7 +67,11 @@
"release": {
"version": "0.1.1",
"download_url": "https://cm.833729.com/media/downloads/%E8%9D%A6%E7%9A%AE%E5%9C%88%E5%84%AA%E5%8C%96%E5%8A%A9%E6%89%8B0.1.1.zip",
"sha256": "",
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"size_bytes": 123456789,
"package_format": "cmshopee-portable-v1",
"updater_protocol": 1,
"min_updater_protocol": 1,
"release_notes": "优化了ai模块的生图的功能",
"published_at": "2026-07-08T14:30:26.935549+08:00",
"force_update": true
@@ -104,3 +114,5 @@
- 服务端返回 `force_update`/`min_supported_version` 属**本仓库外的服务端配置**;客户端代码(`app/update_check.py`/`app/version.py`/启动流程)已按本契约实现,**发强制版不需要改客户端**。
- `download_url` 里的中文可用 URL 编码(如 `%E8%9D%A6...`),系统浏览器能正确打开。
- 若将来要"非强制也温和提示(可跳过、不阻断)",需在客户端加一个非强制分支,另立任务。
- 空 `sha256` 只兼容 T-544 的人工下载引导,绝不能进入自动安装。自动安装还必须同时校验 HTTPS、`size_bytes`、包格式和更新器协议。
- `manifest_signature` 与 `signature_algorithm` 是预留字段;当前未启用数字签名,不能将 SHA-256 描述为发布者身份认证。