Skip to content

Conversation

@kandrelczyk
Copy link
Contributor

This addresses #14186

Alternative patch method based on string value change. Since this is now common for all platforms I removed the no longer necessary code. Also clean up error that is no longer needed. Tested this on Linux with stripped binary and using updater plugin unit tests.

@kandrelczyk kandrelczyk requested a review from a team as a code owner November 22, 2025 23:29
@github-project-automation github-project-automation bot moved this to 📬Proposal in Roadmap Nov 22, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 23, 2025

Package Changes Through 7595a70

There are 7 changes which include @tauri-apps/api with patch, tauri with patch, tauri-cli with patch, tauri-bundler with patch, @tauri-apps/cli with patch, tauri-macos-sign with patch, tauri-utils with patch

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@tauri-apps/api 2.9.0 2.9.1
tauri-utils 2.8.0 2.8.1
tauri-macos-sign 2.3.0 2.3.1
tauri-bundler 2.7.3 2.7.4
tauri-runtime 2.9.1 2.9.2
tauri-runtime-wry 2.9.1 2.9.2
tauri-codegen 2.5.1 2.5.2
tauri-macros 2.5.1 2.5.2
tauri-plugin 2.5.1 2.5.2
tauri-build 2.5.2 2.5.3
tauri 2.9.3 2.9.4
@tauri-apps/cli 2.9.4 2.9.5
tauri-cli 2.9.4 2.9.5

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

}
let mut file_data = std::fs::read(binary).expect("Could not read binary file.");

if let Some(bundle_var_index) = kmp::index_of(BUNDLE_VAR_TOKEN, &file_data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't look at it closely yet, but I think this would fail when patching the binary for the second bundle type right? (e.g .msi first and __TAURI_BUNDLE_TYPE becomes __TAURI_BUNDLE_TYPE_VAR_MSI already that when we do it for the NSIS bundle, we can no longer find __TAURI_BUNDLE_TYPE_VAR_UNK)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an issue with double signing the binaries or patching already signed binary (I don't remember exactly) and the fix was to copy the original binary before each bundle so this should be fine. I tested on linux with standard deb,rpm and appImage and didn't get any errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you remember if after the bundling is all done the binary in target/release/ will be a fresh one or the one from the last patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've double checked and something is not right. I will fix it so that we always patch and bundle a copy of the binary and at the end we're left with the original, unpatched one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still a bit concerned about this approach, like if we stopped at one of these steps (user pressed ctrl-c or we had an error somewhere), there's no way to recover/bundle again other than rebuilding the app's binary through cargo, and since we're matching any string in the binary, although unlikely, we risk replacing the wrong things

In my opinion, this method should not be used for the binary patching/main detection method

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we make sure to never touch the binary in target/release/ and always work on the copy somewhere else then you can just re-run tauri bundle but not sure if that's what you mean

Ah, didn't think of that, that should probably fix this problem, it might leave files in the temp folder but I guess if that's somewhere inside target, the next cargo clean removes it anyways

True but this is so unlikely i wouldn't even count this as an argument

Fair, I just don't really like that chance to be honest 😂

well, any ideas left for the patching idea?

I messed up the words when moving them, I was thinking it shouldn't be the 'main binary patching/detection' method (e.g. use the current one and adding this for a backup)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I messed up the words when moving them, I was thinking it shouldn't be the 'main binary patching/detection' method (e.g. use the current one and adding this for a backup)

ah my bad. I mean honestly fair enough! we can keep both 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  // When packaging multiple binary types, we make a copy of the unsigned main_binary so that we can
  // restore it after each package_type step. This avoids two issues:
  //  - modifying a signed binary without updating its PE checksum can break signature verification
  //    - codesigning tools should handle calculating+updating this, we just need to ensure
  //      (re)signing is performed after every `patch_binary()` operation
  //  - signing an already-signed binary can result in multiple signatures, causing verification errors
  let main_binary_reset_required = matches!(target_os, TargetPlatform::Windows)
    && settings.windows().can_sign()
    && package_types.len() > 1;

So I remembered correctly we do this but it's just for Windows right now. I'm assuming simply extending this approach to Linux will be enough, right? It's basically boils down to the same issue. I will work on this later today.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the future we should look into the "work on temp copy only" approach but that's not urgent

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to be clear, are we going to use this method for binary patching exclusively or do we want to use this as a fallback? (e.g. the find link section thing -> find the string and replace)

/// Package type is not supported by target platform
#[error("Wrong package type {0} for platform {1}")]
InvalidPackageType(String, String),
#[error("Wrong package type {0}")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we could make breaking changes here

@FabianLars any thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only used by the binary patching code. I don't think any external code will use this error as it's very specific.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have downstream bundler users so ideally we don't break here. also not sure if we wanted to keep the old logic around or not @Legend-Master ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we keep InvalidPackageType the same and mark the other variants deprecated?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah yeah - my ping was a bit offtopic here. Just deprecate it, change the comment to say that it's unused and move on.

}
let mut file_data = std::fs::read(binary).expect("Could not read binary file.");

if let Some(bundle_var_index) = kmp::index_of(BUNDLE_VAR_TOKEN, &file_data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just to be clear, are we going to use this method for binary patching exclusively or do we want to use this as a fallback? (e.g. the find link section thing -> find the string and replace)

@kandrelczyk
Copy link
Contributor Author

I've change this to be the only method. I don't see any benefits in using the old method over this.

@FabianLars
Copy link
Member

since the old method didn't work well i agree but i really don't mind either so i'm fine with what tony decides lol - i do like how this here has a seemingly way simpler impl

@Legend-Master
Copy link
Contributor

Let's just roll with this one exclusively

Copy link
Contributor

@Legend-Master Legend-Master left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looking good, seems to work on Windows from testing, thanks again for the help on this
Just some nitpicks

/// Package type is not supported by target platform
#[deprecated(note = "User WrongPackageType instead")]
#[error("Wrong package type {0} for platform {1}")]
InvalidPackageType(String, String),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we change this to WrongPackageType and removed the platform info?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I merged both Linux and Windows cases in one function so I thought the platform validation doesn't apply anymore but after thinking about it I split it again

   #[cfg(target_os = "linux")]
    let bundle_type = match package_type {
      crate::PackageType::Deb => b"__TAURI_BUNDLE_TYPE_VAR_DEB",
      crate::PackageType::Rpm => b"__TAURI_BUNDLE_TYPE_VAR_RPM",
      crate::PackageType::AppImage => b"__TAURI_BUNDLE_TYPE_VAR_APP",
      _ => {
        return Err(crate::Error::InvalidPackageType(
          package_type.short_name().to_owned(),
          "Linux".to_owned(),
        ))
      }
    };
    #[cfg(target_os = "windows")]
    let bundle_type = match package_type {
      crate::PackageType::Nsis => b"__TAURI_BUNDLE_TYPE_VAR_NSS",
      crate::PackageType::WindowsMsi => b"__TAURI_BUNDLE_TYPE_VAR_MSI",
      _ => {
        return Err(crate::Error::InvalidPackageType(
          package_type.short_name().to_owned(),
          "Windows".to_owned(),
        ))
      }
    };
'''

So I've restored this error.

@kandrelczyk
Copy link
Contributor Author

Totally forgot about Mac. I disabled patching on Mac since we already handle it in pub fn bundle_type() in platform.rs. Or do we prefer to patch it and change this method?

match __TAURI_BUNDLE_TYPE {
      "__TAURI_BUNDLE_TYPE_VAR_DEB" => Some(BundleType::Deb),
      "__TAURI_BUNDLE_TYPE_VAR_RPM" => Some(BundleType::Rpm),
      "__TAURI_BUNDLE_TYPE_VAR_APP" => Some(BundleType::AppImage),
      "__TAURI_BUNDLE_TYPE_VAR_MSI" => Some(BundleType::Msi),
      "__TAURI_BUNDLE_TYPE_VAR_NSS" => Some(BundleType::Nsis),
      _ => {
        if cfg!(target_os = "macos") {
          Some(BundleType::App)
        } else {
          None
        }
      }

would be

match __TAURI_BUNDLE_TYPE {
      "__TAURI_BUNDLE_TYPE_VAR_DEB" => Some(BundleType::Deb),
      "__TAURI_BUNDLE_TYPE_VAR_RPM" => Some(BundleType::Rpm),
      "__TAURI_BUNDLE_TYPE_VAR_APP" => Some(BundleType::AppImage),
      "__TAURI_BUNDLE_TYPE_VAR_MSI" => Some(BundleType::Msi),
      "__TAURI_BUNDLE_TYPE_VAR_NSS" => Some(BundleType::Nsis),
      "__TAURI_BUNDLE_TYPE_VAR_MAC" => Some(BundleType::App),
      _ => None
      }

@Legend-Master
Copy link
Contributor

I think we could change that later if we actually add another bundler for mac

Also, we probably want to fix those warnings 🙃

https://github.com/tauri-apps/tauri/actions/runs/19749488088/job/56598652144?pr=14521

@kandrelczyk
Copy link
Contributor Author

Fixed 👍

@@ -0,0 +1,8 @@
---
"tauri": patch:changes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FabianLars do we want to delay this to next minor? since this isn't compatible with our current tauri and cli minor versions combo

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds reasonable

@Legend-Master Legend-Master added this to the 2.10 milestone Nov 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 📬Proposal

Development

Successfully merging this pull request may close these issues.

3 participants