fix(cron): resolve api_server host for the manual-run forward (bind parity)

The forward dialed a hardcoded 127.0.0.1. The api_server adapter binds
extra.host -> API_SERVER_HOST -> 127.0.0.1, so mirror that chain when
dialing. Wildcard binds (0.0.0.0/::) listen on loopback, so keep dialing
loopback for those; bracket bare IPv6 literals.
This commit is contained in:
Victor Kyriazakos
2026-08-28 01:31:10 +00:00
committed by Teknium
parent 8e8112687b
commit 5cc47c994b
2 changed files with 54 additions and 1 deletions

View File

@@ -86,4 +86,35 @@ class TestForwardRelayFrontedRun:
):
cronjob_tools._forward_relay_fronted_run({"id": "abc123"})
assert sent["url"].endswith("/api/jobs/abc123/run")
assert sent["url"].startswith("http://127.0.0.1:")
assert sent["headers"]["Authorization"] == "Bearer secret-key-16chars"
def test_honors_api_server_host_env(self, monkeypatch):
"""API_SERVER_HOST must reach the forward URL (adapter bind parity)."""
monkeypatch.setenv("API_SERVER_HOST", "10.9.8.7")
sent = {}
def fake_post(url, headers=None, timeout=None):
sent["url"] = url
return _Resp(200)
with patch.object(
cronjob_tools, "_relay_fronted_delivery_platforms", return_value={"discord"}
), patch("httpx.post", side_effect=fake_post):
cronjob_tools._forward_relay_fronted_run({"id": "j1"})
assert sent["url"].startswith("http://10.9.8.7:")
def test_wildcard_bind_dials_loopback(self, monkeypatch):
"""0.0.0.0 is a bind address, not a dial address — use loopback."""
monkeypatch.setenv("API_SERVER_HOST", "0.0.0.0")
sent = {}
def fake_post(url, headers=None, timeout=None):
sent["url"] = url
return _Resp(200)
with patch.object(
cronjob_tools, "_relay_fronted_delivery_platforms", return_value={"discord"}
), patch("httpx.post", side_effect=fake_post):
cronjob_tools._forward_relay_fronted_run({"id": "j1"})
assert sent["url"].startswith("http://127.0.0.1:")

View File

@@ -849,7 +849,29 @@ def _forward_relay_fronted_run(job: Dict[str, Any]) -> Optional[str]:
port = int(port_raw) if port_raw else 8642
except ValueError:
port = 8642
url = f"http://127.0.0.1:{port}/api/jobs/{job_id}/run"
# Mirror the api_server's own bind resolution (adapter reads
# extra.host -> API_SERVER_HOST -> 127.0.0.1). A wildcard bind
# (0.0.0.0/::) listens on loopback too, so dial loopback for those.
host = ""
try:
from hermes_cli.config import cfg_get, load_config_readonly
host = str(
cfg_get(
load_config_readonly(), "platforms", "api_server", "extra", "host",
default="",
)
or ""
).strip()
except Exception:
host = ""
if not host:
host = os.getenv("API_SERVER_HOST", "").strip()
if not host or host in ("0.0.0.0", "::", "*"):
host = "127.0.0.1"
if ":" in host and not host.startswith("["):
host = f"[{host}]" # bare IPv6 literal
url = f"http://{host}:{port}/api/jobs/{job_id}/run"
from agent.secret_scope import get_secret