Skip to content

Commit 14fed50

Browse files
authored
Fix BoltSocketBase.getpeercert pass-through (#1339)
`(Async)BoltSocketBase.getpeercert` is not used throughout the code-base. Therefore does this bug and its fix have no direct impact. It's future-proofing the code-base. The `hasattr` was introspecting the `socket.socket` class instead of the `socket_` object. A silly typo, really.
1 parent 4496c43 commit 14fed50

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

src/neo4j/_async_compat/network/_bolt_socket.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def _kill_raw_socket(cls, socket_):
362362
class BoltSocketBase:
363363
Bolt: te.Final[type[Bolt]] = None # type: ignore[assignment]
364364

365-
def __init__(self, socket_: socket):
365+
def __init__(self, socket_: socket | SSLSocket):
366366
self._socket = socket_
367367
self._deadline: Deadline | None = None
368368

@@ -375,16 +375,17 @@ def _socket(self, socket_: socket | SSLSocket) -> None:
375375
self.__socket = socket_
376376
self.getsockname = socket_.getsockname
377377
self.getpeername = socket_.getpeername
378-
if hasattr(socket, "getpeercert"):
379-
self.getpeercert = t.cast(SSLSocket, socket_).getpeercert
378+
if hasattr(socket_, "getpeercert"):
379+
self.getpeercert = socket_.getpeercert
380380
elif "getpeercert" in self.__dict__:
381381
del self.__dict__["getpeercert"]
382382
self.gettimeout = socket_.gettimeout
383383
self.settimeout = socket_.settimeout
384384

385385
getsockname: t.Callable = None # type: ignore
386386
getpeername: t.Callable = None # type: ignore
387-
getpeercert: t.Callable = None # type: ignore
387+
# only exists if the wrapped socket is an SSLSocket
388+
getpeercert: t.Callable
388389
gettimeout: t.Callable = None # type: ignore
389390
settimeout: t.Callable = None # type: ignore
390391

tests/unit/mixed/async_compat/test_network.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,61 @@ def ssl_wrap_side_effect(socket, *args, **kwargs):
456456
ssl_context_mock.wrap_socket.assert_called_once()
457457

458458
assert last_ssl_timeout == expected_timeout
459+
460+
461+
@pytest.mark.parametrize(
462+
"property",
463+
("getsockname", "getpeername", "getpeercert", "settimeout", "gettimeout"),
464+
)
465+
@pytest.mark.parametrize("is_ssl", [False, True])
466+
def test_bolt_socket_forwards_to_tcp_socket(property: str, is_ssl: bool):
467+
class FakeSocket:
468+
def __init__(self, with_ssl: bool) -> None:
469+
self.getsockname = object()
470+
self.getpeername = object()
471+
self.settimeout = object()
472+
self.gettimeout = object()
473+
if with_ssl:
474+
self.getpeercert = object()
475+
476+
sock: socket.socket | SSLSocket = t.cast(t.Any, FakeSocket(is_ssl))
477+
bolt_sock = BoltSocket(sock)
478+
479+
if not is_ssl and property == "getpeercert":
480+
assert not hasattr(bolt_sock, property)
481+
with pytest.raises(AttributeError):
482+
getattr(bolt_sock, property)
483+
else:
484+
assert getattr(bolt_sock, property) is getattr(sock, property)
485+
486+
487+
@pytest.mark.parametrize(
488+
"property",
489+
("getsockname", "getpeername", "getpeercert", "settimeout", "gettimeout"),
490+
)
491+
@pytest.mark.parametrize("ssl1", [False, True])
492+
@pytest.mark.parametrize("ssl2", [False, True])
493+
def test_bolt_socket_setter_forwards_to_tcp_socket(
494+
property: str, ssl1: bool, ssl2: bool
495+
):
496+
class FakeSocket:
497+
def __init__(self, with_ssl: bool) -> None:
498+
self.getsockname = object()
499+
self.getpeername = object()
500+
self.settimeout = object()
501+
self.gettimeout = object()
502+
if with_ssl:
503+
self.getpeercert = object()
504+
505+
sock1: socket.socket | SSLSocket = t.cast(t.Any, FakeSocket(ssl1))
506+
bolt_sock = BoltSocket(sock1)
507+
508+
sock2: socket.socket | SSLSocket = t.cast(t.Any, FakeSocket(ssl2))
509+
bolt_sock._socket = sock2
510+
511+
if not ssl2 and property == "getpeercert":
512+
assert not hasattr(bolt_sock, property)
513+
with pytest.raises(AttributeError):
514+
getattr(bolt_sock, property)
515+
else:
516+
assert getattr(bolt_sock, property) is getattr(sock2, property)

0 commit comments

Comments
 (0)