diff --git a/clients/go/mxgateway/client.go b/clients/go/mxgateway/client.go index 9e3fab7..9bf2370 100644 --- a/clients/go/mxgateway/client.go +++ b/clients/go/mxgateway/client.go @@ -234,11 +234,9 @@ func tlsConfigForOptions(opts Options) *tls.Config { return nil } return &tls.Config{ - MinVersion: tls.VersionTLS12, - ServerName: opts.ServerNameOverride, - //nolint:gosec // internal tool; self-signed cert is the expected gateway default; - // opt-in to strict verification via RequireCertificateValidation. - InsecureSkipVerify: !opts.RequireCertificateValidation, + MinVersion: tls.VersionTLS12, + ServerName: opts.ServerNameOverride, + InsecureSkipVerify: !opts.RequireCertificateValidation, //nolint:gosec // internal tool; self-signed gateway cert expected; opt-in strict via RequireCertificateValidation } } diff --git a/clients/python/src/zb_mom_ww_mxgateway/options.py b/clients/python/src/zb_mom_ww_mxgateway/options.py index b4e1645..29caf29 100644 --- a/clients/python/src/zb_mom_ww_mxgateway/options.py +++ b/clients/python/src/zb_mom_ww_mxgateway/options.py @@ -74,8 +74,20 @@ class BrowseChildrenOptions: def _split_authority(endpoint: str) -> tuple[str, int]: - """Split a gRPC target (optionally scheme-prefixed) into (host, port).""" + """Split a gRPC target (optionally scheme-prefixed) into (host, port). + + Handles bracketed IPv6 literals (e.g. ``[::1]:5120`` or bare ``[::1]``), + returning the host without brackets so it is safe to pass to + ``ssl.get_server_certificate``. + """ target = endpoint.split("://", 1)[-1] + if target.startswith("["): + # Bracketed IPv6: "[::1]:5120" or "[::1]" + bracket_end = target.find("]") + host = target[1:bracket_end] # strip surrounding brackets + remainder = target[bracket_end + 1 :] # ":5120" or "" + port_str = remainder.lstrip(":") + return (host, int(port_str) if port_str else 443) host, _, port = target.rpartition(":") return (host or "localhost", int(port) if port else 443) diff --git a/clients/python/tests/test_tls.py b/clients/python/tests/test_tls.py index 2547011..d7c1c4b 100644 --- a/clients/python/tests/test_tls.py +++ b/clients/python/tests/test_tls.py @@ -134,6 +134,17 @@ def test_split_authority_parses_host_and_port() -> None: assert _split_authority(":5120") == ("localhost", 5120) +def test_split_authority_strips_ipv6_brackets() -> None: + from zb_mom_ww_mxgateway.options import _split_authority + + # Bracketed IPv6 with port — brackets must be removed for ssl.get_server_certificate + assert _split_authority("[::1]:5120") == ("::1", 5120) + # Bare bracketed IPv6 (no port) — default port 443 + assert _split_authority("[::1]") == ("::1", 443) + # Scheme-prefixed bracketed IPv6 + assert _split_authority("grpc://[::1]:5120") == ("::1", 5120) + + def test_tofu_connect_failure_raises_transport_error() -> None: """A failed cert pre-fetch surfaces the client's transport error type.""" options = ClientOptions(endpoint=f"127.0.0.1:{_free_port()}")