mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-27 11:22:03 +00:00
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:
parent
4a626ed187
commit
46e513ef51
3 changed files with 156 additions and 12 deletions
|
|
@ -204,6 +204,7 @@ import argparse
|
|||
import hashlib
|
||||
import json
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
|
@ -7113,6 +7114,45 @@ def _desktop_macos_relaunchable_fixup(desktop_dir: Path) -> None:
|
|||
except Exception as exc:
|
||||
print(f" (warning: macOS relaunch fixup skipped: {exc})")
|
||||
|
||||
|
||||
def _desktop_linux_sandbox_fixup(packaged_executable: Path) -> bool:
|
||||
"""Configure Electron's Linux SUID sandbox helper when required."""
|
||||
if sys.platform != "linux":
|
||||
return True
|
||||
|
||||
sandbox = packaged_executable.parent / "chrome-sandbox"
|
||||
if not sandbox.exists():
|
||||
print(f"✗ Hermes Desktop is missing Electron's Linux sandbox helper: {sandbox}")
|
||||
return False
|
||||
|
||||
# Reject symlinks — chown/chmod must not follow an attacker-controlled
|
||||
# link to an arbitrary path. Use lstat() so we inspect the link itself
|
||||
# rather than the target, and require a regular file.
|
||||
try:
|
||||
sandbox_lstat = sandbox.lstat()
|
||||
except OSError:
|
||||
print(f"✗ Cannot stat Electron's Linux sandbox helper: {sandbox}")
|
||||
return False
|
||||
if not stat.S_ISREG(sandbox_lstat.st_mode):
|
||||
print(f"✗ Electron's Linux sandbox helper is not a regular file: {sandbox}")
|
||||
return False
|
||||
|
||||
if sandbox_lstat.st_uid == 0 and stat.S_IMODE(sandbox_lstat.st_mode) == 0o4755:
|
||||
return True
|
||||
|
||||
sudo = shutil.which("sudo")
|
||||
if not sudo:
|
||||
print("✗ Hermes Desktop requires sudo to configure Electron's Linux sandbox helper.")
|
||||
return False
|
||||
|
||||
print("→ Configuring Electron Linux sandbox helper (sudo required)...")
|
||||
for command in ([sudo, "chown", "root:root", str(sandbox)], [sudo, "chmod", "4755", str(sandbox)]):
|
||||
if subprocess.run(command, check=False).returncode != 0:
|
||||
print(f"✗ Failed to configure Electron's Linux sandbox helper: {sandbox}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def cmd_gui(args: argparse.Namespace):
|
||||
"""Build and launch the native Electron desktop GUI."""
|
||||
desktop_dir = PROJECT_ROOT / "apps" / "desktop"
|
||||
|
|
@ -7238,6 +7278,9 @@ def cmd_gui(args: argparse.Namespace):
|
|||
print(" Expected an unpacked Electron app for the current OS.")
|
||||
sys.exit(1)
|
||||
|
||||
if not _desktop_linux_sandbox_fixup(packaged_executable):
|
||||
sys.exit(1)
|
||||
|
||||
print(f"→ Launching packaged Hermes Desktop: {packaged_executable}")
|
||||
launch_result = subprocess.run([str(packaged_executable)], cwd=desktop_dir, env=env, check=False)
|
||||
sys.exit(launch_result.returncode)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue