tauri-apps / tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
https://tauri.app
Apache License 2.0
85.58k stars 2.59k forks source link

[bug] Fail to sign protoc sidecar with Azure Trusted Signing #11778

Open gschier opened 3 days ago

gschier commented 3 days ago

[!IMPORTANT]
The issue was that the sidecar binary was read-only but Tauri silenced the permission error. See https://github.com/tauri-apps/tauri/issues/11778#issuecomment-2495504198 for more info.

Describe the bug

I'm trying to get Azure Trusted Signing working for my app github.com/mountain-loop/yaak. It signs the main .exe correctly, and correctly skips the already-signed NodeJS sidecar. However, it seems to fail on the unsigned protoc sidecar.

Here is the output from https://github.com/mountain-loop/yaak/actions/runs/11976760384/job/33393142512

Finished `release` profile [optimized] target(s) in 11m 48s
warning: the following packages contain code that will be rejected by a future version of Rust: iso8601 v0.3.0, nom v4.2.3
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`
    Built application at: D:\a\yaak\yaak\src-tauri\target\release\yaak-app.exe
    Signing D:\a\yaak\yaak\src-tauri\target\release\yaak-app.exe
    Signing D:\a\yaak\yaak\src-tauri\target\release\yaak-app.exe with a custom signing command
    Info "[\r\n  {\r\n    \"cloudName\": \"AzureCloud\",\r\n    \"homeTenantId\": \"***\",\r\n    \"id\": \"b045e283-89f9-42ff-bd9a-95f6e7a9b035\",\r\n    \"isDefault\": true,\r\n    \"managedByTenants\": [],\r\n    \"name\": \"Yaak Subscription\",\r\n    \"state\": \"Enabled\",\r\n    \"tenantId\": \"***\",\r\n    \"user\": {\r\n      \"name\": \"***\",\r\n      \"type\": \"servicePrincipal\"\r\n    }\r\n  }\r\n]\r\n\r\nTrusted Signing\r\n\r\nVersion: 1.0.60\r\n\r\n\"Metadata\": {\r\n  \"Endpoint\": \"[https://eus.codesigning.azure.net/\](https://eus.codesigning.azure.net//)",\r\n  \"CodeSigningAccountName\": \"Yaak\",\r\n  \"CertificateProfileName\": \"yaakapp\",\r\n  \"ExcludeCredentials\": []\r\n}\r\n\r\nSubmitting digest for signing...\r\n\r\nOperationId 1eb5fd2a-01d6-45e8-b43a-bacda9cd5f54: InProgress\r\n\r\nSigning completed with status 'Succeeded' in 1.6176595s\r\n\r\nSuccessfully signed: D:\\a\\yaak\\yaak\\src-tauri\\target\\release\\yaak-app.exe\r\r\n\r\nNumber of files successfully Signed: 1\r\r\nNumber of warnings: 0\r\r\nNumber of errors: 0\r\r\n"
File: vendored\node\yaaknode-x86_64-pc-windows-msvc.exe
Index  Algorithm  Timestamp    
========================================
0      sha256     RFC3161      

Successfully verified: vendored\node\yaaknode-x86_64-pc-windows-msvc.exe

    Info sidecar at "vendored\node\yaaknode-x86_64-pc-windows-msvc.exe" already signed. Skipping...
File: vendored\protoc\yaakprotoc-x86_64-pc-windows-msvc.exe
Index  Algorithm  Timestamp    
========================================
SignTool Error: No signature found.

Number of errors: 1

    Signing vendored\protoc\yaakprotoc-x86_64-pc-windows-msvc.exe
    Signing vendored\protoc\yaakprotoc-x86_64-pc-windows-msvc.exe with a custom signing command
failed to bundle project: `failed to run trusted-signing-cli`
    Error failed to bundle project: `failed to run trusted-signing-cli`
Error: Command failed with exit code 1: npm run tauri build

Reproduction

As seen in the tauri.conf.json#L82, the sign command I'm using is:

"windows": {
  "signCommand": "trusted-signing-cli -e https://eus.codesigning.azure.net/ -a Yaak -c yaakapp %1"
}

To debug this, I created a new workflow to simply run this command on the protoc binary (committed it directly to the repo for simplicity), and it succeeded: https://github.com/mountain-loop/yaak/actions/runs/11975020946/job/33387429516

- name: Sign files
  run: trusted-signing-cli -e https://eus.codesigning.azure.net/ -a Yaak -c yaakapp yaakprotoc-x86_64-pc-windows-msvc.exe
  env:
    AZURE_CLIENT_ID: ${{ matrix.platform == 'windows-latest' && secrets.AZURE_CLIENT_ID }}
    AZURE_CLIENT_SECRET: ${{ matrix.platform == 'windows-latest' && secrets.AZURE_CLIENT_SECRET }}
    AZURE_TENANT_ID: ${{ matrix.platform == 'windows-latest' && secrets.AZURE_TENANT_ID }}

Expected behavior

protoc binary should sign successfully during tauri-action build

Full tauri info output

[✔] Environment
    - OS: Mac OS 15.1.1 arm64 (X64)
    ✔ Xcode Command Line Tools: installed
    ✔ rustc: 1.82.0 (f6e511eec 2024-10-15)
    ✔ cargo: 1.82.0 (8f40fc59f 2024-08-21)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-aarch64-apple-darwin (default)
    - node: 22.8.0
    - npm: 10.8.2
    - deno: deno 1.44.0

[-] Packages
    - tauri 🦀: 2.1.1
    - tauri-build 🦀: 2.0.3
    - wry 🦀: 0.47.0
    - tao 🦀: 0.30.8
    - @tauri-apps/api : 2.0.2 (outdated, latest: 2.1.1)
    - @tauri-apps/cli : 2.1.0

[-] Plugins
    - tauri-plugin-dialog 🦀: 2.0.3
    - @tauri-apps/plugin-dialog : 2.0.0 (outdated, latest: 2.0.1)
    - tauri-plugin-updater 🦀: 2.0.2
    - @tauri-apps/plugin-updater : not installed!
    - tauri-plugin-log 🦀: 2.0.1
    - @tauri-apps/plugin-log : 2.0.0
    - tauri-plugin-window-state 🦀: 2.0.1
    - @tauri-apps/plugin-window-state : not installed!
    - tauri-plugin-os 🦀: 2.0.1
    - @tauri-apps/plugin-os : 2.0.0
    - tauri-plugin-fs 🦀: 2.0.3
    - @tauri-apps/plugin-fs : 2.0.0 (outdated, latest: 2.0.2)
    - tauri-plugin-shell 🦀: 2.0.2
    - @tauri-apps/plugin-shell : 2.0.0 (outdated, latest: 2.0.1)

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist
    - devUrl: http://localhost:1420/
    - framework: React

Stack trace

No response

Additional context

No response

gschier commented 3 days ago

Okay, it looks like this was indeed my fault. However, it seems that Tauri did not surface the error that would have helped me fix it.

Running the sign command directly worked, because I committed the binary directly to the repo. I did this on macOS.

However, signing the full app downloads and extracts the protoc binary from a GitHub release. The issue was that it extracts with a read-only permission.

I adjusted the test workflow to use the download script and got this helpful error: https://github.com/mountain-loop/yaak/actions/runs/11987805359/job/33422398760

[
  {
    "cloudName": "AzureCloud",
    "homeTenantId": "***",
    "id": "b045e283-89f9-42ff-bd9a-95f6e7a9b035",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Yaak Subscription",
    "state": "Enabled",
    "tenantId": "***",
    "user": {
      "name": "***",
      "type": "servicePrincipal"
    }
  }
]

SignTool Error: Access is denied.
Number of files successfully Signed: 0
SignTool Error: An error occurred while attempting to sign: src-tauri/vendored/protoc/yaakprotoc-x86_64-pc-windows-msvc.exe

Number of warnings: 0

Number of errors: 1

thread 'main' panicked at C:\Users\runneradmin/.cargo\registry\src\index.crates.io-6f17d22bba15001f\trusted-signing-cli-0.3.0\src/main.rs:157:10:
called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "command [\"C:\\\\Program Files (x86)\\\\Windows Kits\\\\10\\\\bin\\\\10.0.22000.0\\\\x64\\\\signtool.exe\", \"sign\", \"/v\", \"/fd\", \"SHA256\", \"/tr\", \"[http://timestamp.acs.microsoft.com\](http://timestamp.acs.microsoft.com/)", \"/td\", \"SHA256\", \"/dlib\", \"C:\\\\Users\\\\runneradmin\\\\.trusted-signing-cli\\\\lib\\\\bin\\\\x64\\\\Azure.CodeSigning.Dlib.dll\", \"/dmdf\", \"C:\\\\Users\\\\runneradmin\\\\.trusted-signing-cli\\\\metadata.json\", \"src-tauri/vendored/protoc/yaakprotoc-x86_64-pc-windows-msvc.exe\"] exited with code 1" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Error: Process completed with exit code 1.

So it seems that Tauri is silencing stderr of the custom sign command?

FabianLars commented 3 days ago

So it seems that Tauri is silencing stderr of the custom sign command?

It may be hidden behind the --verbose flag (or -vv / -vvv, not sure if the verbosity level matters here) 🤔

gschier commented 3 days ago

Which command would that flag be on? Tauri should be running the same command as my test case

FabianLars commented 3 days ago

tauri build --verbose, or in tauri-action args: --verbose. The signCommand will be executed the same way, we'd just check if the tauri cli is hiding some command output from us.

gschier commented 1 day ago

Ah great, I will give this a try, thanks!