fix(alignment): resolve /root/ hardcoding and stale tanko-DSH references
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Failing after 13m19s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Skipped
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Skipped
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Skipped
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Skipped

F1: agent-health-check.py now resolves the home directory from the agent's
user field via a shared helper (get_user_home) instead of hardcoding /root/.
This fixes the false-positive wrapper-missing:tanko report — tanko has a
working wrapper at /home/jerome/.local/bin/hermes, but the check was looking
in /root/.local/bin/.

F2: Updated stale references that described tanko as DSH-only:
- hermes-zulip-restore.prose.md: tanko excluded — hybrid (DSH + Hermes)
- hermes-zulip-plugin.prose.md: tanko excluded — hybrid (DSH + Hermes)
- infrastructure-control.prose.md: tanko is hybrid (DSH + Hermes) agent
- docs/probe-drift-round2-evidence.md: marked as historical record with
  dated note explaining that the DSH-only observations reflected the
  /root/ hardcoding bug, not the underlying truth

Refs: fix/agent-health-root-hardcoding-20260928
This commit is contained in:
root
2026-09-28 20:48:49 +00:00
parent 2ea6b4fc17
commit 2238777a2f
5 changed files with 34 additions and 12 deletions
+19 -6
View File
@@ -152,6 +152,18 @@ def ssh(host, cmd, user="root"):
except:
return None
def get_user_home(user):
"""Resolve the home directory for a user.
For 'root', returns '/root'. For any other user, returns '/home/<user>'.
This is used to construct paths that reference a user's home directory
(e.g., ~/.local/bin/hermes, ~/.hermes/config.yaml) instead of hardcoding /root/.
"""
if user == "root":
return "/root"
else:
return f"/home/{user}"
def http_get(url, headers=None, timeout=5):
"""Return HTTP status code as string."""
try:
@@ -521,8 +533,8 @@ def check_config_integrity():
# Check YAML parses
yaml_ok = ssh(host,
"python3 -c "
'"import yaml; yaml.safe_load(open(\'/root/.hermes/config.yaml\')); print(\'OK\')" '
f"python3 -c "
f"'import yaml; yaml.safe_load(open(\'{home}/.hermes/config.yaml\')); print(\'OK\')" '
"2>&1 || echo 'FAIL'",
user=user)
if not yaml_ok:
@@ -576,7 +588,8 @@ def check_wrapper_integrity():
continue
# Check wrapper exists
wrapper = ssh(host, "ls -la /root/.local/bin/hermes 2>/dev/null", user=user)
home = get_user_home(user)
wrapper = ssh(host, f"ls -la {home}/.local/bin/hermes 2>/dev/null", user=user)
if not wrapper:
# Check alternate wrapper locations
wrapper = ssh(host, "which hermes 2>/dev/null; command -v hermes 2>/dev/null", user=user)
@@ -599,7 +612,7 @@ def check_wrapper_integrity():
# a removed path (litellm-api-keys.prose.md documents
# `rm -f /usr/local/bin/infisical`) must neither produce a dangling path
# nor trigger the PATH check — it is not an invocation.
wrapper_body = ssh(host, "cat /root/.local/bin/hermes 2>/dev/null", user=user) or ""
wrapper_body = ssh(host, f"cat {home}/.local/bin/hermes 2>/dev/null", user=user) or ""
wrapper_code = "\n".join(line.split("#", 1)[0] for line in wrapper_body.splitlines())
invoked_paths = _infisical_invocation_paths(wrapper_body)
if "infisical" in wrapper_code:
@@ -635,7 +648,7 @@ def check_wrapper_integrity():
# Check hermes-real exists
hermes_real = ssh(host,
"ls -la /root/.local/bin/hermes-real 2>/dev/null || echo MISS",
f"ls -la {home}/.local/bin/hermes-real 2>/dev/null || echo MISS",
user=user)
if not hermes_real or hermes_real.strip() == "MISS":
# Check venv path
@@ -650,7 +663,7 @@ def check_wrapper_integrity():
# Check the .env file has the key
env_has_key = ssh(host,
"grep -c 'LITELLM_API_KEY' /root/.hermes/.env 2>/dev/null || echo 0",
f"grep -c 'LITELLM_API_KEY' {home}/.hermes/.env 2>/dev/null || echo 0",
user=user)
if env_has_key and env_has_key.strip() not in ("", "0"):
print(f" ✅ {name}: wrapper + .env key present")