fix(desktop): verify the installed payload before launching on Windows - #1439
Open
RainMona wants to merge 2 commits into
Open
fix(desktop): verify the installed payload before launching on Windows#1439RainMona wants to merge 2 commits into
RainMona wants to merge 2 commits into
Conversation
node-pty's build/**/obj trees and .exp/.iobj/.ipdb/.lib/.pdb/.tlog link outputs shipped inside app.asar and app.asar.unpacked (124 files in the 0.92.0 Windows installer). Only the .node/.dll/.exe outputs are runtime payload; the rest just widens the NSIS extraction surface. Co-authored-by: RainMona <RainMona@users.noreply.github.com>
Community reports of `Cannot find module 'fs-extra'` on Windows came
from installs whose resources tree was only partially extracted: the
0.91.x/0.92.0 installers ship the file, and electron-builder's NSIS
extraction falls back to a non-atomic 7z extract that ignores per-file
errors after its atomic copy fails (locked handles, antivirus, MAX_PATH).
Nothing checked the result, so the app started from a partial tree and
failed on the first missing module or toolchain.
- afterPack writes resources/openalice-integrity.json: version plus every
file under app.asar, app.asar.unpacked/ and runtime/ with its size.
- installer.nsh customInstall re-checks that inventory after extraction
and aborts (exit 3) with a reinstall message instead of handing off to
--force-run. customInit now waits up to 20 s for processes under
$INSTDIR to exit instead of sleeping one second before RD /S.
- The packaged desktop main verifies the inventory before resolving the
data home; a damaged install shows a reinstall dialog linking to the
latest release and quits. OPENALICE_DESKTOP_SKIP_INSTALL_INTEGRITY=1
bypasses it for diagnosis.
- assert-desktop-package validates the inventory against the unpacked
package and rejects node-pty compiler intermediates in the archive.
The helper PowerShell is written to $PLUGINSDIR one line per FileWrite so
NSIS string limits and $/${} expansion never touch the script body; the
inventory is parsed with JavaScriptSerializer because Windows PowerShell's
ConvertFrom-Json caps input near 2 MB and the inventory is ~1.7 MB.
Co-authored-by: RainMona <RainMona@users.noreply.github.com>
|
@cursoragent is attempting to deploy a commit to the luokerenx4's Team Team on Vercel. A member of the Team first needs to authorize it. |
luokerenx4
marked this pull request as ready for review
September 9, 2026 11:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Community reports of
A JavaScript error occurred in the main process — Cannot find module 'fs-extra'(require stackresources\app\node_modules\electron-updater\out\main.js) on Windows desktop.Root cause is not packaging. I unpacked the shipped NSIS installers from Linux (
7z x OpenAlice.Setup.<v>.exe '$PLUGINSDIR/app-64.7z'):fs-extrain payloadresources/app/(15 934 files)app.asarapp.asar+resources/runtime/(19 874 files)The module goes missing between the installer and disk. electron-builder's
extractUsing7zacopies the 7z output atomically with 5 retries, then on failure falls through to a directNsis7z::Extractthat ignores per-file errors (templates/nsis/include/extractAppPackage.nsh). In silent--updatedmode there is no user prompt, and--force-runthen launches whatever landed. Locked handles from Guardian children, antivirus scans of freshly extracted files, andMAX_PATHon long user profiles are the usual triggers. Nothing checked the result, so the first missing module or toolchain surfaced as an unrelated crash.The ASAR migration (#1406) removed the
node_moduleshalf of this surface.resources/runtime/still carries ~21k files (vendor/pi10 959,vendor/git10 427; longest relative path 183 chars), so the same interruption now shows up as a broken Pi or Git Bash instead of a missing module.What
afterPackinventory.scripts/desktop-after-pack.mjswritesresources/openalice-integrity.json(version + every file underapp.asar,app.asar.unpacked/,runtime/with byte size). Shared logic inscripts/desktop-install-integrity.mjs. ~1.7 MB for the 0.92.0 payload; collect 95 ms, verify 65 ms.installer.nshgainscustomInstall: after extraction and before electron-builder's force-run launch it re-checks the inventory via PowerShell and aborts (exit level 3, reinstall message) instead of handing off to a partial tree.customInitreplacesSleep 1000with a bounded wait (20 s) for processes under$INSTDIRto exit beforeRD /S /Q. Helper scripts are written to$PLUGINSDIRoneFileWriteper line so NSIS string limits and$/${}expansion never touch the script body; the inventory is parsed withJavaScriptSerializerbecause Windows PowerShell'sConvertFrom-Jsoncaps input near 2 MB (fallback toConvertFrom-Jsonwhen the assembly is unavailable).apps/desktop/src/install-integrity.ts; the packaged main process verifies the inventory before resolving the data home. Damaged → error dialog with the first missing/truncated paths, "Download installer" (opens latest release) / "Quit", result logged asinstall-integrityindesktop.log.OPENALICE_DESKTOP_SKIP_INSTALL_INTEGRITY=1bypasses for diagnosis.assert-desktop-packagevalidates the inventory against the unpacked package and rejects node-pty compiler intermediates in the archive.build/**/obj/**and.exp/.iobj/.ipdb/.lib/.pdb/.tlogundernode_modules/node-ptyare excluded (124 files in 0.92.0).Design choice recorded per AGENTS.md: a hard stop with a reinstall dialog rather than a "continue anyway" option, because a partial tree can fail later in a data-mutating path. This is an autonomous contribution; no maintainer approval is implied.
Verification
cd apps/desktop && npx tsc --noEmitclean (afterpnpm -F @traderalice/guardian-runtime build).pnpm test:owner:desktop: 18 files / 71 tests pass, including newinstall-integrity.spec.ts, inventory cases indesktop-after-pack.spec.tsandassert-desktop-package.spec.ts, and the installer contract indesktop-upgrade-smoke-lib.spec.ts(also asserts the helper bodies contain no${}/$(NSIS expansions).resources/tree, generated the inventory with the new hook logic, then ran the renderedopenalice-verify-install.ps1under PowerShell 7.6 on Linux: intact →checked 19874 files, problems 0exit 0 (1.7 s); after deletingpi-coding-agent/dist/cli.js, truncatingui/dist/index.htmland removingvendor/git/win32-x64/mingw64→problems 4555exit 1 with the first five paths; missing/corrupt inventory → exit 2.pnpm test:changed(the package.json change widens it to the full closure, 767 files): 764 pass; the 3 failing files (project-transfer*.spec.ts,template-upgrade.spec.ts,workspace-absorb.spec.ts) are git-heavy 5 s/10 s timeouts in this VM and untouched by this change.Residual risk
JavaScriptSerializerpath have not executed on Windows PowerShell 5.1; only the rendered script under pwsh 7 (which exercised theConvertFrom-Jsonfallback). The releasedesktop-upgrade-smokeonwindows-latest(previous release → candidate via realSetup.exe /S --updated) is the gate that runs bothcustomInitandcustomInstallfor real; a wrongAbortthere would fail that job, not ship.Contents/Resources, so it is covered by the signature; the startup check adds ~130 ms oflstaton 20k files before the data-home prompt.vendor/pi/node_modules/**/src/**/*.tssources account for the longest paths (183 chars); trimming them invendor-managed-runtime.mjswould lowerMAX_PATHexposure further.