fix(install.ps1): tell electron-builder we're NOT signing instead of pre-extracting winCodeSign

The previous commit (c7e46f9f3) worked around the winCodeSign-symlinks-
on-Windows extraction crash by pre-extracting the archive ourselves with
-snl + -x!darwin. That fix was correct but addressed the wrong layer.

The deeper question: why was electron-builder fetching winCodeSign at all
when we have no signing cert configured? Answer: electron-builder
unconditionally pre-warms the toolchain assuming any build MIGHT sign.
The cert auto-discovery never finds anything (we never set CSC_LINK
or anything else), so the signing never happens — but the 100MB fetch
of winCodeSign and its broken-on-Windows symlink extraction does.

Set CSC_IDENTITY_AUTO_DISCOVERY=false (with WIN_CSC_LINK and
WIN_CSC_KEY_PASSWORD also explicitly cleared as belt-and-suspenders)
before invoking npm run pack, and electron-builder skips the entire
winCodeSign apparatus. No download, no extraction, no privilege check.
Env vars are saved/restored around the invocation so we don't leak
the override into Stage-PlatformSdks etc.

Net: removes the 100-line Initialize-ElectronBuilderCache helper that
manually downloaded + extracted winCodeSign-2.6.0.7z. Replaced with
3 env-var assignments. The produced Hermes.exe is functionally
identical — just no longer carries a code-signing-machinery dependency
we never used.
This commit is contained in:
emozilla 2026-05-28 10:37:07 -04:00
parent c7e46f9f3d
commit d5fe467277

View file

