mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 13:26:40 +00:00
A same-user gateway whose control pipe or process refuses the client was reported as `Gateway inaccessible (authorization)`, which reads as a credential failure. Two real causes hide behind it: - #139845: the gateway runs elevated; the non-elevated Desktop's OpenProcess on its PID fails (err 5). - #140252: a session-0 S4U boot-task gateway won the control pipe; the interactive Desktop can never reach it. discover/ensure now probe the owner PID (gateway.pid / gateway.lock) on a refusal: ProcessIdToSessionId for both sides, TokenElevation for both. A different session is `gateway_other_session`; a same-session owner that is elevated (or whose token a filtered client cannot open) is `gateway_elevated`. Each carries a remedy in `detail`, which Desktop already shows in its boot error. Anything else keeps `authorization`. Exit code stays 4. No Windows host was available: the classifier and mapping are unit-tested, the native probes are covered by tests/gateway/test_refused_owner_windows.py (Windows CI); the elevated-owner case needs a live retest. Refs #134889 (W8) Refs #139845 Refs #140252 Refs #140337
38 lines
1.7 KiB
Python
38 lines
1.7 KiB
Python
"""Machine-readable ensure boundary. No bootstrap credentials leave this command."""
|
|
from dataclasses import asdict
|
|
import json
|
|
import sys
|
|
from contextlib import redirect_stdout
|
|
|
|
|
|
def ensure_exit_code(result) -> int:
|
|
if result.reason_code == "deadline":
|
|
return 5
|
|
if result.reason_code in {"authorization", "profile_mismatch", "gateway_elevated", "gateway_other_session"}:
|
|
return 4
|
|
return {"ready": 0, "incompatible": 3, "draining": 6,
|
|
"inaccessible": 7, "conflict": 7, "starting": 5, "absent": 5}[result.state]
|
|
|
|
|
|
def cmd_gateway_ensure(args) -> None:
|
|
from hermes_constants import get_hermes_home
|
|
from hermes_cli.gateway_runtime import ensure_gateway_runtime
|
|
|
|
try:
|
|
# Legacy imported utilities can print; protocol stdout belongs only to us.
|
|
with redirect_stdout(sys.stderr):
|
|
result = ensure_gateway_runtime(get_hermes_home(), timeout=float(args.timeout))
|
|
payload = asdict(result)
|
|
if result.endpoint:
|
|
payload["endpoint"]["capabilities"] = sorted(result.endpoint.capabilities)
|
|
# The code THIS client (and any gateway it starts) runs, resolved exactly like the owner's
|
|
# ``endpoint.code_sha``: a client that sees them differ is attached to a gateway that
|
|
# outlived ``hermes update`` and must restart it rather than re-attach.
|
|
from hermes_cli.version_info import get_code_identity
|
|
payload["client_code_sha"] = get_code_identity().get("sha")
|
|
code = ensure_exit_code(result)
|
|
except (ValueError, TypeError):
|
|
payload, code = {"state": "inaccessible", "reason_code": "invalid_invocation", "endpoint": None}, 2
|
|
print(json.dumps(payload, separators=(",", ":"), sort_keys=True))
|
|
raise SystemExit(code)
|