Skip to content

Commit 8d148a9

Browse files
feat: Custom sign command with object notation (#10634)
* feat!: Custom sign command with object notation * implement JsonSchema if schema feature is enabled * feat: support old string-based custom signing command config * format: Run cargo fmt inside tooling/bundler folder * chore: update json schema * format: cargo fmt again * small cleanup * fix change file --------- Co-authored-by: Lucas Nogueira <[email protected]>
1 parent 5c335ae commit 8d148a9

File tree

9 files changed

+162
-31
lines changed

9 files changed

+162
-31
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"tauri-bundler": patch:feat
3+
"tauri-utils": patch:feat
4+
"@tauri-apps/cli": patch:feat
5+
"tauri-cli": patch:feat
6+
---
7+
8+
Custom sign command with object notation for whitespaces in the command path and arguments.

core/tauri-config-schema/schema.json

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,10 +2033,14 @@
20332033
]
20342034
},
20352035
"signCommand": {
2036-
"description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in it which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n Example:\n ```text\n sign-cli --arg1 --arg2 %1\n ```\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.",
2037-
"type": [
2038-
"string",
2039-
"null"
2036+
"description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in args which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.",
2037+
"anyOf": [
2038+
{
2039+
"$ref": "#/definitions/CustomSignCommandConfig"
2040+
},
2041+
{
2042+
"type": "null"
2043+
}
20402044
]
20412045
}
20422046
},
@@ -2425,6 +2429,37 @@
24252429
}
24262430
]
24272431
},
2432+
"CustomSignCommandConfig": {
2433+
"description": "Custom Signing Command configuration.",
2434+
"anyOf": [
2435+
{
2436+
"description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].",
2437+
"type": "string"
2438+
},
2439+
{
2440+
"description": "An object notation of the command.\n\n This is more complex notation for the command but\n this allows you to use whitespace in the command and arguments.",
2441+
"type": "object",
2442+
"required": [
2443+
"args",
2444+
"cmd"
2445+
],
2446+
"properties": {
2447+
"cmd": {
2448+
"description": "The command to run to sign the binary.",
2449+
"type": "string"
2450+
},
2451+
"args": {
2452+
"description": "The arguments to pass to the command.\n\n \"%1\" will be replaced with the path to the binary to be signed.",
2453+
"type": "array",
2454+
"items": {
2455+
"type": "string"
2456+
}
2457+
}
2458+
},
2459+
"additionalProperties": false
2460+
}
2461+
]
2462+
},
24282463
"LinuxConfig": {
24292464
"description": "Configuration for Linux bundles.\n\n See more: <https://tauri.app/v1/api/config#linuxconfig>",
24302465
"type": "object",

core/tauri-utils/src/config.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,34 @@ impl Default for WebviewInstallMode {
891891
}
892892
}
893893

894+
/// Custom Signing Command configuration.
895+
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
896+
#[cfg_attr(feature = "schema", derive(JsonSchema))]
897+
#[serde(rename_all = "camelCase", deny_unknown_fields, untagged)]
898+
pub enum CustomSignCommandConfig {
899+
/// A string notation of the script to execute.
900+
///
901+
/// "%1" will be replaced with the path to the binary to be signed.
902+
///
903+
/// This is a simpler notation for the command.
904+
/// Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.
905+
///
906+
/// If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].
907+
Command(String),
908+
/// An object notation of the command.
909+
///
910+
/// This is more complex notation for the command but
911+
/// this allows you to use whitespace in the command and arguments.
912+
CommandWithOptions {
913+
/// The command to run to sign the binary.
914+
cmd: String,
915+
/// The arguments to pass to the command.
916+
///
917+
/// "%1" will be replaced with the path to the binary to be signed.
918+
args: Vec<String>,
919+
},
920+
}
921+
894922
/// Windows bundler configuration.
895923
///
896924
/// See more: <https://tauri.app/v1/api/config#windowsconfig>
@@ -935,19 +963,14 @@ pub struct WindowsConfig {
935963
/// Configuration for the installer generated with NSIS.
936964
pub nsis: Option<NsisConfig>,
937965
/// Specify a custom command to sign the binaries.
938-
/// This command needs to have a `%1` in it which is just a placeholder for the binary path,
966+
/// This command needs to have a `%1` in args which is just a placeholder for the binary path,
939967
/// which we will detect and replace before calling the command.
940968
///
941-
/// Example:
942-
/// ```text
943-
/// sign-cli --arg1 --arg2 %1
944-
/// ```
945-
///
946969
/// By Default we use `signtool.exe` which can be found only on Windows so
947970
/// if you are on another platform and want to cross-compile and sign you will
948971
/// need to use another tool like `osslsigncode`.
949972
#[serde(alias = "sign-command")]
950-
pub sign_command: Option<String>,
973+
pub sign_command: Option<CustomSignCommandConfig>,
951974
}
952975

