17 KiB
17 KiB
CTMS Desktop Release Stabilization Checklist
状态: active
适用范围: Web 与 macOS Desktop 统一客户端发布
最后更新: 2026-07-02
本清单用于第一、二阶段桌面端能力完成后的准发布稳定化。它不引入离线登录、本地业务数据存储、内嵌后端服务或离线同步。
1. 发布链路门禁
发布候选提交必须从同一 Git 提交构建 Web 与 Desktop 制品,并完成以下检查:
cd frontend
npm ci
npm run version:check
npm run release:env:check
npm run runtime:check
npm run desktop:release:check
npm run ui:contract
npm run type-check
npm run test:unit
npm run build
npm run desktop:build:app
正式发布还必须确认:
frontend/package.json、package-lock.json、Tauri 配置、Cargo manifest/lock 版本一致。VITE_BUILD_CHANNEL=release和VITE_BUILD_COMMIT=<release tag commit>由 CI 注入,且npm run release:env:check通过。- 在正式 release tag 和签名环境中执行
npm run desktop:release-readiness:check,确认 tag、构建元数据、签名/公证变量、updater 私钥和生产 artifact HTTPS 基址齐备。 - macOS app 已签名和公证。
- updater
.sig使用组织 CI secret 或密钥库中的私钥生成,私钥未进入仓库。 - 设置
TAURI_SIGNING_PRIVATE_KEY、TAURI_SIGNING_PRIVATE_KEY_PASSWORD和 Apple 签名/公证变量后,以REQUIRE_DESKTOP_SIGNING=true再次执行npm run release:env:check,随后执行npm run desktop:build:macos-release -- --ci。 - 正式 updater feed 先执行
npm run desktop:update-feed:create -- --artifact <CTMS.app.tar.gz> --base-url <versioned-https-artifact-prefix> --output-dir <release-dir>生成latest.json与SHA256SUMS.txt。 - 正式 updater feed 执行
npm run desktop:update-feed:check -- --feed <release-dir>/latest.json --artifacts-dir <release-dir>,并确认 checksum manifest、updater artifact、.sig和latest.json均通过校验。 - 不可变制品先上传,
latest.json最后原子替换;若 feed 校验未通过,不替换线上latest.json。 - Web 与 Desktop 制品记录同一产品版本、Git 标签和完整提交 SHA。
2. 安全边界复审
自动门禁 npm run desktop:release:check 覆盖以下静态约束:
- Tauri bundle 启用
app、dmg和 updater artifacts。 - updater public key 已配置。
- CSP 禁止 wildcard source、
unsafe-eval、宽泛 HTTP API 访问和object-src。 - Tauri capability 不包含 shell 权限、持久文件系统 scope 或宽泛目录读写。
- 文件系统与 opener scope 只允许
$TEMP/ctms-desktop/**。 - 单实例插件先于其他桌面插件注册。
- Tauri command 白名单仅包含凭据和更新命令。
- 前端源码不通过 query string 传递 token。
ctms_token只允许由secureSessionStorage处理。- 登录表单密码不写入
localStorage或sessionStorage;Web 端只使用浏览器凭据管理能力,Desktop 端只使用系统凭据库。 - 系统通知只能通过
frontend/src/runtime/notifications.ts发送,标题和正文保持通用。 - 通知 capability 只暴露权限查询、权限请求和发送通知,不使用
notification:default。 - opener capability 只允许打开
$TEMP/ctms-desktop/**下的临时文件,不开放 URL 或 reveal 权限。 - updater capability 不直接暴露给 WebView,自动更新只走受控 Tauri command。
- 更新弹窗 release notes 过滤 URL、token 查询参数和 Authorization/Bearer 形态文本。
- CI release 候选 workflow 包含 version/runtime/desktop/ui/type/unit/build/desktop app smoke 门禁。
- signed macOS release candidate workflow 只允许从
vX.Y.Ztag 运行,并包含签名环境检查、Universal macOS 构建、update feed 生成、checksum 校验和 verified release directory 上传。
人工复审还必须确认:
- token 不出现在 URL、日志、系统通知正文、下载链接或持久化业务缓存中。
- 密码不出现在 URL、日志、系统通知正文、诊断信息或明文浏览器存储中。
- 桌面端通知正文只显示通用内容,不包含项目、文件或版本详情。
- 服务端权限、审计和业务数据持久化仍由 FastAPI 后端裁决。
- Web 运行时不直接导入 Tauri API。
3. 端到端回归矩阵
| 场景 | Web | macOS Desktop | 预期 |
|---|---|---|---|
| 登录与项目恢复 | 必测 | 必测 | 登录成功后恢复可访问项目;401 后重新登录 |
| 记住密码 | 必测 | 必测 | Web 使用浏览器凭据管理/自动填充;Desktop 使用系统凭据库;未勾选时不继续写入保存密码 |
| 30 天免登录 | 不适用 | 必测 | 关闭并重启 App 后复用系统凭据库中的后端在线会话;超过 30 天或 /me 校验失败后重新登录 |
| 服务器地址未配置 | 不适用 | 必测 | 自动进入服务器设置,不进入业务页 |
| 服务器地址切换 | 不适用 | 必测 | 清除当前会话和项目上下文,要求重新登录 |
| 服务端不可达 | 必测 | 必测 | 显示可恢复错误,不进入离线模式 |
| 附件上传 | 必测 | 必测 | Web 使用浏览器文件选择,Desktop 使用原生选择 |
| 附件下载/保存/打开 | 必测 | 必测 | 使用 Authorization header;无 ?token= |
| 临时文件清理 | 不适用 | 必测 | 启动时清理 $TEMP/ctms-desktop/** |
| 系统通知开启 | 不适用 | 必测 | 用户主动开启后请求 OS 权限并创建订阅 |
| 系统通知拒绝 | 不适用 | 必测 | 开关回退,提示系统权限未开启 |
| 通知领取与 ack | 不适用 | 必测 | 显示成功后 ack;失败等待租约重试 |
| 单实例重复启动 | 不适用 | 必测 | 恢复、显示并聚焦主窗口 |
| 自动更新检查 | 不适用 | 必测 | release 通道按当前 CTMS origin 派生清单 |
| 更新稍后提醒 | 不适用 | 必测 | 同版本 24 小时内不重复提示 |
| 更新安装失败 | 不适用 | 必测 | 不打断业务录入,显示可排障错误 |
4. 桌面体验验收
- 登录页显示当前桌面服务器地址,长 URL 不撑破登录面板。
- 30 天免登录仍只保存系统凭据库会话记录,不把 token 写入 URL、日志、通知正文或业务缓存。
- 记住密码与 30 天免登录使用独立凭据记录;服务器切换后不复用旧服务器保存的密码。
- 服务器设置页显示当前服务器、连接检查状态、HTTP 错误、超时和网络失败原因。
- 个人中心显示客户端类型、版本、平台、构建通道、提交、服务器和能力状态。
- 个人中心可复制诊断信息,内容不包含 token 或业务敏感数据。
- 通知开关显示 OS 权限状态。
- 手动检查更新能反馈“已是最新版本”、未启用更新或检查失败。
- 关键弹窗、表单、按钮在最小窗口尺寸
1180x760下不重叠、不溢出。 - 更新弹窗只显示版本、发布日期和通用 release notes,不展示 token、下载链接或业务详情。
5. 不允许项
- 不实现离线登录、离线浏览、离线队列或离线同步。
- 不在桌面端保存 CTMS 业务数据副本。
- 不内嵌 FastAPI、PostgreSQL、SQLite 或本地业务 API 镜像。
- 不绕过后端做本地权限裁决或本地审计回放。
6. 2026-07-01 收尾验证记录
本轮收尾验证在 /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop 的 detached HEAD c923f887 上执行,包含当前工作区文档与 CI 门禁调整。
已通过的自动门禁:
cd frontend && npm run version:checkcd frontend && npm run release:env:checkcd frontend && npm run runtime:checkcd frontend && npm run desktop:release:checkcd frontend && npm run ui:contractcd frontend && npm run type-checkcd frontend && npm run test:unitcd frontend && npm run buildcd frontend && npm run desktop:build:appcd frontend && node --check scripts/verify-desktop-update-feed.mjs
验证结论:
- Tauri 运行时边界、release 静态安全门禁、构建元数据预检、版本一致性和 UI 合约均通过。
- Web 生产构建和未签名 macOS
.appsmoke 构建均可重复执行。 - 当前 CI 已补齐
npm run release:env:check和npm run ui:contract,tag 构建会将VITE_BUILD_CHANNEL规范为release并校验 tag 与版本号一致。 - updater feed 校验脚本已完成语法检查;正式
latest.json需要在签名 updater artifacts 生成后执行实物校验。
仍需正式发布前人工确认:
- macOS 签名、公证、Apple Developer 凭据和组织 updater 私钥。
- 签名后的 updater artifacts、
.sig、checksum manifest 和latest.json在真实发布目录内通过npm run desktop:update-feed:check。 - 不可变制品上传完成后,再原子替换线上
latest.json。 - Desktop 端到端人工回归矩阵、最小窗口体验验收和系统通知/自动更新真实环境验证。
7. 2026-07-02 发布稳定化推进记录
本次推进补齐了发布链路自动化,不改变桌面端产品边界:
- 新增
npm run desktop:build:macos-release,封装 Universal macOSapp/dmgrelease candidate 构建命令。 - 新增
npm run desktop:update-feed:create,从签名 updater artifact 和.sig生成latest.json、复制发布目录文件并生成SHA256SUMS.txt。 npm run desktop:update-feed:check在传入--artifacts-dir时要求并校验SHA256SUMS.txt。- 新增
npm run desktop:release-readiness:check,在正式签名候选构建前检查 release tag、构建元数据、签名/公证变量、updater 私钥和生产 artifact HTTPS 基址。 - 新增
.github/workflows/desktop-release-candidate.yml,在 release tag 上执行签名候选构建、feed 生成、feed 校验并上传 verified release directory。 npm run desktop:release:check已检查上述脚本和 workflow,避免发布链路回退。
仍未自动完成、正式发布前必须人工确认:
- Apple Developer 凭据、证书、签名身份、公证结果和组织 updater 私钥。
- 生产下载源的不可变制品上传和线上
latest.json原子替换。 - 真实环境下的自动更新安装、系统通知、单实例和完整人工回归。
8. 2026-07-02 端到端回归优化记录
本轮端到端优化仍保持在线桌面客户端边界,不引入离线、本地业务存储或本地权限裁决。
已完成的自动化收口:
- 服务器地址切换时,桌面设置页调用
auth.logout({ rememberCurrentStudy: false }),避免退出时把旧服务器项目记入当前用户的最近项目;随后继续清除当前项目上下文。 - 系统偏好连接页与独立服务器设置页保持同一切换服务器语义,切换时不记忆旧服务器项目并清除当前项目上下文。
- 系统通知轮询在部分通知显示失败或系统通知未实际发起时,先 ack 已成功发起系统通知的通知,再让失败项通过租约重试,贴合“显示成功后 ack;失败等待重试”的回归预期。
- 自动更新管理器新增稍后提醒 24 小时抑制、安装失败可重试、检查失败不打断业务和未启用更新状态的单元覆盖。
- 附件 API 新增 blob 下载、multipart 上传和删除端点单元覆盖,确保下载凭据继续由 axios Authorization header 承载而不是进入 URL。
- 文件任务反馈 helper 新增选择、保存、取消保存和打开的单元覆盖,约束桌面保存/打开继续走
frontend/src/runtime/适配层。 - Keychain/凭据库会话新增旧浏览器 token 迁移、未配置服务器不读取凭据、本地 30 天上限、服务器切换删除旧服务器凭据,以及恢复 token 必须先经
/me校验的单元覆盖。 - 桌面发布门禁新增单实例重复启动处理校验,要求重复启动时恢复、显示并聚焦
main窗口。 - 会话刷新后的跨窗口 token 更新不再写入
localStoragefallback,只通过内存态 BroadcastChannel 通知,避免 token 进入明文广播缓存。 desktop:release:check新增 session broadcast 静态门禁,防止TOKEN_UPDATEDpayload 回退写入localStorage。- 新增相关单元测试覆盖服务器切换不记忆旧项目、通知权限未授权不领取、部分通知失败时只 ack 成功项、系统通知未发起时不 ack、自动更新失败恢复路径、附件文件流契约、30 天在线会话恢复边界、单实例恢复行为和 token 广播存储边界。
仍需人工或真实环境验证:
- Keychain/凭据库 30 天在线会话恢复。
- 原生附件上传、下载、保存和打开。
- 系统通知拒绝路径的 OS 级交互。
- 单实例重复启动聚焦主窗口。
- 签名 release 构建下的自动更新 feed、验签、安装和重启实物流。
9. 2026-07-02 安全边界复审记录
本轮安全复审在端到端自动化收口之后推进,不改变桌面端在线客户端边界。
已完成的安全边界收口:
- Tauri notification capability 从
notification:default收敛为notification:allow-is-permission-granted、notification:allow-request-permission和notification:allow-notify。 desktop:release:check新增 capability 最小化约束,拒绝notification:default、opener URL/reveal 权限和 WebView 直连 updater 权限。desktop:release:check将 token URL 检查扩展到token与access_token查询参数,并扩大日志敏感词检查到token、access_token、authorization和bearer。- 更新弹窗 release notes 增加清理逻辑,过滤 URL、token 查询参数、
access_token、Authorization和Bearer形态文本,避免 feed 内容把下载链接或凭据样式文本带入 UI。 - 凭据库 Rust 单测新增带凭据 server origin 拒绝,以及 Keychain/Credential Manager account 不暴露原始服务器 origin 的覆盖。
仍需人工复审确认:
- 真实生产 release notes 内容保持通用,不写入项目、文件、下载链接或敏感业务详情。
- 正式签名、公证和 updater feed 环境继续使用组织 secret,不在日志、artifact 或配置中泄露私钥材料。
10. 2026-07-02 桌面体验收口记录
本轮体验收口聚焦登录、服务器设置、个人中心诊断、系统偏好和最小窗口布局稳定性,不改变业务能力边界。
已完成的体验收口:
- 个人中心新增只读客户端诊断信息,展示客户端类型、版本、平台、构建通道、提交、服务器和能力状态,并支持复制诊断信息。
- 登录页在桌面最小窗口附近收紧左右分栏 padding 和卡片宽度,长服务器地址继续在登录面板内换行,不撑破布局。
- 服务器设置页增加面板内滚动和健康检查 URL 换行约束,避免
1180x760下长 URL 或错误信息溢出。 - 系统偏好通知/更新控制区允许换行,长状态说明使用
overflow-wrap,避免按钮和权限状态标签在窄视口重叠。 - 个人中心对话框内容区改为内部滚动,诊断值使用强制换行,避免新增诊断信息后超过最小窗口高度。
- 通知权限运行时改为优先读取 WebView
Notification.permission的granted/denied状态;请求权限返回default时保持“待授权”,不再误标为“已拒绝”。 - 系统偏好通知页已移除授权成功态的固定标签文案,开启状态只由开关表达;待授权、已拒绝和不可用状态继续显示提示标签。
- 系统偏好通知页新增“测试通知”命令,完整走
frontend/src/runtime/notifications.ts->@tauri-apps/plugin-notification的系统通知发送链路;测试通知文案为固定通用内容,不包含项目、文件、token 或其他敏感业务信息。 showSystemNotification和测试通知调用会在发送前确认系统通知权限,只有真正发起系统通知时才返回成功;桌面通知轮询据此只 ack 已实际发起系统通知的后端通知。- 真实 macOS
.app已验证系统偏好通知开关可调用系统通知权限并生效。验证截图见/Users/zcc/Library/Application Support/CleanShot/media/media_boKznpjOwt/CleanShot 2026-07-02 at 11.07.52@2x.png。 Layout.desktop.test.ts新增静态契约覆盖个人中心诊断、登录页最小窗口断点、服务器设置滚动和偏好页控制区换行约束。notifications.test.ts新增授权、拒绝、待授权、取消授权请求和测试通知发送链路的单元覆盖。
仍需人工体验验收:
- 在真实 macOS
.app中以1180x760检查登录页、服务器设置、个人中心、系统偏好和更新弹窗无重叠、无横向溢出。 - 在真实系统通知权限拒绝流程中确认权限状态提示、开关回退和错误提示与 OS 状态一致。