mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-23 16:36:23 +00:00
fix(gateway): guard acquire_gateway_runtime_lock against root-owned lock PermissionError
Widen the PermissionError handling from is_gateway_runtime_lock_active (#42689) to the sibling open() in acquire_gateway_runtime_lock: a stale root-owned gateway.lock left by a launchd Background session previously crashed the acquiring process. Unlink the stale file and retry once; if the unlink or retry fails, return False cleanly instead of raising.
This commit is contained in:
parent
6f50c5607b
commit
35fb2e428a
2 changed files with 72 additions and 1 deletions
|
|
@ -799,7 +799,22 @@ def acquire_gateway_runtime_lock() -> bool:
|
|||
|
||||
path = _get_gateway_lock_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
handle = open(path, "a+", encoding="utf-8")
|
||||
try:
|
||||
handle = open(path, "a+", encoding="utf-8")
|
||||
except PermissionError:
|
||||
# Stale root-owned lock file from a previous launchd Background
|
||||
# session that ran as root (same failure mode handled in
|
||||
# is_gateway_runtime_lock_active). The parent directory owner can
|
||||
# unlink files even when they don't own them, so remove the stale
|
||||
# lock and retry once with a fresh file.
|
||||
try:
|
||||
path.unlink()
|
||||
except OSError:
|
||||
return False
|
||||
try:
|
||||
handle = open(path, "a+", encoding="utf-8")
|
||||
except OSError:
|
||||
return False
|
||||
if not _try_acquire_file_lock(handle):
|
||||
handle.close()
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1805,3 +1805,59 @@ class TestPermissionErrorOnLockFile:
|
|||
|
||||
result = status.is_gateway_runtime_lock_active(lock_path)
|
||||
assert result is False
|
||||
|
||||
def test_acquire_gateway_runtime_lock_recovers_from_permission_error(self, tmp_path, monkeypatch):
|
||||
"""acquire_gateway_runtime_lock must survive a stale root-owned lock
|
||||
file: unlink it and retry with a fresh file instead of crashing."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
lock_path = status._get_gateway_lock_path()
|
||||
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
lock_path.write_text("stale", encoding="utf-8")
|
||||
|
||||
real_open = open
|
||||
|
||||
def deny_write(path, *args, **kwargs):
|
||||
# Simulate a root-owned file: opening fails while the ORIGINAL
|
||||
# stale file is still on disk; after unlink, the fresh file the
|
||||
# retry creates opens fine.
|
||||
if (
|
||||
str(path) == str(lock_path)
|
||||
and lock_path.exists()
|
||||
and lock_path.read_text(encoding="utf-8") == "stale"
|
||||
):
|
||||
raise PermissionError(13, "Permission denied", str(path))
|
||||
return real_open(path, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr("builtins.open", deny_write)
|
||||
|
||||
try:
|
||||
assert status.acquire_gateway_runtime_lock() is True
|
||||
finally:
|
||||
status.release_gateway_runtime_lock()
|
||||
|
||||
def test_acquire_gateway_runtime_lock_gives_up_when_unlink_denied(self, tmp_path, monkeypatch):
|
||||
"""If the stale lock cannot even be unlinked, acquisition fails
|
||||
cleanly (returns False) rather than raising."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
lock_path = status._get_gateway_lock_path()
|
||||
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
lock_path.write_text("stale", encoding="utf-8")
|
||||
|
||||
real_open = open
|
||||
|
||||
def deny_write(path, *args, **kwargs):
|
||||
if str(path) == str(lock_path):
|
||||
raise PermissionError(13, "Permission denied", str(path))
|
||||
return real_open(path, *args, **kwargs)
|
||||
|
||||
real_unlink = Path.unlink
|
||||
|
||||
def deny_unlink(self, *args, **kwargs):
|
||||
if str(self) == str(lock_path):
|
||||
raise OSError(13, "Permission denied", str(self))
|
||||
return real_unlink(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr("builtins.open", deny_write)
|
||||
monkeypatch.setattr(Path, "unlink", deny_unlink)
|
||||
|
||||
assert status.acquire_gateway_runtime_lock() is False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue