| .. | ||
|---|---|---|
| src | Add the SSH agent socket provider API to the documentation | 2026-08-30 20:05:37 |
| tests | Build a full example SSH agent socket provider, and integration test it | 2026-08-30 18:14:44 |
| LICENSE.txt | Extract the SSH agent socket provider API to a separate PyPI package | 2026-08-30 10:25:08 |
| README.md | Build a full example SSH agent socket provider, and integration test it | 2026-08-30 18:14:44 |
| pyproject.toml | Build a full example SSH agent socket provider, and integration test it | 2026-08-30 18:14:44 |
An interface for SSH agent socket providers, which expose an abstract communication channel for an SSH agent to derivepassphrase.
This package contains only the interface definition and the types involved.
derivepassphrase-sshagentsocketprovider is a pure Python package, and may be easily installed with any pip-compatible Python package manager such as pip, pipx, or uv.
(pip is distributed with Python 3 by default.)
derivepassphrase-sshagentsocketprovider requires Python 3.9 or higher, as well as the typing-extensions package.
pip install derivepassphrase-sshagentsocketprovider
The SSHAgentSocket represents the abstract communication channel to an SSH agent.
Ensure that the abstract channel behaves like a socket with respect to the sendall and recv operations.
The abstract channel must also be a context manager, which closes itself upon leaving the context, causing further sendall and recv operations to raise an error.
(By convention, this is OSError, with errno.EBADF.)
The SSHAgentSocketProvider is a callable that returns an SSHAgentSocket when called without arguments.
To then actually register an SSH agent socket provider, build an SSHAgentSocketProviderEntry struct.
For example:
# The class is an SSHAgentSocket and has an empty constructor, so the
# constructor is a valid SSHAgentSocketProvider.
class SSHAgentOverStdinStdoutSocket:
"""Forwarding STDIN/STDOUT, as if connected to an SSH agent."""
FLAGS_ARE_UNSUPPORTED = "flags argument is unsupported"
"""Common error message."""
def __enter__(self) -> Self:
"""Return self."""
return self
def __exit__(self, *args: object) -> bool | None:
"""Close stdin/stdout."""
sys.stdin.close()
sys.stdout.close()
return None
def send(self, data: Buffer, flags: int = 0, /) -> None:
"""Send data to agent."""
if flags:
raise ValueError(self.FLAGS_ARE_UNSUPPORTED)
sys.stdout.buffer.write(data)
def recv(self, bufsize: int, flags: int = 0, /) -> bytes:
"""Receive data from agent."""
if flags:
raise ValueError(self.FLAGS_ARE_UNSUPPORTED)
return sys.stdin.buffer.read(bufsize)
ENTRY_POINT = SSHAgentSocketProviderEntry(
provider=SSHAgentOverStdinStdoutSocket,
key="stdin_stdout",
aliases=("stdin", "stdout"),
)
Then add an appropriate entry point definition in your pyproject.toml, using the entry point group name derivepassphrase.ssh_agent_socket_providers:
[project.entry."derivepassphrase.ssh_agent_socket_providers"]
first_provider = "mymodule: ENTRY_POINT"
derivepassphrase will then pick up stdin_stdout as a new SSH agent socket provider, with aliases stdin and stdout.[^entry_point_name]
[^entry_point_name]:
Only the fields in the SSHAgentSocketProviderEntry matter, not what names are used to declare the entry point.
By convention, however, you would choose stdin_stdout as the entry point name, not first_provider.
(See the tests and the test data for two further examples.)
Like derivepassphrase, derivepassphrase-sshagentsocketprovider is distributed under the terms of the zlib/libpng license.