Files
omarchy-pkgs/pkgbuilds/hermes-desktop/runtime-test.py
T
Spencer BullandGPT-6 Codex 2fb9ab2ba9 Launch native Hermes without privileged sandbox setup
Use the same direct executable path for menu launches and URLs, require working user namespaces, and retain only the first-update relaunch gate backport. This avoids the upstream CLI fallback that makes a helper in the user runtime setuid-root.

Co-Authored-By: GPT-6 Codex (xhigh) <noreply@openai.com>
2026-09-07 03:17:42 -05:00

86 lines
4.1 KiB
Python

"""Check native launch and the release updater without running Hermes or sudo."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
source, patch_file, launcher = map(Path, sys.argv[1:])
with tempfile.TemporaryDirectory(prefix="hermes-runtime-check-") as temporary:
root = Path(temporary)
destination = root / "scripts/desktop-update/posix.sh"
destination.parent.mkdir(parents=True)
shutil.copyfile(source / "scripts/desktop-update/posix.sh", destination)
subprocess.run(["git", "apply", str(patch_file.resolve())], cwd=root, check=True)
home = root / "home with spaces"
runtime = home / ".hermes/hermes-agent"
native = runtime / "apps/desktop/release/linux-unpacked"
native.mkdir(parents=True)
executable = native / "Hermes"
executable.write_text(f"#!{sys.executable}\n" + '''import json, os, sys
from pathlib import Path
Path(os.environ["TEST_OUTPUT"]).write_text(json.dumps({
"args": sys.argv[1:], "home": os.environ["HERMES_HOME"],
"store": os.environ["HERMES_DESKTOP_PASSWORD_STORE"],
"gpu": os.environ.get("HERMES_DESKTOP_DISABLE_GPU"),
}))
''')
executable.chmod(0o755)
sandbox = native / "chrome-sandbox"
sandbox.write_text("fixture")
sandbox.chmod(0o755)
mock_bin = root / "bin"
mock_bin.mkdir()
unshare = mock_bin / "unshare"
unshare.write_text('#!/bin/bash\nexit "${TEST_NAMESPACE_RESULT:-0}"\n')
unshare.chmod(0o755)
forbidden = '#!/bin/bash\ntouch "$TEST_FORBIDDEN"\nexit 99\n'
cli = runtime / "venv/bin/hermes"
cli.parent.mkdir(parents=True)
cli.write_text(forbidden)
cli.chmod(0o755)
for command in ("sudo", "omarchy-install-hermes-cli"):
target = mock_bin / command
target.write_text(forbidden if command == "sudo" else '#!/bin/bash\nexit 0\n')
target.chmod(0o755)
output = root / "launch.json"
forbidden_output = root / "forbidden"
env = {"HOME": str(home), "PATH": f"{mock_bin}:/usr/bin:/bin",
"TEST_OUTPUT": str(output), "TEST_FORBIDDEN": str(forbidden_output)}
launch = ["bash", str(launcher.resolve())]
for args, overrides, expected_args, expected_store in (
([], {"WAYLAND_DISPLAY": "wayland-1"}, ["--ozone-platform=wayland"], "gnome-libsecret"),
(["--ozone-platform=x11", "hermes://open?text=a%20b"],
{"WAYLAND_DISPLAY": "wayland-1", "HERMES_DESKTOP_PASSWORD_STORE": "kwallet6"},
["--ozone-platform=x11", "hermes://open?text=a%20b"], "kwallet6"),
([], {"HERMES_HOME": str(home / ".hermes/profiles/work"), "HERMES_DESKTOP_DISABLE_GPU": "1"},
[], "gnome-libsecret"),
):
subprocess.run(launch + args, env={**env, **overrides}, check=True)
result = json.loads(output.read_text())
assert result["args"] == ["--disable-setuid-sandbox", *expected_args], result
assert result["home"] == str(home / ".hermes"), result
assert result["store"] == expected_store, result
assert result["gpu"] == overrides.get("HERMES_DESKTOP_DISABLE_GPU"), result
assert not forbidden_output.exists(), "launcher invoked CLI or sudo"
output.unlink()
for code in ("1", "127"):
for args in ([], ["hermes://open"]):
result = subprocess.run(launch + args, env={**env, "TEST_NAMESPACE_RESULT": code},
capture_output=True, text=True)
assert result.returncode != 0 and "user namespaces" in result.stderr, result
assert not output.exists() and not forbidden_output.exists()
gate = ["bash", str(destination), "--self-test-gate", "--install-root", str(runtime),
"--relaunch-target", str(executable)]
assert subprocess.check_output(gate, env=env, text=True).strip() == "relaunch"
assert subprocess.check_output(gate, env={**env, "TEST_NAMESPACE_RESULT": "1"}, text=True).startswith("manual:")
gate[-1] = "/opt/hermes-desktop/Hermes"
assert subprocess.check_output(gate, env=env, text=True).startswith("skew:")
print("PASS: direct native launches fail closed; release updater accepts the namespace sandbox")