Metadata-Version: 2.4
Name: ssh-wrapper
Version: 0.1.0
Summary: One-auth OpenSSH ControlMaster lifecycle with mux-only channels
Author: kogeler
Maintainer: kogeler
License-Expression: MIT
Project-URL: Homepage, https://kogeler.github.io/ssh-wrapper/
Project-URL: Documentation, https://kogeler.github.io/ssh-wrapper/
Project-URL: Repository, https://github.com/kogeler/ssh-wrapper
Project-URL: Issues, https://github.com/kogeler/ssh-wrapper/issues
Project-URL: Changelog, https://github.com/kogeler/ssh-wrapper/blob/main/CHANGELOG.md
Keywords: openssh,ssh,controlmaster,multiplexing,asyncio
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Networking
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: bandit[toml]==1.9.4; extra == "dev"
Requires-Dist: mypy==2.3.1; extra == "dev"
Requires-Dist: pip-audit==2.10.1; extra == "dev"
Requires-Dist: ruff==0.16.4; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest==9.1.1; extra == "test"
Requires-Dist: pytest-asyncio==1.4.0; extra == "test"
Requires-Dist: pytest-cov==7.1.0; extra == "test"
Provides-Extra: package
Requires-Dist: build==1.5.0; extra == "package"
Requires-Dist: setuptools==84.0.0; extra == "package"
Requires-Dist: wheel==0.48.0; extra == "package"
Provides-Extra: docs
Requires-Dist: mkdocs-material==9.7.7; extra == "docs"
Dynamic: license-file

# SSH Wrapper

`ssh-wrapper` owns one native OpenSSH ControlMaster and exposes only
no-fallback mux channels. It can also supervise one remote process group with
a bounded heartbeat lease, so owner loss cleans up only that group.

The runtime is fully typed and uses only the Python standard library. It does
not choose hosts, store credentials, reconnect a lost master, or define a
consumer protocol.

## Requirements

- CPython 3.13 or 3.14
- Linux
- an OpenSSH client
- `python3` on the remote host only when using `OwnedRemoteProcess`

## Installation

Install an exact reviewed version with pip:

```bash
python3.13 -m pip install "ssh-wrapper==0.1.0"
```

Use `python3.14` in the same command when that is the selected supported
interpreter.

This is a library and does not install a command-line entry point, so `pipx`
is not an appropriate installation method.

## Basic use

```python
import asyncio
from pathlib import Path

from ssh_wrapper import ConnectionSpec, OpenSSHMaster, SSHMasterSettings


async def run() -> bytes:
    master = OpenSSHMaster(
        SSHMasterSettings(
            ssh_path=Path("/usr/bin/ssh"),
            false_path=Path("/usr/bin/false"),
            connect_timeout=30,
        ),
        ConnectionSpec.from_alias("workstation"),
    )
    await master.start()
    try:
        process = await asyncio.create_subprocess_exec(
            *master.command_argv("uname -a"),
            stdout=asyncio.subprocess.PIPE,
        )
        stdout, _stderr = await process.communicate()
        if process.returncode:
            raise RuntimeError(f"remote command exited {process.returncode}")
        return stdout
    finally:
        await master.close()
```

The caller owns each ordinary secondary process and its output. Use
`OwnedRemoteProcess` for a long-lived child that must remain tied to an owner
lease.

## Project links

- [Documentation](https://kogeler.github.io/ssh-wrapper/)
- [Repository](https://github.com/kogeler/ssh-wrapper)
- [Issue tracker](https://github.com/kogeler/ssh-wrapper/issues)
- [Changelog](https://github.com/kogeler/ssh-wrapper/blob/main/CHANGELOG.md)
- [Contributing](https://github.com/kogeler/ssh-wrapper/blob/main/CONTRIBUTING.md)
- [Security policy](https://github.com/kogeler/ssh-wrapper/blob/main/SECURITY.md)
- [Security design](https://kogeler.github.io/ssh-wrapper/user/security/)
- [MIT license](https://github.com/kogeler/ssh-wrapper/blob/main/LICENSE)
