Tauri v2 Updaterビルドは設定overlayを分ける
Tauri v2のupdaterは、同じ機能に見えても2つの別レイヤーで設定されます。
Rust側のコードはCargo featureで切り替えられます。一方で、Tauri bundlerの設定はビルドツールが後段で読むJSON設定です。tauri.conf.jsonにupdater設定を入れたままだと、Rustのupdaterコードを無効にしていても、通常ビルドがupdater artifactの作成や署名を試みることがあります。
安全な形は、base configからupdater専用設定を外し、updater付きrelease buildのときだけ別のoverlay configを適用することです。
症状: 通常ビルドなのに署名を要求される
失敗はコンパイル後、bundle stepで出ることが多いです。
Error: missing private key
または:
TAURI_SIGNING_PRIVATE_KEY is not set
Rust側ではすでにfeature gateを書いているので、直感に反します。
#[cfg(feature = "updater")]
fn init_updater() {
// updater setup
}
しかし、このfeature gateが制御しているのはRustのコンパイルです。bundlerが読むJSON設定からupdater keyを消すわけではありません。
Cargo featureはTauri bundler configを制御しない
Cargo featureはRust crateのcompile-time inputです。どのmodule、関数、dependencyをコンパイルするかを決めます。
Tauri configはbuild-tool inputです。bundlerはbundle.createUpdaterArtifactsやplugins.updaterを設定ファイルから読みます。default buildで使う設定にそれらのkeyが残っていれば、Rust featureがoffでもbundlerはその設定に従って動けます。
例えば、base configに次を入れると危険です。
{
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"pubkey": "PASTE THE PUBLIC KEY TEXT HERE",
"endpoints": ["https://releases.my-app.invalid/latest.json"]
}
}
}
この時点でbase configは「updater build用の設定」になっています。通常ビルドは、もう純粋な通常ビルドではありません。
updater設定はoverlay configへ移す
base configには、すべてのbuild variantで共通する設定だけを残します。
{
"productName": "my-app",
"version": "1.0.0",
"build": {
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},
"bundle": {
"active": true,
"targets": ["nsis", "msi"]
},
"plugins": {}
}
updater専用設定は、例えばsrc-tauri/tauri.updater.conf.jsonに分けます。
{
"bundle": {
"createUpdaterArtifacts": true
},
"plugins": {
"updater": {
"pubkey": "PASTE THE PUBLIC KEY TEXT HERE",
"endpoints": ["https://releases.my-app.invalid/latest.json"],
"windows": {
"installMode": "passive"
}
}
}
}
これでbuild commandの意味が明確になります。
# 通常installer build: updater artifactも署名要求もなし
npm run tauri -- build
# updater release build: updater feature + updater config overlay
npm run tauri -- build --features updater --config src-tauri/tauri.updater.conf.json
重要なのは、updater featureを有効にするcommandでは、必ずupdater config overlayも適用することです。
Rust側のfeature gateも残す
overlayは、default build時にbundlerがupdater設定を読まないようにするためのものです。Rust側のfeature gateの代わりではありません。
runtime setupも明示しておきます。
#[cfg(feature = "updater")]
fn init_updater(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
app.handle().plugin(tauri_plugin_updater::Builder::new().build())?;
Ok(())
}
#[cfg(not(feature = "updater"))]
fn init_updater(_app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
そのうえで、通常のsetup pathからinit_updater()を呼びます。default buildではno-opになり、updater buildではpluginを初期化します。
exit codeではなくartifactを確認する
updater buildで特に危険なのは、成功したように見える欠落です。
次のcommandは、overlayを忘れていてもcompileやbundle自体は成功することがあります。
npm run tauri -- build --features updater
--config src-tauri/tauri.updater.conf.jsonがないため、installerはできてもupdater署名が生成されない、という状態になり得ます。
release手順にはartifact checkを入れます。
# default buildではupdater署名がないことを確認
npm run tauri -- build
test ! -f "src-tauri/target/release/bundle/nsis/my-app_1.0.0_x64-setup.exe.sig"
# updater buildでは署名があることを確認
npm run tauri -- build --features updater --config src-tauri/tauri.updater.conf.json
test -f "src-tauri/target/release/bundle/nsis/my-app_1.0.0_x64-setup.exe.sig"
PowerShellならTest-Pathで同じ確認を書けます。
if (-not (Test-Path "src-tauri\target\release\bundle\nsis\my-app_1.0.0_x64-setup.exe.sig")) {
throw "Updater signature was not generated"
}
実際のartifact名はproduct name、version、architecture、bundler targetで変わります。release processで期待している本物のpathを確認してください。
この修正が向かないケース
buildが失敗しただけで、常にoverlayを増やせばよいわけではありません。
overlay patternが必要なのは、次の条件が揃うときです。
- featureがoptionalである
- build tool側にもそのfeature用のconfig keyがある
- compiled code pathがoffでも、そのconfig keyがbuild toolを動かす
- build variantごとに生成すべきartifactが違う
すべてのreleaseで常にupdater artifactが必要なら、base configにupdater設定を置く設計もあり得ます。その場合は、CIで署名環境を確実に用意するほうが本筋です。
参考
- Tauri updater plugin
- Tauri configuration reference
- feature flagがbuild tool configを制御しない時はoverlayを使う
- Tauri v2 IPCはRustとTypeScriptの契約を明示してずれを防ぐ
まとめ
updater artifactは、通常ビルドとは別のbuild variantとして扱います。defaultのtauri.conf.jsonからupdater専用設定を外し、updater release buildでだけoverlayを適用し、最後に.sigファイルの有無を確認します。これで、不要な署名要求と、成功したように見える更新不能releaseの両方を避けられます。