953976
impl Default for WindowsConfig {

tooling/bundler/src/bundle.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ use tauri_utils::display_path;
2020
pub use self::{
2121
category::AppCategory,
2222
settings::{
23-
AppImageSettings, BundleBinary, BundleSettings, DebianSettings, DmgSettings, MacOsSettings,
24-
PackageSettings, PackageType, Position, RpmSettings, Settings, SettingsBuilder, Size,
25-
UpdaterSettings,
23+
AppImageSettings, BundleBinary, BundleSettings, CustomSignCommandSettings, DebianSettings,
24+
DmgSettings, MacOsSettings, PackageSettings, PackageType, Position, RpmSettings, Settings,
25+
SettingsBuilder, Size, UpdaterSettings,
2626
},
2727
};
2828
#[cfg(target_os = "macos")]

tooling/bundler/src/bundle/settings.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,17 @@ pub struct NsisSettings {
459459
pub installer_hooks: Option<PathBuf>,
460460
}
461461

462+
/// The Custom Signing Command Settings for Windows exe
463+
#[derive(Clone, Debug)]
464+
pub struct CustomSignCommandSettings {
465+
/// The command to run to sign the binary.
466+
pub cmd: String,
467+
/// The arguments to pass to the command.
468+
///
469+
/// "%1" will be replaced with the path to the binary to be signed.
470+
pub args: Vec<String>,
471+
}
472+
462473
/// The Windows bundle settings.
463474
#[derive(Clone, Debug)]
464475
pub struct WindowsSettings {
@@ -504,7 +515,7 @@ pub struct WindowsSettings {
504515
/// By Default we use `signtool.exe` which can be found only on Windows so
505516
/// if you are on another platform and want to cross-compile and sign you will
506517
/// need to use another tool like `osslsigncode`.
507-
pub sign_command: Option<String>,
518+
pub sign_command: Option<CustomSignCommandSettings>,
508519
}
509520

510521
impl Default for WindowsSettings {

tooling/bundler/src/bundle/windows/sign.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// SPDX-License-Identifier: Apache-2.0
44
// SPDX-License-Identifier: MIT
55

6+
use crate::bundle::settings::CustomSignCommandSettings;
67
#[cfg(windows)]
78
use crate::bundle::windows::util;
89
use crate::{bundle::common::CommandExt, Settings};
9-
use anyhow::Context;
1010
#[cfg(windows)]
1111
use std::path::PathBuf;
1212
#[cfg(windows)]
@@ -50,7 +50,7 @@ pub struct SignParams {
5050
pub certificate_thumbprint: String,
5151
pub timestamp_url: Option<String>,
5252
pub tsp: bool,
53-
pub sign_command: Option<String>,
53+
pub sign_command: Option<CustomSignCommandSettings>,
5454
}
5555

5656
#[cfg(windows)]
@@ -136,16 +136,14 @@ pub fn verify(path: &Path) -> crate::Result<bool> {
136136
Ok(cmd.status()?.success())
137137
}
138138

139-
pub fn sign_command_custom<P: AsRef<Path>>(path: P, command: &str) -> crate::Result<Command> {
139+
pub fn sign_command_custom<P: AsRef<Path>>(
140+
path: P,
141+
command: &CustomSignCommandSettings,
142+
) -> crate::Result<Command> {
140143
let path = path.as_ref();
141144

142-
let mut args = command.trim().split(' ');
143-
let bin = args
144-
.next()
145-
.context("custom signing command doesn't contain a bin?")?;
146-
147-
let mut cmd = Command::new(bin);
148-
for arg in args {
145+
let mut cmd = Command::new(&command.cmd);
146+
for arg in &command.args {
149147
if arg == "%1" {
150148
cmd.arg(path);
151149
} else {
@@ -194,7 +192,10 @@ pub fn sign_command<P: AsRef<Path>>(path: P, params: &SignParams) -> crate::Resu
194192
}
195193
}
196194

197-
pub fn sign_custom<P: AsRef<Path>>(path: P, custom_command: &str) -> crate::Result<()> {
195+
pub fn sign_custom<P: AsRef<Path>>(
196+
path: P,
197+
custom_command: &CustomSignCommandSettings,
198+
) -> crate::Result<()> {
198199
let path = path.as_ref();
199200

200201
log::info!(action = "Signing";"{} with a custom signing command", tauri_utils::display_path(path));

tooling/cli/schema.json

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,10 +2033,14 @@
20332033
]
20342034
},
20352035
"signCommand": {
2036-
"description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in it which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n Example:\n ```text\n sign-cli --arg1 --arg2 %1\n ```\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.",
2037-
"type": [
2038-
"string",
2039-
"null"
2036+
"description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in args which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.",
2037+
"anyOf": [
2038+
{
2039+
"$ref": "#/definitions/CustomSignCommandConfig"
2040+
},
2041+
{
2042+
"type": "null"
2043+
}
20402044
]
20412045
}
20422046
},
@@ -2425,6 +2429,37 @@
24252429
}
24262430
]
24272431
},
2432+
"CustomSignCommandConfig": {
2433+
"description": "Custom Signing Command configuration.",
2434+
"anyOf": [
2435+
{
2436+
"description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].",
2437+
"type": "string"
2438+
},
2439+
{
2440+
"description": "An object notation of the command.\n\n This is more complex notation for the command but\n this allows you to use whitespace in the command and arguments.",
2441+
"type": "object",
2442+
"required": [
2443+
"args",
2444+
"cmd"
2445+
],
2446+
"properties": {
2447+
"cmd": {
2448+
"description": "The command to run to sign the binary.",
2449+
"type": "string"
2450+
},
2451+
"args": {
2452+
"description": "The arguments to pass to the command.\n\n \"%1\" will be replaced with the path to the binary to be signed.",
2453+
"type": "array",
2454+
"items": {
2455+
"type": "string"
2456+
}
2457+
}
2458+
},
2459+
"additionalProperties": false
2460+
}
2461+
]
2462+
},
24282463
"LinuxConfig": {
24292464
"description": "Configuration for Linux bundles.\n\n See more: <https://tauri.app/v1/api/config#linuxconfig>",
24302465
"type": "object",

tooling/cli/src/helpers/config.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,23 @@ pub fn nsis_settings(config: NsisConfig) -> tauri_bundler::NsisSettings {
110110
}
111111
}
112112

113+
pub fn custom_sign_settings(
114+
config: CustomSignCommandConfig,
115+
) -> tauri_bundler::CustomSignCommandSettings {
116+
match config {
117+
CustomSignCommandConfig::Command(command) => {
118+
let mut tokens = command.split(' ');
119+
tauri_bundler::CustomSignCommandSettings {
120+
cmd: tokens.next().unwrap().to_string(), // split always has at least one element
121+
args: tokens.map(String::from).collect(),
122+
}
123+
}
124+
CustomSignCommandConfig::CommandWithOptions { cmd, args } => {
125+
tauri_bundler::CustomSignCommandSettings { cmd, args }
126+
}
127+
}
128+
}
129+
113130
fn config_handle() -> &'static ConfigHandle {
114131
static CONFIG_HANDLE: OnceLock<ConfigHandle> = OnceLock::new();
115132
CONFIG_HANDLE.get_or_init(Default::default)

tooling/cli/src/interface/rust.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ mod cargo_config;
4040
mod desktop;
4141
pub mod installation;
4242
pub mod manifest;
43+
use crate::helpers::config::custom_sign_settings;
4344
use cargo_config::Config as CargoConfig;
4445
use manifest::{rewrite_manifest, Manifest};
4546

@@ -1424,7 +1425,7 @@ fn tauri_config_to_bundle_settings(
14241425
webview_install_mode: config.windows.webview_install_mode,
14251426
webview_fixed_runtime_path: config.windows.webview_fixed_runtime_path,
14261427
allow_downgrades: config.windows.allow_downgrades,
1427-
sign_command: config.windows.sign_command,
1428+
sign_command: config.windows.sign_command.map(custom_sign_settings),
14281429
},
14291430
license: config.license.or_else(|| {
14301431
settings

0 commit comments

Comments
 (0)