fix(gateway): don't resolve node symlink into profile dir
generate_systemd_unit() and generate_launchd_plist() used
Path(shutil.which('node')).resolve().parent to find the node bin dir.
When ~/.local/bin/node is a symlink into a specific profile's node
install (e.g. ~/.hermes/profiles/<p>/node/bin/node), .resolve() chases
it and bakes that one profile's path into EVERY profile's service
definition.
This breaks profile isolation and makes systemd_unit_is_current()
perpetually False: each gateway rewrites its unit + daemon-reload on
every boot, destabilizing multi-profile setups into a ~5-minute restart
loop (observed NRestarts ~1600 across two gateways).
Fix: use Path(resolved_node).parent — the directory where node is found
on PATH — instead of chasing the symlink to its resolved target. This
keeps generated service definitions profile-agnostic.
Affects both the systemd (Linux) and launchd (macOS) unit generators.
This commit is contained in:
parent
50aaa426c1
commit
9138176dcd
1 changed files with 16 additions and 2 deletions
|
|
@ -2655,7 +2655,15 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None)
|
|||
path_entries = _build_service_path_dirs()
|
||||
resolved_node = shutil.which("node")
|
||||
if resolved_node:
|
||||
resolved_node_dir = str(Path(resolved_node).resolve().parent)
|
||||
# Use the directory where ``node`` is *found on PATH*, NOT the
|
||||
# symlink's resolved target. ``~/.local/bin/node`` is often a symlink
|
||||
# into a specific profile's node install (e.g. profiles/jarvis/node/
|
||||
# bin/node); calling .resolve() here would chase that symlink and bake
|
||||
# one profile's node path into *every* profile's service unit. That
|
||||
# cross-profile leak makes systemd_unit_is_current() perpetually false,
|
||||
# so each gateway rewrites its unit + daemon-reload on every boot. Using
|
||||
# the symlink's own parent keeps the generated unit profile-agnostic.
|
||||
resolved_node_dir = str(Path(resolved_node).parent)
|
||||
if resolved_node_dir not in path_entries:
|
||||
path_entries.append(resolved_node_dir)
|
||||
|
||||
|
|
@ -3807,7 +3815,13 @@ def generate_launchd_plist() -> str:
|
|||
priority_dirs = _build_service_path_dirs()
|
||||
resolved_node = shutil.which("node")
|
||||
if resolved_node:
|
||||
resolved_node_dir = str(Path(resolved_node).resolve().parent)
|
||||
# Use the directory where ``node`` is *found on PATH*, NOT the symlink's
|
||||
# resolved target. ``~/.local/bin/node`` is often a symlink into a
|
||||
# specific profile's node install; calling .resolve() would chase it and
|
||||
# bake one profile's path into every profile's service definition,
|
||||
# breaking profile isolation and causing perpetual unit rewrites. See
|
||||
# the matching fix in generate_systemd_unit().
|
||||
resolved_node_dir = str(Path(resolved_node).parent)
|
||||
if resolved_node_dir not in priority_dirs:
|
||||
priority_dirs.append(resolved_node_dir)
|
||||
sane_path = ":".join(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue