Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,33 @@ jobs:

- name: Configure Tauri Windows signCommand
if: matrix.platform == 'windows-latest' && env.JSIGN_PATH != ''
shell: bash
shell: pwsh
run: |
cat > signing.conf.json << 'EOF'
{
"bundle": {
"windows": {
"signCommand": {
"cmd": "pwsh",
"args": ["-File", "scripts/sign-windows.ps1", "%1"]
}
# Resolve absolute paths — Tauri's bundler uses std::process::Command
# (no shell) so bare names like 'pwsh' fail PATH lookup on Windows.
$pwshPath = (Get-Command pwsh).Source -replace '\\', '/'
$scriptPath = (Resolve-Path "scripts/sign-windows.ps1").Path -replace '\\', '/'
$config = @{
bundle = @{
windows = @{
signCommand = @{
cmd = $pwshPath
args = @("-File", $scriptPath, "%1")
}
}
}
}
}
EOF
echo "SIGNING_ARGS=--config signing.conf.json" >> "$GITHUB_ENV"
} | ConvertTo-Json -Depth 10
$config | Set-Content signing.conf.json
Write-Host "signing.conf.json:"
Get-Content signing.conf.json
Add-Content -Path $env:GITHUB_ENV -Value "SIGNING_ARGS=--config signing.conf.json"

- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Enable bundler debug logging — sign command stdout/stderr is
# swallowed on failure; RUST_LOG surfaces the command invocation.
RUST_LOG: tauri_bundler=debug
# macOS signing & notarization (optional — skipped if not set)
APPLE_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
Expand All @@ -127,3 +135,27 @@ jobs:
releaseDraft: true
prerelease: false
args: ${{ matrix.args }} ${{ env.SIGNING_ARGS }}

# Dump sign script log on failure — Tauri bundler swallows subprocess
# stdout/stderr when the sign command exits non-zero, making failures
# invisible. The script writes a transcript to $RUNNER_TEMP/sign-windows.log.
- name: Dump signing log on failure
if: failure() && matrix.platform == 'windows-latest'
shell: pwsh
run: |
$logFile = Join-Path $env:RUNNER_TEMP "sign-windows.log"
if (Test-Path $logFile) {
Write-Host "=== sign-windows.log ==="
Get-Content $logFile
Write-Host "=== end sign-windows.log ==="
} else {
Write-Host "No sign-windows.log found at $logFile"
Write-Host "Sign script may not have been invoked, or RUNNER_TEMP differs."
Write-Host "Checking TEMP fallback..."
$fallback = Join-Path $env:TEMP "sign-windows.log"
if (Test-Path $fallback) {
Get-Content $fallback
} else {
Write-Host "No log file found at $fallback either."
}
}
74 changes: 69 additions & 5 deletions scripts/sign-windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#
# Called by Tauri as: pwsh -File scripts/sign-windows.ps1 <file_path>
#
# NOTE: Tauri's bundler swallows stdout/stderr from sign commands on failure
# (output_ok() discards output on non-zero exit). All diagnostic output is
# tee'd to a log file so a post-failure workflow step can dump it.
#
# Required environment variables:
# JSIGN_PATH - Path to jsign JAR file
# EV_KEYSTORE - GCP Cloud KMS keystore URL
Expand All @@ -16,9 +20,20 @@ param(
[string]$FilePath
)

# Log to file since Tauri bundler discards subprocess output on failure
$logDir = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP }
$logFile = Join-Path $logDir "sign-windows.log"
Start-Transcript -Path $logFile -Append -Force | Out-Null

Write-Host "=== sign-windows.ps1 started at $(Get-Date -Format o) ==="
Write-Host "FilePath: $FilePath"
Write-Host "PID: $PID"
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"

# Check if signing is configured
if (-not $env:JSIGN_PATH -or -not $env:EV_KEYSTORE) {
Write-Host "Windows code signing not configured - skipping $FilePath"
Stop-Transcript | Out-Null
exit 0
}

Expand All @@ -33,10 +48,47 @@ $requiredVars = @(
)

foreach ($varName in $requiredVars) {
if (-not [System.Environment]::GetEnvironmentVariable($varName)) {
$val = [System.Environment]::GetEnvironmentVariable($varName)
if (-not $val) {
Write-Error "Missing required environment variable: $varName"
Stop-Transcript | Out-Null
exit 1
}
# Log presence without leaking secrets
$display = if ($varName -eq "GCLOUD_ACCESS_TOKEN") { "***($($val.Length) chars)" } else { $val }
Write-Host "${varName}: $display"
}

# Verify file exists
if (-not (Test-Path $FilePath)) {
Write-Error "File not found: $FilePath"
Stop-Transcript | Out-Null
exit 1
}
Write-Host "File exists: $FilePath ($($(Get-Item $FilePath).Length) bytes)"

# Verify java is available
$javaCmd = Get-Command java -ErrorAction SilentlyContinue
if (-not $javaCmd) {
Write-Error "java not found in PATH"
Write-Host "PATH: $env:PATH"
Stop-Transcript | Out-Null
exit 1
}
Write-Host "Java: $($javaCmd.Source)"

# Verify jsign jar exists
if (-not (Test-Path $env:JSIGN_PATH)) {
Write-Error "jsign jar not found: $env:JSIGN_PATH"
Stop-Transcript | Out-Null
exit 1
}

# Verify certificate exists
if (-not (Test-Path $env:EV_CERTIFICATE_PATH)) {
Write-Error "Certificate file not found: $env:EV_CERTIFICATE_PATH"
Stop-Transcript | Out-Null
exit 1
}

Write-Host "Signing $FilePath with EV certificate..."
Expand All @@ -53,10 +105,22 @@ $jsignArgs = @(
$FilePath
)

& java @jsignArgs
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to sign $FilePath (exit code: $LASTEXITCODE)"
exit 1
# Log the command (mask the access token)
$displayArgs = $jsignArgs.Clone()
$storepassIdx = [Array]::IndexOf($displayArgs, "--storepass")
if ($storepassIdx -ge 0 -and ($storepassIdx + 1) -lt $displayArgs.Length) {
$displayArgs[$storepassIdx + 1] = "***"
}
Write-Host "Running: java $($displayArgs -join ' ')"

& java @jsignArgs 2>&1 | ForEach-Object { Write-Host $_ }
$exitCode = $LASTEXITCODE

if ($exitCode -ne 0) {
Write-Error "Failed to sign $FilePath (exit code: $exitCode)"
Stop-Transcript | Out-Null
exit $exitCode
}

Write-Host "Successfully signed $FilePath"
Stop-Transcript | Out-Null
Loading