From 4cb6ccb16a8871ab5196d46070db72c1caa5cc3d Mon Sep 17 00:00:00 2001 From: parveshsaini Date: Thu, 18 Jun 2026 00:30:06 +0530 Subject: [PATCH 1/2] fix(agentex): only bracket IPv6 literals when building the OTLP metrics URL --- agentex/src/temporal/run_worker.py | 15 +++++++++++- .../temporal/test_run_worker_metrics_url.py | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 agentex/tests/unit/temporal/test_run_worker_metrics_url.py diff --git a/agentex/src/temporal/run_worker.py b/agentex/src/temporal/run_worker.py index de44cba6..c8e1429d 100644 --- a/agentex/src/temporal/run_worker.py +++ b/agentex/src/temporal/run_worker.py @@ -40,6 +40,19 @@ # Task queue name for agentex server operations AGENTEX_SERVER_TASK_QUEUE = "agentex-server" + +def build_metrics_url(host_url: str | None) -> str | None: + """Build the OTLP metrics endpoint URL from a host. + + Per RFC 3986, only IPv6 literals are wrapped in brackets; hostnames and + IPv4 literals are used as-is. Returns None when no host is configured. + """ + if not host_url: + return None + host = f"[{host_url}]" if ":" in host_url else host_url + return f"http://{host}:4317" + + # Global worker instance health_check_worker: Worker | None = None @@ -84,7 +97,7 @@ async def run_worker( # Check for metrics configuration host_url = os.environ.get("DD_AGENT_HOST") - metrics_url = f"http://[{host_url}]:4317" if host_url else None + metrics_url = build_metrics_url(host_url) if metrics_url: logger.info(f"Configuring worker with metrics URL: {metrics_url}") diff --git a/agentex/tests/unit/temporal/test_run_worker_metrics_url.py b/agentex/tests/unit/temporal/test_run_worker_metrics_url.py new file mode 100644 index 00000000..5d74223d --- /dev/null +++ b/agentex/tests/unit/temporal/test_run_worker_metrics_url.py @@ -0,0 +1,23 @@ +import pytest +from src.temporal.run_worker import build_metrics_url + + +@pytest.mark.unit +def test_metrics_url_is_none_when_host_unset(): + assert build_metrics_url(None) is None + assert build_metrics_url("") is None + + +@pytest.mark.unit +@pytest.mark.parametrize("host", ["localhost", "datadog-agent", "10.0.0.5"]) +def test_hostname_and_ipv4_are_not_bracketed(host): + assert build_metrics_url(host) == f"http://{host}:4317" + + +@pytest.mark.unit +@pytest.mark.parametrize( + "host,expected", + [("::1", "http://[::1]:4317"), ("fe80::1", "http://[fe80::1]:4317")], +) +def test_ipv6_literal_is_bracketed(host, expected): + assert build_metrics_url(host) == expected From 32c5211470a0508aa114c647327a5a8c35a1c12c Mon Sep 17 00:00:00 2001 From: parveshsaini Date: Thu, 18 Jun 2026 09:33:55 +0530 Subject: [PATCH 2/2] fix(agentex): handle host:port and bracketed IPv6 when building OTLP metrics URL --- agentex/src/temporal/run_worker.py | 28 +++++++++++++++---- .../temporal/test_run_worker_metrics_url.py | 26 +++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/agentex/src/temporal/run_worker.py b/agentex/src/temporal/run_worker.py index c8e1429d..08b86717 100644 --- a/agentex/src/temporal/run_worker.py +++ b/agentex/src/temporal/run_worker.py @@ -41,16 +41,34 @@ AGENTEX_SERVER_TASK_QUEUE = "agentex-server" +OTLP_METRICS_DEFAULT_PORT = 4317 + + def build_metrics_url(host_url: str | None) -> str | None: - """Build the OTLP metrics endpoint URL from a host. + """Build the OTLP metrics endpoint URL from a ``host`` or ``host:port`` value. - Per RFC 3986, only IPv6 literals are wrapped in brackets; hostnames and - IPv4 literals are used as-is. Returns None when no host is configured. + Accepts a bare hostname/IPv4, an IPv6 literal (bracketed or not), or any of + those with an explicit ``:port`` suffix. Per RFC 3986 only IPv6 literals are + wrapped in brackets, and the default OTLP gRPC port is appended only when the + value does not already carry one. Returns None when no host is configured. """ if not host_url: return None - host = f"[{host_url}]" if ":" in host_url else host_url - return f"http://{host}:4317" + + host = host_url.strip() + port: str | None = None + + if host.startswith("["): + bracket_end = host.find("]") + if bracket_end != -1: + rest = host[bracket_end + 1 :] + port = rest[1:] if rest.startswith(":") else None + host = host[1:bracket_end] + elif host.count(":") == 1: + host, port = host.split(":", 1) + + bracketed = f"[{host}]" if ":" in host else host + return f"http://{bracketed}:{port or OTLP_METRICS_DEFAULT_PORT}" # Global worker instance diff --git a/agentex/tests/unit/temporal/test_run_worker_metrics_url.py b/agentex/tests/unit/temporal/test_run_worker_metrics_url.py index 5d74223d..6253808f 100644 --- a/agentex/tests/unit/temporal/test_run_worker_metrics_url.py +++ b/agentex/tests/unit/temporal/test_run_worker_metrics_url.py @@ -21,3 +21,29 @@ def test_hostname_and_ipv4_are_not_bracketed(host): ) def test_ipv6_literal_is_bracketed(host, expected): assert build_metrics_url(host) == expected + + +@pytest.mark.unit +@pytest.mark.parametrize( + "host,expected", + [ + ("datadog-agent:4317", "http://datadog-agent:4317"), + ("10.0.0.5:4317", "http://10.0.0.5:4317"), + ("datadog-agent:5555", "http://datadog-agent:5555"), + ], +) +def test_hostname_with_explicit_port_is_not_bracketed(host, expected): + assert build_metrics_url(host) == expected + + +@pytest.mark.unit +@pytest.mark.parametrize( + "host,expected", + [ + ("[::1]", "http://[::1]:4317"), + ("[fe80::1]", "http://[fe80::1]:4317"), + ("[::1]:5555", "http://[::1]:5555"), + ], +) +def test_already_bracketed_ipv6_literal(host, expected): + assert build_metrics_url(host) == expected