@ -1837,106 +1837,6 @@ function Install-NodeDeps {
} }
} }
function Initialize-ElectronBuilderCache {
# Pre-warm electron-builder's winCodeSign cache so it never tries to
# extract the .7z archive itself.
#
# The bug we're working around: winCodeSign-2.6.0.7z contains macOS
# symbolic links under darwin/10.12/lib/ (libcrypto.dylib, libssl.dylib
# pointing at versioned siblings). On Windows, 7-Zip's extraction of
# those symlinks requires SeCreateSymbolicLinkPrivilege — a per-user
# right that non-admin accounts on stock Windows don't have. So
# electron-builder fails the extraction every time it pulls a fresh
# cache, on every grandma-class box.
#
# The fix: do the extraction ourselves with `-x!darwin` to skip the
# entire macOS subtree. electron-builder is doing a WINDOWS build —
# it never reads anything under darwin/ on this code path. As long
# as the cache directory exists with the Windows-relevant files,
# electron-builder's "is the cache present?" check passes and it
# skips its own extraction entirely.
#
# Tooling: we use 7za.exe from the 7zip-bin npm package that
# electron-builder itself depends on (so we know it's present after
# the workspace `npm install` finishes). Falls back to no-op if
# neither is found — electron-builder will then attempt its own
# broken extraction and fail with a recognizable error.
$cacheRoot = "$env:LOCALAPPDATA\electron-builder\Cache\winCodeSign"
$extractedDir = "$cacheRoot\winCodeSign-2.6.0"
$sentinel = "$extractedDir\windows-10\x64\signtool.exe"
# Fast-path: already populated from a prior run.
if (Test-Path $sentinel) {
Write-Info "electron-builder winCodeSign cache already populated"
return
}
# Locate 7za.exe. electron-builder hoists 7zip-bin to the workspace
# root node_modules so apps/desktop's pack step can find it.
$sevenZip = "$InstallDir\node_modules\7zip-bin\win\x64\7za.exe"
if (-not (Test-Path $sevenZip)) {
# Some npm versions don't hoist; check apps/desktop's local copy.
$sevenZip = "$InstallDir\apps\desktop\node_modules\7zip-bin\win\x64\7za.exe"
}
if (-not (Test-Path $sevenZip)) {
Write-Warn "7za.exe not found in node_modules; electron-builder may fail to extract winCodeSign"
Write-Warn " Looked at: $InstallDir\node_modules\7zip-bin\win\x64\7za.exe"
Write-Warn " and: $InstallDir\apps\desktop\node_modules\7zip-bin\win\x64\7za.exe"
return
}
New-Item -ItemType Directory -Force -Path $cacheRoot | Out-Null
# Download to a TEMP path; electron-builder doesn't care about the
# archive itself once the extracted dir exists.
$tmpArchive = "$env:TEMP\hermes-wincodesign-$(Get-Random).7z"
$url = "https://github.com/electron-userland/electron-builder-binaries/releases/download/winCodeSign-2.6.0/winCodeSign-2.6.0.7z"
Write-Info "Pre-extracting winCodeSign to skip electron-builder's broken extraction..."
try {
Invoke-WebRequest -Uri $url -OutFile $tmpArchive -UseBasicParsing -ErrorAction Stop
} catch {
Write-Warn "Failed to download winCodeSign: $_"
Write-Warn " electron-builder will fall back to its own extraction (which fails on non-admin Windows)"
return
}
# 7-Zip flags:
# x extract with full paths
# -y assume yes on all prompts
# -bd no progress bar (silent)
# -snl do NOT extract symbolic links as links — store as the
# resolved file content instead. This is what stops the
# privilege-not-held crash on the darwin/*.dylib symlinks.
# -x!darwin exclude the entire darwin/ subtree (macOS-specific
# code-signing tools that a Windows build doesn't need)
# -o<dir> output directory
#
# Belt-and-suspenders: we BOTH skip the darwin subtree AND tell 7-Zip
# to dereference any remaining symlinks. Either alone would fix it;
# together they're defensive against winCodeSign adding more symlinks
# under linux/ or appxAssets/ in some future release.
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& $sevenZip x -y -bd -snl "-x!darwin" "-o$cacheRoot" $tmpArchive 2>&1 | Out-Null
$code = $LASTEXITCODE
$ErrorActionPreference = $prevEAP
Remove-Item -Force $tmpArchive -ErrorAction SilentlyContinue
if ($code -ne 0) {
Write-Warn "Pre-extraction of winCodeSign failed (7-Zip exit $code)"
return
}
if (Test-Path $sentinel) {
Write-Success "winCodeSign cache pre-populated at $extractedDir"
} else {
Write-Warn "winCodeSign extraction completed but expected file is missing: $sentinel"
}
}
function Install-Desktop { function Install-Desktop {
# Build apps/desktop into a launchable Hermes.exe. Only called from # Build apps/desktop into a launchable Hermes.exe. Only called from
# Stage-Desktop, which is itself only included in the manifest when # Stage-Desktop, which is itself only included in the manifest when
@ -2019,13 +1919,6 @@ function Install-Desktop {
} }
Pop-Location Pop-Location
# Pre-warm electron-builder's winCodeSign cache so its own broken
# 7-Zip extraction doesn't fire later. Has to happen AFTER the
# workspace npm install (we need 7za.exe from 7zip-bin) but BEFORE
# `npm run pack` (which triggers electron-builder's first cache miss).
# See Initialize-ElectronBuilderCache for the full rationale.
Initialize-ElectronBuilderCache
# 2. Build apps/desktop. `npm run pack` runs: # 2. Build apps/desktop. `npm run pack` runs:
# assert-root-install + write-build-stamp + stage-native-deps + # assert-root-install + write-build-stamp + stage-native-deps +
# tsc -b + vite build + electron-builder --dir # tsc -b + vite build + electron-builder --dir
@ -2033,12 +1926,31 @@ function Install-Desktop {
# apps/desktop/release/win-unpacked/ without bundling NSIS/MSI; # apps/desktop/release/win-unpacked/ without bundling NSIS/MSI;
# we don't need a distributable installer artifact, just a # we don't need a distributable installer artifact, just a
# launchable binary the Tauri installer can spawn. # launchable binary the Tauri installer can spawn.
#
# CSC_IDENTITY_AUTO_DISCOVERY=false tells electron-builder we are
# NOT signing the output. This short-circuits the winCodeSign fetch +
# extraction entirely (which fails on non-admin Windows due to a
# macOS-symlink extraction crash electron-builder hasn't fixed in
# years). We never had a signing cert to use, so the apparatus was
# dead weight that broke fresh installs. The produced Hermes.exe
# is functionally identical — just unsigned, same as it would be
# if signing had been attempted but no cert was configured.
#
# WIN_CSC_LINK and WIN_CSC_KEY_PASSWORD explicitly cleared as
# belt-and-suspenders: if the user's environment has them set
# for some other tool, electron-builder would still try to sign.
Write-Info "Building desktop app (this takes 1-3 minutes)..." Write-Info "Building desktop app (this takes 1-3 minutes)..."
$buildLog = "$env:TEMP\hermes-desktop-build-$(Get-Random).log" $buildLog = "$env:TEMP\hermes-desktop-build-$(Get-Random).log"
Push-Location $desktopDir Push-Location $desktopDir
$prevEAP = $ErrorActionPreference $prevEAP = $ErrorActionPreference
$prevCSCAuto = $env:CSC_IDENTITY_AUTO_DISCOVERY
$prevWinCscLink = $env:WIN_CSC_LINK
$prevWinCscKeyPassword = $env:WIN_CSC_KEY_PASSWORD
try { try {
$ErrorActionPreference = "Continue" $ErrorActionPreference = "Continue"
$env:CSC_IDENTITY_AUTO_DISCOVERY = "false"
$env:WIN_CSC_LINK = ""
$env:WIN_CSC_KEY_PASSWORD = ""
& $npmExe run pack 2>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath $buildLog & $npmExe run pack 2>&1 | ForEach-Object { "$_" } | Tee-Object -FilePath $buildLog
$code = $LASTEXITCODE $code = $LASTEXITCODE
$ErrorActionPreference = $prevEAP $ErrorActionPreference = $prevEAP
@ -2058,6 +1970,13 @@ function Install-Desktop {
if ($prevEAP) { $ErrorActionPreference = $prevEAP } if ($prevEAP) { $ErrorActionPreference = $prevEAP }
Pop-Location Pop-Location
throw throw
} finally {
# Restore env to whatever the caller had — don't leak our
# signing-off override into anything install.ps1 invokes later
# (Stage-PlatformSdks, etc.).
$env:CSC_IDENTITY_AUTO_DISCOVERY = $prevCSCAuto
$env:WIN_CSC_LINK = $prevWinCscLink
$env:WIN_CSC_KEY_PASSWORD = $prevWinCscKeyPassword
} }
Pop-Location Pop-Location