fix(desktop): configure Linux Electron sandbox helper - #37529
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes Linux-specific issues when launching a locally built Electron desktop app by ensuring Electron’s chrome-sandbox helper is configured with the required root:root ownership and 4755 mode, and by updating the installer to recognize Linux unpacked desktop artifacts.
Changes:
- Add a Linux sandbox helper repair step to
hermes desktop/guibefore launching the packaged app. - Update
scripts/install.sh --include-desktopto detect Linux unpacked artifacts (not only macOS.app) and configurechrome-sandbox. - Add a regression test covering the Linux launcher sandbox repair path.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
tests/hermes_cli/test_gui_command.py |
Adds regression coverage asserting sudo chown/sudo chmod are invoked before launching on Linux. |
scripts/install.sh |
Detects Linux unpacked desktop output and attempts to configure chrome-sandbox after build. |
hermes_cli/main.py |
Implements Linux chrome-sandbox fixup in the packaged-app launch path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| sandbox = packaged_executable.parent / "chrome-sandbox" | ||
| if not sandbox.exists(): | ||
| print(f"✗ Hermes Desktop is missing Electron's Linux sandbox helper: {sandbox}") | ||
| return False | ||
|
|
||
| sandbox_stat = sandbox.stat() | ||
| if sandbox_stat.st_uid == 0 and stat.S_IMODE(sandbox_stat.st_mode) == 0o4755: | ||
| return True |
| if [ "$OS" = "linux" ]; then | ||
| local sandbox="$desktop_dir/release/linux-unpacked/chrome-sandbox" | ||
| if [ "$(id -u)" -eq 0 ]; then | ||
| chown root:root "$sandbox" && chmod 4755 "$sandbox" | ||
| elif command -v sudo >/dev/null 2>&1; then | ||
| sudo chown root:root "$sandbox" && sudo chmod 4755 "$sandbox" | ||
| else | ||
| log_error "Cannot configure Electron sandbox helper without sudo: $sandbox" | ||
| return 1 | ||
| fi | ||
| fi |
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).
|
Flagging a design concern on the launch-path fixup before this lands (Ari is picking this up). The core issue: the launcher must not depend on sudo being obtainable.
We can't assume root is reachable, so auto-sudo can't be the default launch behavior. The clean alternative (zero-root) is not reliably available either. Modern Electron sandboxes via unprivileged user namespaces with no SUID helper at all — but you can't detect availability from sysctls; the knobs lie. Probed on a stock Ubuntu 24.04 box: So userns is blocked out of the box on current Ubuntu defaults, and the only way to know is a runtime Suggested launch logic (never spawns sudo itself):
Principle: the launcher detects and informs; it never assumes root is obtainable and never escalates on the user's behalf. The Context: reported on Discord — Linux users currently have to run the manual chown/chmod dance, which is what motivated this PR. The fix is right to pursue; it just shouldn't require sudo at launch. |
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
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 NousResearch#37529 (rebased, merge conflicts resolved, copilot review feedback addressed).
Why
hermes desktopbuilds an unpacked Electron app on Linux, but Electron's generatedchrome-sandboxhelper is user-owned with mode755. Chromium aborts before the desktop app starts unless that helper is owned byrootwith mode4755.The existing
install.sh --include-desktoppath was also macOS-only after the build step: it searched only forHermes.app, so a successful Linux build was reported as missing.What changed
root:root 4755before launching a locally built desktop app.install.sh --include-desktopand configure its sandbox helper after build.Verification
bash -n scripts/install.shpython -m pytest tests/hermes_cli/test_gui_command.py -qpython -m pytest tests/test_install_sh_setup_wizard_tty_probe.py tests/test_install_sh_root_fhs_uv_python_path.py tests/test_install_sh_symlink_stomp.py -q755helper and confirmedhermes desktop --skip-buildrepairs it and launches the sandboxed Electron process.