feat(updater): gate auto-updater behind Cargo feature updater

Makes tauri-plugin-updater and tauri-plugin-process optional
dependencies enabled by a default-on `updater` Cargo feature.
Sandboxed packaging targets (Flatpak, Snap) will build with
`--no-default-features` to exclude the plugins entirely,
satisfying store policies that prohibit competing auto-updaters.

Changes:
- Cargo.toml: add `updater` feature; plugins are now optional deps
- lib.rs: gate plugin registration on the feature
- updates/mod.rs: is_auto_update_eligible() returns false when
  the feature is off (catch-all for unusual build configs)
- capabilities/default.json: remove updater/process permissions
- build.rs: emit capabilities/auto-updater.json only when the
  feature is enabled; remove it otherwise. The file is gitignored
  since it is fully build-driven.

cc
This commit is contained in:
vicrodh committed 2026-04-13 18:32:28 -06:00
1 parent 0dd0313087
commit 031da1792d
6 files changed
+62 -11

No files matched your search

+9 -2
View File
@@ -16,6 +16,13 @@ path = "src/main.rs"
[build-dependencies]
tauri-build = { version = "2", features = [] }
[features]
default = ["updater"]
# Enables the in-app auto-updater (tauri-plugin-updater + tauri-plugin-process).
# Disabled for sandboxed packaging targets (Flatpak, Snap) which have their own
# update channels and whose store policies prohibit competing updaters.
updater = ["dep:tauri-plugin-updater", "dep:tauri-plugin-process"]
[dependencies]
# QBZ Crates (extracted core functionality)
qbz-models = { path = "../crates/qbz-models" }
@@ -39,8 +46,8 @@ tauri-plugin-opener = "2"
tauri-plugin-os = "2"
tauri-plugin-single-instance = { version = "2", features = ["deep-link"] }
tauri-plugin-deep-link = "2"
tauri-plugin-updater = "2"
tauri-plugin-process = "2"
tauri-plugin-updater = { version = "2", optional = true }
tauri-plugin-process = { version = "2", optional = true }
# Serialization
serde = { version = "1", features = ["derive"] }
+32
View File
@@ -1,3 +1,35 @@
use std::fs;
use std::path::Path;
/// Auto-updater capability, emitted to capabilities/ only when the `updater`
/// Cargo feature is active. Gitignored so Flatpak/Snap builds (which disable
/// the feature) never reference permissions for plugins that aren't linked.
const AUTO_UPDATER_CAPABILITY: &str = r#"{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "auto-updater",
"description": "Permissions for the in-app auto-updater (macOS + Linux AppImage). Generated by build.rs when the `updater` Cargo feature is enabled.",
"windows": ["main", "miniplayer"],
"permissions": [
"updater:default",
"process:allow-restart"
]
}
"#;
fn main() {
let capability_path = Path::new("capabilities/auto-updater.json");
if cfg!(feature = "updater") {
if let Err(e) = fs::write(capability_path, AUTO_UPDATER_CAPABILITY) {
panic!("Failed to emit auto-updater capability: {e}");
}
} else if capability_path.exists() {
if let Err(e) = fs::remove_file(capability_path) {
panic!("Failed to remove stale auto-updater capability: {e}");
}
}
println!("cargo:rerun-if-changed=build.rs");
tauri_build::build()
}
+1 -3
View File
@@ -36,8 +36,6 @@
"os:default",
"dialog:default",
"clipboard-manager:default",
"clipboard-manager:allow-write-text",
"updater:default",
"process:allow-restart"
"clipboard-manager:allow-write-text"
]
}
+8 -3
View File
@@ -729,7 +729,7 @@ pub fn run() {
// Initialize per-user data paths (no user active yet until login)
let user_data_paths = user_data::UserDataPaths::new();
tauri::Builder::default()
let builder = tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {
// Second instance launched — bring existing window to front
if let Some(window) = app.get_webview_window("main") {
@@ -750,9 +750,14 @@ pub fn run() {
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_clipboard_manager::init());
#[cfg(feature = "updater")]
let builder = builder
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_process::init());
builder
.manage(AppState::with_device_and_settings(
saved_device,
audio_settings,
+10 -3
View File
@@ -661,13 +661,20 @@ pub async fn fetch_release_for_version(
/// - Linux AppImage (detected via APPIMAGE env var)
///
/// Not supported for Flatpak, Snap, DEB, RPM, AUR, Gentoo (they have their own update channels).
/// Also returns false unconditionally when the `updater` Cargo feature is disabled
/// (i.e., sandboxed Flatpak/Snap builds that don't link tauri-plugin-updater).
pub fn is_auto_update_eligible() -> bool {
#[cfg(target_os = "macos")]
#[cfg(not(feature = "updater"))]
{
return false;
}
#[cfg(all(feature = "updater", target_os = "macos"))]
{
return true;
}
#[cfg(target_os = "linux")]
#[cfg(all(feature = "updater", target_os = "linux"))]
{
if crate::flatpak::is_flatpak() || crate::snap::is_snap() {
return false;
@@ -675,7 +682,7 @@ pub fn is_auto_update_eligible() -> bool {
return env::var("APPIMAGE").is_ok();
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
#[cfg(all(feature = "updater", not(any(target_os = "macos", target_os = "linux"))))]
{
false
}