Marco Ricci commited on 2026-01-18 15:42:53
Zeige 1 geänderte Dateien mit 26 Einfügungen und 9 Löschungen.
The SSH agent socket provider, by contract, must raise `NotImplementedError` (or a subclass) if and only if the socket can never be successfully constructed, on principle. Conversely, if the socket provider raises any other kind of error, then the socket *could* be constructed on this system, principally. In the specific case of Windows named pipes whose address is named by the `SSH_AUTH_SOCK` environment variable, it is a programming error to first check the environment variable value, allowing `KeyError` or `ValueError` to bubble through to the caller, and only afterwards during construction of the named pipe realize that there is no support.
| ... | ... |
@@ -409,7 +409,7 @@ class WindowsNamedPipeHandle: |
| 409 | 409 |
|
| 410 | 410 |
""" |
| 411 | 411 |
if not name.replace("/", "\\").startswith(PIPE_PREFIX):
|
| 412 |
- msg = f"Invalid named pipe address: {name!r}"
|
|
| 412 |
+ msg = f"Invalid named pipe name: {name!r}"
|
|
| 413 | 413 |
raise ValueError(msg) |
| 414 | 414 |
self.handle: HANDLE | None = None |
| 415 | 415 |
while self.handle is None: |
| ... | ... |
@@ -652,29 +652,50 @@ class SocketProvider: |
| 652 | 652 |
|
| 653 | 653 |
@staticmethod |
| 654 | 654 |
def _windows_named_pipe( |
| 655 |
- pipe_name: _WindowsNamedPipeSocketAddress | str, |
|
| 655 |
+ pipe_name: _WindowsNamedPipeSocketAddress | str | None, |
|
| 656 | 656 |
) -> _types.SSHAgentSocket: |
| 657 |
- """Return a socket wrapper around a Windows named pipe. |
|
| 657 |
+ r"""Return a socket wrapper around a Windows named pipe. |
|
| 658 |
+ |
|
| 659 |
+ Args: |
|
| 660 |
+ pipe_name: |
|
| 661 |
+ The named pipe's name, or a well-known named pipe socket |
|
| 662 |
+ address, or `None` to look up the true name in |
|
| 663 |
+ `SSH_AUTH_SOCK`. In the latter case, the `SSH_AUTH_SOCK` |
|
| 664 |
+ environment variable is assumed to contain a valid named |
|
| 665 |
+ pipe name, i.e., a path starting with `\\.\pipe\` or |
|
| 666 |
+ `//./pipe/`. |
|
| 658 | 667 |
|
| 659 | 668 |
Raises: |
| 669 |
+ KeyError: |
|
| 670 |
+ The `SSH_AUTH_SOCK` environment variable was not found. |
|
| 660 | 671 |
OSError: |
| 661 | 672 |
There was an error setting up a connection to the agent. |
| 673 |
+ ValueError: |
|
| 674 |
+ The path clearly does not name a valid named pipe name. |
|
| 662 | 675 |
WindowsNamedPipesNotAvailableError: |
| 663 | 676 |
This Python version does not support Windows named |
| 664 | 677 |
pipes. |
| 665 | 678 |
|
| 666 | 679 |
""" |
| 680 |
+ # We must raise WindowsNamedPipesNotAvailableError in preference |
|
| 681 |
+ # to other errors, so we must duplicate the system support check |
|
| 682 |
+ # here (even though WindowsNamedPipeHandle would raise as well). |
|
| 667 | 683 |
if not hasattr(ctypes, "WinDLL"): |
| 668 | 684 |
msg = "This Python version does not support Windows named pipes." |
| 669 | 685 |
raise WindowsNamedPipesNotAvailableError(msg) |
| 670 | 686 |
else: # noqa: RET506 # pragma: unless the-annoying-os no cover |
| 671 | 687 |
# TODO(the-13th-letter): Rewrite using structural pattern |
| 672 |
- # matching. |
|
| 688 |
+ # matching (3 cases). |
|
| 673 | 689 |
# https://the13thletter.info/derivepassphrase/latest/pycompatibility/#after-eol-py3.9 |
| 674 | 690 |
if pipe_name == _WindowsNamedPipeSocketAddress.PAGEANT: |
| 675 | 691 |
return WindowsNamedPipeHandle.for_pageant() |
| 676 | 692 |
if pipe_name == _WindowsNamedPipeSocketAddress.OPENSSH: |
| 677 | 693 |
return WindowsNamedPipeHandle.for_openssh() |
| 694 |
+ if pipe_name is None: # pragma: no branch |
|
| 695 |
+ pipe_name = os.environ["SSH_AUTH_SOCK"] |
|
| 696 |
+ if not pipe_name.replace("/", "\\").startswith(PIPE_PREFIX):
|
|
| 697 |
+ msg = f"Invalid named pipe name: {pipe_name!r}"
|
|
| 698 |
+ raise ValueError(msg) |
|
| 678 | 699 |
return WindowsNamedPipeHandle(pipe_name) |
| 679 | 700 |
|
| 680 | 701 |
@classmethod |
| ... | ... |
@@ -728,11 +749,7 @@ class SocketProvider: |
| 728 | 749 |
pipes. |
| 729 | 750 |
|
| 730 | 751 |
""" |
| 731 |
- address = os.environ["SSH_AUTH_SOCK"] |
|
| 732 |
- if not address.replace("/", "\\").startswith(PIPE_PREFIX):
|
|
| 733 |
- msg = f"Invalid named pipe name: {address!r}"
|
|
| 734 |
- raise ValueError(msg) |
|
| 735 |
- return cls._windows_named_pipe(address) |
|
| 752 |
+ return cls._windows_named_pipe(None) |
|
| 736 | 753 |
|
| 737 | 754 |
registry: ClassVar[ |
| 738 | 755 |
dict[str, _types.SSHAgentSocketProvider | str | None] |
| 739 | 756 |