11 KiB
发布指南
构建命令
# 推荐:当前平台完整门禁、打包、验证和 SHA-256
./scripts/build.sh
# macOS Apple Silicon 指定版本
./scripts/build.sh v2.1.1 mac-arm64
# Windows x86_64(推荐在 Windows CMD/PowerShell 中执行)
scripts\build.bat v2.1.1 win-x64
# 本地重复构建时缩短门禁;正式发布不要跳过
./scripts/build.sh v2.1.1 mac-arm64 --quick
scripts/build.sh 与 scripts/build.bat 面向 v2.1.x,会检查 Node、npm、Rust target 和五处版本元数据。显式传入不同于当前源码的新版本时,脚本会同步版本文件;它们只负责构建,不会自动创建 tag 或推送远程仓库。安装包和 SHA256SUMS.txt 输出到:
release/v2.1.1/macos-arm64/
release/v2.1.1/windows-x64/
平台安装包必须在目标系统构建和验证。macOS 不能替代 Windows x86_64 实机打包。
Windows 构建环境
建议使用 Windows 10/11 x64,并安装:
- Node.js 18+ 与 npm
- Rust stable 的
x86_64-pc-windows-msvctoolchain - Visual Studio 2022 Build Tools,勾选 Desktop development with C++
- Windows 10/11 SDK
- Microsoft Edge WebView2 Runtime
首次准备:
rustup default stable-x86_64-pc-windows-msvc
rustup target add x86_64-pc-windows-msvc
npm ci
scripts\build.bat v2.1.1 win-x64
默认执行完整门禁;--quick 适合开发期重复构建,正式发布不要使用 --skip-checks。输出位于 release\v2.1.1\windows-x64\。没有代码签名证书时可以生成开发安装包,但 Windows SmartScreen 可能提示未知发布者。
Gitee Release
构建、提交并推送对应 tag 后执行:
# 只检查附件,不访问 Gitee API
./scripts/release.py v2.1.1 --dry-run
# 创建或更新 Release,上传安装包和 SHA256SUMS.txt,并核验远程附件
./scripts/release.py v2.1.1
发布凭据从 GITEE_TOKEN 或 ~/.netrc 的 gitee.com 条目读取,脚本不会输出 Token。脚本只读取 release/v<版本>/ 下的 .dmg、.exe、.msi 和 SHA256SUMS.txt,上传成功后保留本地文件。远程已有同名同大小附件时会跳过;同名但大小不同时停止,避免静默覆盖已发布二进制。
macOS App 位于:
src-tauri/target/release/bundle/macos/OpsXShell.app
指定 aarch64-apple-darwin target 时,产物位于对应 target 的 release/bundle 下。
临时 DMG
Tauri 调用 hdiutil 制作 DMG 时,可能在异常中断后留下:
rw.<进程号>.OpsXShell_<版本>_aarch64.dmg
这些 rw.*.dmg 是可写临时镜像,不是发布包。确认没有正在运行的 Tauri/hdiutil 打包任务后可以删除。正式包没有 rw.<数字>. 前缀。
如果 DMG 脚本报错 resource busy,先检查是否正从临时挂载目录运行 OpsXShell:
hdiutil info
lsof +D /Volumes/<临时卷名>
先正常退出该 OpsXShell 进程,再卸载对应的临时卷并重新构建。不要在应用仍从卷内运行时直接删除 rw.*.dmg。
签名、公证和自动更新(未完成)
当前状态:没有签名凭据,公开包是 ad-hoc / 未签名,未公证,没有自动更新。
没有 APPLE_* / Authenticode 证书、minisign 私钥和 HTTPS 更新源之前,不得在 README、界面、Release 说明或 CI 绿勾上写「已签名」「已公证」「支持自动更新」。tauri.conf.json 的 signingIdentity 现在是 "-";plugins 只有 deep-link,没有 updater。
现有门禁只做「有凭据才验、没凭据就标明开发包」:
REQUIRE_SIGNING=true时,scripts/release-preflight.mjs检查环境变量齐全,scripts/verify-release.mjs拒绝 macOS ad-hoc、要求 Windows AuthenticodeValid。- 未设该变量时,
./scripts/build.sh仍可打开发包,验证只检查架构和体积。 - CI 工作流
.github/workflows/tauri-release.yml已能在 Secrets 齐全时写入src-tauri/tauri.signing.conf.json再构建;本地build.sh还不会生成这份配置,所以本机即使导出了同样的环境变量,也不会走出 ad-hoc。 - 全仓库没有
notarytool/staple。Developer ID 签过但未公证的.app,用户机器上仍会被 Gatekeeper 拦。 scripts/release.py仍提示「右键打开」——这是 ad-hoc 包的权宜说明,正式公证后必须删掉。
下面是有凭据之后的做法。没齐之前不要改 signingIdentity、不要接 updater 插件、不要在设置里放「检查更新」。
1. 凭据(先买/申请,再接线)
| 平台 | 要什么 | 放到哪里 |
|---|---|---|
| macOS | Apple Developer Program;Developer ID Application 证书(.p12);App 专用密码 |
本机环境变量 + GitHub/Gitee Secrets:APPLE_CERTIFICATE(p12 的 base64)、APPLE_CERTIFICATE_PASSWORD、APPLE_SIGNING_IDENTITY(如 Developer ID Application: …)、APPLE_ID、APPLE_PASSWORD、APPLE_TEAM_ID |
| Windows | 代码签名证书(OV/EV PFX) | WINDOWS_CERTIFICATE_BASE64、WINDOWS_CERTIFICATE_PASSWORD |
| 自动更新 | 单独的 minisign 密钥对,与 Apple/Authenticode 不是同一把 | 私钥只进 CI Secrets;公钥写进仓库的 updater 配置 |
Linux 安装包(deb/rpm/AppImage)不走 Apple/Authenticode。自动更新的 .sig 是另一套签名,三平台都要。
src-tauri/tauri.signing.conf.json 由脚本现场生成,必须进 .gitignore,不得提交。
2. 本地与 CI 同源签名
目标:本机 REQUIRE_SIGNING=true ./scripts/build.sh 与 CI 走同一条路径,都能复现同一类签名产物。
build.sh/build.bat在签名变量齐全时,生成tauri.signing.conf.json(macOS 写bundle.macOS.signingIdentity;Windows 写 thumbprint / sha256 / timestamp),再npx tauri build --config src-tauri/tauri.signing.conf.json。- 不要改仓库里的
tauri.conf.json默认"-"——没凭据的开发机构必须还能打 ad-hoc。 REQUIRE_SIGNING=true时verify-release.mjs必须失败于 ad-hoc / 无效 Authenticode;不要为了绿而关校验。- 正式标签才设
REQUIRE_SIGNING=true。日常 PR 构建保持未签名。
3. macOS 公证(notarytool + staple)
签名成功 ≠ 用户能打开。必须公证并钉票:
# 构建并 Developer ID 签名之后
xcrun notarytool submit "$DMG" \
--apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$DMG"
# 若 staple 的是 .app,再重新打 DMG,或对 DMG 再 staple
spctl --assess --type install --verbose "$DMG"
验收(必须在另一台未关 SIP、未关 Gatekeeper 的 Mac上,不要只在构建机看 spctl):
- 下载 DMG,双击打开,拖到「应用程序」,不要右键「打开」、不要
xattr -d。 - 能启动、能连 SSH,菜单里没有 DevTools。
codesign --verify --deep --strict且codesign -dv不是Signature=adhoc。- 删掉 Release 说明和
release.py里的「右键绕过 Gatekeeper」。
没做完 staple 之前,文档继续写「未公证」。
4. Windows Authenticode
CI 已有 PFX 导入和 Get-AuthenticodeSignature 门禁。本机应对齐:
- 导入 PFX,把 thumbprint 写入
tauri.signing.conf.json(digestAlgorithm: sha256,时间戳如http://timestamp.digicert.com)。 - 对
.exe/.msi都验Status -eq Valid,不要只签主程序。 - 在一台干净 Windows 上安装:SmartScreen 不应再是「未知发布者」。EV 证书对 SmartScreen 更友好,OV 可能仍有一段时间的声誉积累——如实写,不要标「已通过 SmartScreen」。
5. 自动更新(有公钥、HTTPS、回滚才开)
架构规则已经写死:没有签名公钥、HTTPS 更新源和回滚策略,更新必须保持关闭。接入顺序:
- 生成 minisign 密钥;公钥进
tauri.conf.json的plugins.updater.pubkey;私钥只进 Secrets。 - 依赖
tauri-plugin-updater,capabilities 只开updater:allow-check与updater:allow-download-and-install。 - 构建打开
createUpdaterArtifacts,每个安装包旁有.sig。 - 发布时生成
latest.json(版本、各平台 URL、签名),放到 HTTPS(Gitee/GitHub Release 附件或静态镜像,建议双 endpoint)。 - 前端「检查更新」:公钥和 endpoint 未进正式包之前不要画这个入口。
- 回滚:保留上一份
latest.json;更新失败或健康检查失败时指回上一版本;文档写清如何撤回错误版本(覆盖 manifest,而不是删掉用户已装的包)。 release.py除.dmg/.exe/.msi外还要上传.sig与latest.json。
未完成前,设置页、欢迎页、菜单都不要出现「自动更新」或「已是最新」。
6. 发布工作流补齐(与签名独立,但同一闭环)
.github/workflows/tauri-release.yml 现在只 upload-artifact(约 90 天过期),permissions.contents: read,不能建 GitHub Release。有凭据并公证之后再改:
- tag 与现有 Gitee 流程对齐(不要两套版本号)。
contents: write后创建 Release,附 SHA256SUMS、安装包、.sig、latest.json。- 公证步骤放在「Verify native package」之前或之中;未 staple 不得当正式附件。
GitHub Release 不是「已公证」的替代;没有 notary/Authenticode 时,Release 也只能标开发包。
产物验证
npm run release:preflight:mac
npm run release:verify:mac
npm run release:preflight:win
npm run release:verify:win
验证脚本检查架构、体积和安装包存在性。正式标签还会验证 macOS 签名/Gatekeeper 或 Windows Authenticode 签名。
安装包还必须包含 ssh:// 协议注册。macOS 检查 CFBundleURLTypes,Windows 安装后检查当前用户 Software\\Classes\\ssh 并实际执行一次协议唤起。只验证配置文件不足以证明单实例事件交付正常。
发布前检查
package.json、package-lock.json、src-tauri/Cargo.toml、Cargo.lock和tauri.conf.json版本一致。npm run acceptance:full通过。- 目标平台构建和签名通过。
- 安装后完成输入框复制/粘贴、SFTP 双向拖拽、普通区域右键菜单、SSH/SFTP/代理/跳板和
ssh://单实例唤起验收。 - 大模型新配置必须先测试后保存;Agent CLI 必须固定当前 SSH 目标,每条命令确认后才执行,critical 命令不得放行。
- 检查安装包尺寸,没有上传
rw.*.dmg、日志、测试密钥或用户数据。 - 保留上一稳定版本及回滚说明。