Sign Windows Theseus binaries with DigiCert KeyLocker's cloud HSM (#3838)

* feat(ci): sign Windows Theseus bins with DigiCert KeyLocker cloud HSM

* perf(ci): speed up Jsign installation

* fix(ci): use absolute path to DigiCert client certificate

This should avoid errors related to Jsign not being able to find it
we've seen on CI.

* fix(ci): trim strange characters out from DigiCert credentials

* ci: another attempt at fixing Jsign errors

* chore: add comment mentioning why `jsign` choco deps are ignored

* tweak: move KeyLocker signing config to CI release Tauri config file

This prevents casual local builds from attempting to use a signing
command they really can't use, improving developer experience.

* tweak(ci/windows): do not waste time and signatures with MSIs

We aren't distributing these anyway. This should reduce the signing
operations required for building the app from 5 (one for the binary,
another for the MSI installer, two for WiX extension DLLs and one for
the NSIS installer) to 2.

* feat(ci): make Windows code signing toggleable, do not sign non-final builds

* chore(ci): tweak `sign-windows-binaries` input wording

* fix(ci): deal with usual Powershell syntax shenanigans

* fix(ci): work around more Powershell syntax shenanigans

Who thought it'd be a good idea to make a comma a synonymous of a space
for separating command line arguments? Why have to characters for the
same thing?

* perf(ci): do not run app build workflow on Labrinth changes

Labrinth is not related to the app at all, so this is just a waste of CI
minutes.

* ci(theseus): enable Windows code signing by default for manual triggers

These are expected to be not that common, so defaulting to what causes
the least human errors when it comes to publishing a release makes most
sense.
This commit is contained in:
Alejandro González 2025-06-26 19:43:20 +02:00 committed by GitHub
parent 2d8420131d
commit b75cfc063b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 11 deletions

View File

@ -9,14 +9,18 @@ on:
- .github/workflows/theseus-release.yml - .github/workflows/theseus-release.yml
- 'apps/app/**' - 'apps/app/**'
- 'apps/app-frontend/**' - 'apps/app-frontend/**'
- 'apps/labrinth/src/common/**'
- 'apps/labrinth/Cargo.toml'
- 'packages/app-lib/**' - 'packages/app-lib/**'
- 'packages/app-macros/**' - 'packages/app-macros/**'
- 'packages/assets/**' - 'packages/assets/**'
- 'packages/ui/**' - 'packages/ui/**'
- 'packages/utils/**' - 'packages/utils/**'
workflow_dispatch: workflow_dispatch:
inputs:
sign-windows-binaries:
description: Sign Windows binaries
type: boolean
default: true
required: false
jobs: jobs:
build: build:
@ -103,11 +107,21 @@ jobs:
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev pkg-config libayatana-appindicator3-dev librsvg2-dev sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev pkg-config libayatana-appindicator3-dev librsvg2-dev
- name: Install code signing client (Windows only)
if: startsWith(matrix.platform, 'windows')
run: choco install jsign --ignore-dependencies # GitHub runners come with a global Java installation already
- name: Install frontend dependencies - name: Install frontend dependencies
run: pnpm install run: pnpm install
- name: Disable Windows code signing for non-final release builds
if: ${{ startsWith(matrix.platform, 'windows') && !startsWith(github.ref, 'refs/tags/v') && !inputs.sign-windows-binaries }}
run: |
jq 'del(.bundle.windows.signCommand)' apps/app/tauri-release.conf.json > apps/app/tauri-release.conf.json.new
Move-Item -Path apps/app/tauri-release.conf.json.new -Destination apps/app/tauri-release.conf.json -Force
- name: build app (macos) - name: build app (macos)
run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config "tauri-release.conf.json" run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json
if: startsWith(matrix.platform, 'macos') if: startsWith(matrix.platform, 'macos')
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -121,15 +135,29 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: build app - name: build app (Linux)
run: pnpm --filter=@modrinth/app run tauri build --config "tauri-release.conf.json" run: pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json
id: build_os if: startsWith(matrix.platform, 'ubuntu')
if: "!startsWith(matrix.platform, 'macos')"
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: build app (Windows)
run: |
[System.Convert]::FromBase64String("$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64") | Set-Content -Path signer-client-cert.p12 -AsByteStream
$env:DIGICERT_ONE_SIGNER_CREDENTIALS = "$env:DIGICERT_ONE_SIGNER_API_KEY|$PWD\signer-client-cert.p12|$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD"
pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles 'nsis,updater'
Remove-Item -Path signer-client-cert.p12
if: startsWith(matrix.platform, 'windows')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
DIGICERT_ONE_SIGNER_API_KEY: ${{ secrets.DIGICERT_ONE_SIGNER_API_KEY }}
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64 }}
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD }}
- name: upload ${{ matrix.platform }} - name: upload ${{ matrix.platform }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:

View File

@ -1,6 +1,24 @@
{ {
"bundle": { "bundle": {
"createUpdaterArtifacts": "v1Compatible" "createUpdaterArtifacts": "v1Compatible",
"windows": {
"signCommand": {
"cmd": "jsign",
"args": [
"sign",
"--verbose",
"--storetype",
"DIGICERTONE",
"--keystore",
"https://clientauth.one.digicert.com",
"--storepass",
"env:DIGICERT_ONE_SIGNER_CREDENTIALS",
"--tsaurl",
"https://timestamp.sectigo.com,http://timestamp.digicert.com",
"%1"
]
}
}
}, },
"build": { "build": {
"features": ["updater"] "features": ["updater"]

View File

@ -14,9 +14,6 @@
"externalBin": [], "externalBin": [],
"icon": ["icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"], "icon": ["icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
"windows": { "windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com",
"nsis": { "nsis": {
"installMode": "perMachine", "installMode": "perMachine",
"installerHooks": "./nsis/hooks.nsi" "installerHooks": "./nsis/hooks.nsi"