← ./articles-ja

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.createUpdaterArtifactsplugins.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で署名環境を確実に用意するほうが本筋です。

参考

まとめ

updater artifactは、通常ビルドとは別のbuild variantとして扱います。defaultのtauri.conf.jsonからupdater専用設定を外し、updater release buildでだけoverlayを適用し、最後に.sigファイルの有無を確認します。これで、不要な署名要求と、成功したように見える更新不能releaseの両方を避けられます。