fix: allow running gateway service as root for LXC/container environments (#4732)
Previously, `hermes gateway install --system` hard-refused to create a service running as root, even when explicitly requested via `--run-as-user root`. This forced LXC/container users (where root is the only user) to either create throwaway users or comment out the check in source. Changes: - Auto-detected root (no explicit --run-as-user) still raises, but with a message explaining how to override - Explicit `--run-as-user root` now allowed with a warning about security implications - Interactive setup wizard prompt accepts 'root' as a valid username (warning comes from _system_service_identity downstream) - Added tests for all three paths: auto-detected root rejection, explicit root allowance, and normal non-root passthrough
This commit is contained in:
@@ -258,8 +258,11 @@ def _system_service_identity(run_as_user: str | None = None) -> tuple[str, str,
|
||||
username = (run_as_user or os.getenv("SUDO_USER") or os.getenv("USER") or os.getenv("LOGNAME") or getpass.getuser()).strip()
|
||||
if not username:
|
||||
raise ValueError("Could not determine which user the gateway service should run as")
|
||||
if username == "root" and not run_as_user:
|
||||
raise ValueError("Refusing to install the gateway system service as root; pass --run-as-user root to override (e.g. in LXC containers)")
|
||||
if username == "root":
|
||||
raise ValueError("Refusing to install the gateway system service as root; pass --run-as USER")
|
||||
print_warning("Installing gateway service to run as root.")
|
||||
print_info(" This is fine for LXC/container environments but not recommended on bare-metal hosts.")
|
||||
|
||||
try:
|
||||
user_info = pwd.getpwnam(username)
|
||||
@@ -321,9 +324,9 @@ def install_linux_gateway_from_setup(force: bool = False) -> tuple[str | None, b
|
||||
while True:
|
||||
run_as_user = prompt(" Run the system gateway service as which user?", default="")
|
||||
run_as_user = (run_as_user or "").strip()
|
||||
if run_as_user and run_as_user != "root":
|
||||
if run_as_user:
|
||||
break
|
||||
print_error(" Enter a non-root username.")
|
||||
print_error(" Enter a username.")
|
||||
|
||||
systemd_install(force=force, system=True, run_as_user=run_as_user)
|
||||
return scope, True
|
||||
|
||||
@@ -466,6 +466,51 @@ class TestGeneratedUnitIncludesLocalBin:
|
||||
assert "/.local/bin" in unit
|
||||
|
||||
|
||||
class TestSystemServiceIdentityRootHandling:
|
||||
"""Root user handling in _system_service_identity()."""
|
||||
|
||||
def test_auto_detected_root_is_rejected(self, monkeypatch):
|
||||
"""When root is auto-detected (not explicitly requested), raise."""
|
||||
import pwd
|
||||
import grp
|
||||
|
||||
monkeypatch.delenv("SUDO_USER", raising=False)
|
||||
monkeypatch.setenv("USER", "root")
|
||||
monkeypatch.setenv("LOGNAME", "root")
|
||||
|
||||
import pytest
|
||||
with pytest.raises(ValueError, match="pass --run-as-user root to override"):
|
||||
gateway_cli._system_service_identity(run_as_user=None)
|
||||
|
||||
def test_explicit_root_is_allowed(self, monkeypatch):
|
||||
"""When root is explicitly passed via --run-as-user root, allow it."""
|
||||
import pwd
|
||||
import grp
|
||||
|
||||
root_info = pwd.getpwnam("root")
|
||||
root_group = grp.getgrgid(root_info.pw_gid).gr_name
|
||||
|
||||
username, group, home = gateway_cli._system_service_identity(run_as_user="root")
|
||||
assert username == "root"
|
||||
assert home == root_info.pw_dir
|
||||
|
||||
def test_non_root_user_passes_through(self, monkeypatch):
|
||||
"""Normal non-root user works as before."""
|
||||
import pwd
|
||||
import grp
|
||||
|
||||
monkeypatch.delenv("SUDO_USER", raising=False)
|
||||
monkeypatch.setenv("USER", "nobody")
|
||||
monkeypatch.setenv("LOGNAME", "nobody")
|
||||
|
||||
try:
|
||||
username, group, home = gateway_cli._system_service_identity(run_as_user=None)
|
||||
assert username == "nobody"
|
||||
except ValueError as e:
|
||||
# "nobody" might not exist on all systems
|
||||
assert "Unknown user" in str(e)
|
||||
|
||||
|
||||
class TestEnsureUserSystemdEnv:
|
||||
"""Tests for _ensure_user_systemd_env() D-Bus session bus auto-detection."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user