Add validated OTA candidate publishing and fix 1.1.2 dependency failure

This commit is contained in:
2026-09-27 19:00:20 +08:00
parent 98eadc5c8b
commit f80c4d9938
26 changed files with 571 additions and 25 deletions
@@ -102,6 +102,12 @@ node --test @($tests.FullName)
`TEST-RELEASE-VERSION` 交替模拟 OTA、镜像、同一代码连续导出两种产物、构建失败、已有目录、并发锁和历史导出 IMG 被删除。OTA 按已登记节点推进;IMG 不使用 OTA 跳转门禁,但新候选必须严格高于当前版本。`image --candidate-output` 只能写正式目录外且不得改变 `VERSION`、发布记录或正式目录;`image --validated-candidate --validation-report` 只接受下一补丁、摘要一致、字段严格且全部门槛为真的无秘密实卡报告,重建期望 bundle 并复核真实 IMG 后才原字节晋升。候选后源码变化、报告多余字段、摘要错误、已有版本、并发、复制或记录写入失败均须保持版本、记录和正式目录字节不变。另行覆盖用户明确授权的 `image --repair-current` 原有同版本修复语义。
`TEST-OTA-LOCAL`/`TEST-RELEASE-VERSION` 增加 `DEPLOY-OTA-OFFLINE-CLOSURE` 与 `DEPLOY-OTA-CANDIDATE`:缺少直接依赖、固定版本不符、wheel 未列入摘要清单时,候选导出须在发布前拒绝;从候选包实际载荷解出软件与 wheelhouse,用目标 Python/AArch64 标签执行 `pip --no-index --dry-run --ignore-installed --only-binary=:all:`,并在板端隔离 venv 完成无网络安装。新 OTA 候选不占版本;晋升仅接受下一补丁、包字节与报告摘要相同、源码与离线材料未变化、真实安装及恢复均通过的报告。拒绝篡改包、过期源码、报告字段错误和发布中断,核对正式包与试装候选逐字节一致。1.1.1 可直接升级到 1.1.3,1.1.2 标记不可用但原包保留。
隔离复制验收须从候选包的 `software/` 单独运行完整 pytest;设备侧共享协议黄金向量应在 `tests/fixtures/` 随包携带。本机有移动工程时再对照其向量逐字节核验,OTA/板端不得因移动工程目录缺席而跳过设备端协议测试。
历史排障经验:电脑端测试工具的依赖只写入其独立环境,不写入设备 `requirements-dev.txt`;发布前从候选包实际载荷在板端隔离 venv 执行 `pip install --no-index`,并确认完整 pytest 通过。实机 OTA 后 `kernel-recovery.json` 的启动时间和启动标识可能更新,用户配置与资源应分别核对;恢复原版本时程序、持久数据和组件文件按备份字节复核。旧失败留下的 OTA 一次性 unit 可由 `failed` 变为禁用的 `inactive`,主服务及 FRP、蓝牙的启停状态仍须与备份一致。
`TEST-IMAGE-LOCAL` 校验官方 IMG 摘要在导出前后不变;独立读取 MBR、FAT16、rootfs 离线 bundle、软件版本和全部 SHA-256。镜像元数据必须严格为 v3,记录应用载荷 rootfs 路径、压缩字节数和摘要,以及已登记内核 release、压缩/展开字节数、摘要、FAT 安装预算和 `32 MiB` 安全余量;FAT 必须不存在 `MSCBOOT.TGZ`。预编译载荷逐项覆盖外层/内部摘要、3,048 个模块普通文件、五个 boot 文件、固定 release/commit、确定性 gzip、路径穿越、符号链接、特殊文件和损坏元数据。隔离假根验证应用与内核载荷共同写入、读回、既有目标拒绝及“两类压缩载荷 + 256 MiB”空间门槛;合成 FAT 分别覆盖空间通过、边界和不足,预算按簇计入五个 boot 文件、受管/原始/临时启动脚本与状态文件,并确认不足发生在任何候选 boot 文件写入前。Linux 上再只读挂载真实复制件根分区,逐字节比对两类载荷和 FAT 元数据,并确认 `matrix-image-firstboot.service` 与 `ssh.service` 均已启用、受管 sshd 配置逐字匹配、一次性程序指向 FAT 分区且排序早于 SSH 和普通启动脚本。根分区还必须包含 `sshd`、`sudo` 和 `visudo`,SSH 不得被 mask。以 `BASE_IMAGE_PACKAGES.tsv` 为基准解析 FFmpeg、libheif 和 Python venv 的全部直接/传递 Debian 依赖;删除任意仅由闭包提供的包、根包、基准清单、内核依赖或摘要条目时,构建必须在复制正式镜像前失败。导出入口必须在 `python3 -S` 下完成参数解析,不得因 Pillow 或 FontTools 未安装而在发布锁前退出。静态回归必须确认首启写入网络配置并重启 NetworkManager 后直接进入部署,不得循环调用 `nmcli connection up`、等待 SSID/DHCP 或以默认路由缺失退出;`DEFER_SERVICE_START=1` 的全新安装和同版本恢复均使用不要求默认路由的 `dedicated_host.py check --service`,普通部署的严格检查仍要求默认路由。离线完成状态必须固定、无凭据并明确安装成功和 WiFi 未连接。首启只启用控制服务,SSH 也只能 `enable`、不能在具有 `Before=` 排序的 oneshot 内 `start` 或 `enable --now`;账户必须显式加入 `sudo` 组,sudoers 临时文件先经 `visudo` 校验再原子安装,实际 sshd 策略必须经 `sshd -t/-T` 校验。同版本中断恢复必须拒绝版本或安装文件不完整的 `/opt`。破坏活动配置槽必须回退旧槽,两个槽都损坏、产品错误、未知 schema、非法账户/WiFi/IPv4 均拒绝。编辑器覆盖打开、密码遮挡、修改原包确认、另存为不改原包和另存后自动重开;中文、空格及长路径必须生成无 BOM UTF-8 规范摘要并由独立 `Get-FileHash` 复核,摘要长度、十六进制、分隔符、多行、文件名或内容错误以及旧版中文名变成 `?` 的摘要均拒绝。保留名、错误扩展名、同路径、既有 IMG、孤立同名摘要和不可写目录必须在修改前拒绝且不留半成品。主窗口、密码输入框和全部应用内提示在 100%、150%、200% 缩放及约 1280×720、1920×1080、4K 工作区完整可达,跨不同 DPI 显示器或改变分辨率后不得裁切;低分辨率允许滚动。镜像扫描不得包含项目凭据、当前设备数据、SSH 主机密钥、NetworkManager 连接、缓存或编译输出。
`TEST-IMAGE-LOCAL` 的编辑器回归必须直接运行 Python/PySide6 源码单元测试,并将最终 Windows 10/11 x64 单 EXE 单独复制到隔离临时目录,在不依赖源码目录、Python、.NET、Qt 或外部 DLL 的环境中重复 `--validate` 与 `--apply`。同一合成 FAT16 镜像还必须由主工程 `image_config.py` 交叉读取,并覆盖非活动槽更新、活动槽损坏回退和失败不留新 IMG/摘要/临时文件。GUI 人工验收继续覆盖单 IMG 拖放、密码遮挡、确认流程、另存后自动重开、进度响应以及 100%/150%/200% DPI、1280×720、1080p、4K 和跨显示器变化。macOS 只验证源码和构建说明完整,未在 macOS 实际构建时不得写成 macOS 产物通过。