fix(desktop): configure Linux Electron sandbox helper

Electron's chrome-sandbox helper must be root:root 4755 on Linux or the
sandboxed renderer aborts before the desktop app starts. The existing
installer only searched for macOS .app bundles, so a successful Linux
build was reported as missing.

Changes:
- Add _desktop_linux_sandbox_fixup() to hermes_cli/main.py, called
  before launching a packaged desktop app on Linux.
- Use lstat() + S_ISREG check to reject symlinks — chown/chmod on a
  symlink target would set SUID on an arbitrary path.
- Update install.sh to recognize Linux unpacked artifacts and configure
  chrome-sandbox with proper error handling (the original PR silently
  ignored chown/chmod failures).
- Add regression tests: normal fixup flow, symlink rejection, and
  already-configured skip path.

Closes #37529 (rebased, merge conflicts resolved, copilot review
feedback addressed).
This commit is contained in:
ethernet
2026-06-02 18:18:28 -04:00
parent 4a626ed187
commit 46e513ef51
3 changed files with 156 additions and 12 deletions

View File

@ -2222,10 +2222,10 @@ postinstall_mode() {
fi
}
# Build apps/desktop into a launchable Hermes.app. Mirrors install.ps1's
# Build apps/desktop into a launchable native app. Mirrors install.ps1's
# Install-Desktop: a root-level npm install so the apps/* workspace resolves
# the desktop's own deps (Electron ~150MB), then `npm run pack`
# (electron-builder --dir) which emits release/mac*/Hermes.app. Only invoked
# (electron-builder --dir) which emits an unpacked app for the current OS. Only invoked
# via the 'desktop' stage / --include-desktop, which the Electron app's own
# first-launch bootstrap never requests (it must not rebuild itself).
install_desktop() {
@ -2261,7 +2261,7 @@ install_desktop() {
log_success "Desktop workspace dependencies installed"
# 2. Build. `npm run pack` = tsc + vite build + electron-builder --dir,
# producing an unpacked release/mac*/Hermes.app. We disable signing
# producing an unpacked app for the current OS. We disable signing
# auto-discovery so electron-builder falls back to an ad-hoc signature
# instead of grabbing an unrelated Developer ID from the keychain; a
# real signed/notarized .dmg needs Apple credentials and is a separate
@ -2274,21 +2274,53 @@ install_desktop() {
}
local app=""
local cand
for cand in \
"$desktop_dir/release/mac-arm64/Hermes.app" \
"$desktop_dir/release/mac/Hermes.app"; do
if [ -d "$cand" ]; then
app="$cand"
break
if [ "$OS" = "linux" ]; then
if [ -x "$desktop_dir/release/linux-unpacked/Hermes" ]; then
app="$desktop_dir/release/linux-unpacked/Hermes"
elif [ -x "$desktop_dir/release/linux-unpacked/hermes" ]; then
app="$desktop_dir/release/linux-unpacked/hermes"
fi
done
else
local cand
for cand in \
"$desktop_dir/release/mac-arm64/Hermes.app" \
"$desktop_dir/release/mac/Hermes.app"; do
if [ -d "$cand" ]; then
app="$cand"
break
fi
done
fi
if [ -z "$app" ]; then
log_error "Desktop build completed but no Hermes.app was found under $desktop_dir/release/"
log_error "Desktop build completed but no app was found under $desktop_dir/release/"
return 1
fi
log_success "Desktop app built: $app"
# Linux: Electron's chrome-sandbox helper needs root:root 4755 or the
# sandboxed renderer will abort on startup. Check the file is a regular
# file (not a symlink) before chown/chmod so we don't follow an
# attacker-controlled link to an arbitrary path.
if [ "$OS" = "linux" ]; then
local sandbox="$desktop_dir/release/linux-unpacked/chrome-sandbox"
if [ -f "$sandbox" ] && [ ! -L "$sandbox" ]; then
if [ "$(id -u)" -eq 0 ]; then
chown root:root "$sandbox" && chmod 4755 "$sandbox" || {
log_error "Cannot configure Electron sandbox helper: $sandbox"
return 1
}
elif command -v sudo >/dev/null 2>&1; then
sudo chown root:root "$sandbox" && sudo chmod 4755 "$sandbox" || {
log_error "Cannot configure Electron sandbox helper (sudo failed): $sandbox"
return 1
}
else
log_error "Cannot configure Electron sandbox helper without sudo: $sandbox"
return 1
fi
fi
fi
# macOS: make the locally-built (ad-hoc) app relaunchable after an in-place
# self-update. An ad-hoc bundle has no stable Designated Requirement, so a
# later in-place rebuild (new cdhash) plus the inherited quarantine flag