fix(desktop): disable signtool via signtoolOptions.sign=null, drop dead winCodeSign pre-extract

VM run 5 diagnosis: the pre-extract from 3b29e65c1 ran (extracted 83
files, 24MB) but produced ZERO files at the expected sentinel path
'/winCodeSign-2.6.0/windows-10/x64/signtool.exe'.

Cause: the .7z archive's root entries are 'windows-10/', 'darwin/',
'linux/', etc. — not 'winCodeSign-2.6.0/<arch>'. Extracting with
'-o$cacheRoot' put files at $cacheRoot/windows-10/..., NOT at
$cacheRoot/winCodeSign-2.6.0/windows-10/.... I had the directory
nesting wrong from the start.

And then we observed: electron-builder downloads winCodeSign-2.6.0.7z
under a random numeric filename ('384387955.7z') regardless of what's
already extracted in the parent dir. The cache key isn't the dirname;
it's content-addressed. So the pre-extract approach was doomed even
if the path nesting had been right.

Actual fix: signtoolOptions.sign=null in apps/desktop/package.json's
win build config. electron-builder honors this and skips the bundled-
prebuild signing entirely — no signtool invocation, no winCodeSign
fetch, no symlink-privilege crash. The previous failures all stemmed
from electron-builder pre-signing node-pty's bundled .exes
(winpty-agent.exe, OpenConsole.exe) which are already author-signed
upstream; re-signing with our nonexistent cert was overwriting good
sigs with nothing useful anyway.

Cost: when we DO get a real cert later, we'll add it back with the
sign function pointing at the cert chain. Until then, all-null is
the correct config and unblocks every non-admin Windows user.

Removed Initialize-ElectronBuilderCache (the dead pre-extract).
Removed the call site. Kept the CSC_IDENTITY_AUTO_DISCOVERY env
vars as belt-and-suspenders against a future electron-builder
change that might revive cert auto-discovery.
This commit is contained in:
emozilla
2026-05-28 11:42:40 -04:00
parent 3b29e65c1b
commit 3387b8df58
2 changed files with 4 additions and 93 deletions
+4 -1
View File
@@ -200,7 +200,10 @@
"target": [
"nsis",
"msi"
]
],
"signtoolOptions": {
"sign": null
}
},
"nsis": {
"oneClick": false,
-92
View File
@@ -1844,87 +1844,6 @@ function Install-NodeDeps {
}
}
function Initialize-ElectronBuilderCache {
# Pre-warm electron-builder's winCodeSign cache so its own extraction
# of the .7z archive never runs.
#
# Why this exists: even when no signing cert is configured (we set
# CSC_IDENTITY_AUTO_DISCOVERY=false below), electron-builder still
# invokes signtool on node-pty's bundled prebuilt binaries
# (winpty-agent.exe, OpenConsole.exe) because they live under
# asarUnpack: ['**/*.node', '**/prebuilds/**'] in apps/desktop's
# package.json. signtool ships inside winCodeSign-2.6.0.7z, so
# electron-builder fetches and extracts the archive.
#
# The archive contains macOS symbolic links under darwin/10.12/lib/
# (libcrypto.dylib + libssl.dylib pointing at versioned siblings).
# Creating symlinks on Windows requires SeCreateSymbolicLinkPrivilege,
# which non-admin accounts on stock Windows don't have. Result:
# 7-Zip exit 2 on every grandma-class box, four retries, then the
# whole build fails.
#
# The fix: do the extraction ourselves with -snl (don't preserve
# symlinks — store as resolved file content) AND -x!darwin (skip
# the macOS subtree entirely — we're building for Windows). With
# the cache directory populated, electron-builder's "is the cache
# present?" check passes and it never runs its own extraction.
#
# Idempotent: fast-path returns if winCodeSign-2.6.0/windows-10/x64/
# signtool.exe already exists. Tooling: uses 7za.exe from the
# 7zip-bin npm dep (which electron-builder itself depends on, so
# it's present after the workspace npm install completed).
$cacheRoot = "$env:LOCALAPPDATA\electron-builder\Cache\winCodeSign"
$extractedDir = "$cacheRoot\winCodeSign-2.6.0"
$sentinel = "$extractedDir\windows-10\x64\signtool.exe"
if (Test-Path $sentinel) {
Write-Info "electron-builder winCodeSign cache already populated"
return
}
$sevenZip = "$InstallDir\node_modules\7zip-bin\win\x64\7za.exe"
if (-not (Test-Path $sevenZip)) {
$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"
return
}
New-Item -ItemType Directory -Force -Path $cacheRoot | Out-Null
$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 (skips electron-builder's broken-on-Windows extraction)..."
try {
Invoke-WebRequest -Uri $url -OutFile $tmpArchive -UseBasicParsing -ErrorAction Stop
} catch {
Write-Warn "Failed to download winCodeSign: $_"
return
}
$prevEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& $sevenZip x -y -bd -snl "-x!darwin" "-o$cacheRoot" $tmpArchive 2>&1 | ForEach-Object { "$_" }
$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 {
# Build apps/desktop into a launchable Hermes.exe. Only called from
# Stage-Desktop, which is itself only included in the manifest when
@@ -2009,17 +1928,6 @@ function Install-Desktop {
}
Pop-Location
# Pre-warm electron-builder's winCodeSign cache. MUST happen after the
# workspace npm install (we need 7za.exe from 7zip-bin) but BEFORE
# `npm run pack` (electron-builder pre-fetches signtool for re-signing
# node-pty's bundled prebuilds; if its own 7-Zip extraction runs first
# we hit the symlink-privilege crash). Belt-and-suspenders with the
# CSC_IDENTITY_AUTO_DISCOVERY env vars below: those kill cert
# discovery (so no signing actually happens to OUR Hermes.exe),
# while the pre-extract handles the toolchain fetch that still fires
# for the bundled-prebuild re-sign. Both are needed.
Initialize-ElectronBuilderCache
# 2. Build apps/desktop. `npm run pack` runs:
# assert-root-install + write-build-stamp + stage-native-deps +
# tsc -b + vite build + electron-builder --dir