Metadata-Version: 2.1
Name: persistent-ssh-agent
Version: 0.2.0
Summary: A Python library for persistent SSH agent management with automatic key handling, focusing on Windows compatibility and seamless Git integration.
License: MIT
Author: longhao
Author-email: hal.long@outlook.com
Requires-Python: >=3.8,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Description-Content-Type: text/markdown

# persistent-ssh-agent

<div align="center">

[![Python Version](https://img.shields.io/pypi/pyversions/persistent_ssh_agent)](https://img.shields.io/pypi/pyversions/persistent_ssh_agent)
[![Nox](https://img.shields.io/badge/%F0%9F%A6%8A-Nox-D85E00.svg)](https://github.com/wntrblm/nox)
[![PyPI Version](https://img.shields.io/pypi/v/persistent_ssh_agent?color=green)](https://pypi.org/project/persistent_ssh_agent/)
[![Downloads](https://static.pepy.tech/badge/persistent_ssh_agent)](https://pepy.tech/project/persistent_ssh_agent)
[![Downloads](https://static.pepy.tech/badge/persistent_ssh_agent/month)](https://pepy.tech/project/persistent_ssh_agent)
[![Downloads](https://static.pepy.tech/badge/persistent_ssh_agent/week)](https://pepy.tech/project/persistent_ssh_agent)
[![License](https://img.shields.io/pypi/l/persistent_ssh_agent)](https://pypi.org/project/persistent_ssh_agent/)
[![PyPI Format](https://img.shields.io/pypi/format/persistent_ssh_agent)](https://pypi.org/project/persistent_ssh_agent/)
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/loonghao/persistent_ssh_agent/graphs/commit-activity)
![Codecov](https://img.shields.io/codecov/c/github/loonghao/persistent_ssh_agent)
</div>
🔐 A modern Python library for persistent SSH agent management across sessions.

[Key Features](#key-features) •
[Installation](#installation) •
[Documentation](#usage) •
[Examples](#examples) •
[Contributing](#contributing)

</div>

## ✨ Key Features

- 🔄 Persistent SSH agent management across sessions
- 🔑 Automatic SSH key loading and caching
- 🪟 Windows-optimized implementation
- 🔗 Seamless Git integration
- 🌐 Cross-platform compatibility (Windows, Linux, macOS)
- 📦 No external dependencies beyond standard SSH tools

## 🚀 Installation

```bash
pip install persistent-ssh-agent
```

## 📋 Requirements

- Python 3.x
- OpenSSH (ssh-agent, ssh-add) installed and available in PATH
- Git (optional, for Git operations)

## 📖 Usage

### Basic Usage

```python
from persistent_ssh_agent import PersistentSSHAgent

# Create an instance
ssh_agent = PersistentSSHAgent()

# Set up SSH for a specific host
if ssh_agent.setup_ssh('github.com'):
    print("✅ SSH authentication ready!")
```

### GitPython Integration

```python
from git import Repo
from persistent_ssh_agent import PersistentSSHAgent
import os

def clone_with_gitpython(repo_url: str, local_path: str, branch: str = None) -> Repo:
    """Clone a repository using GitPython with persistent SSH authentication."""
    ssh_agent = PersistentSSHAgent()

    # Extract hostname and set up SSH
    hostname = ssh_agent._extract_hostname(repo_url)
    if not hostname or not ssh_agent.setup_ssh(hostname):
        raise RuntimeError("Failed to set up SSH authentication")

    # Get SSH command and configure environment
    ssh_command = ssh_agent.get_git_ssh_command(hostname)
    if not ssh_command:
        raise RuntimeError("Failed to get SSH command")

    # Set up Git environment
    env = os.environ.copy()
    env['GIT_SSH_COMMAND'] = ssh_command

    # Clone with GitPython
    return Repo.clone_from(
        repo_url,
        local_path,
        branch=branch,
        env=env
    )

# Example usage
try:
    repo = clone_with_gitpython(
        'git@github.com:username/repo.git',
        '/path/to/local/repo',
        branch='main'
    )
    print(f"✅ Repository cloned: {repo.working_dir}")

    # Perform Git operations
    repo.remotes.origin.pull()
    repo.remotes.origin.push()
except Exception as e:
    print(f"❌ Error: {e}")
```

### Advanced GitPython Operations

```python
def setup_git_operations():
    """Set up environment for Git operations."""
    ssh_agent = PersistentSSHAgent()
    hostname = "github.com"

    if not ssh_agent.setup_ssh(hostname):
        raise RuntimeError("SSH setup failed")

    ssh_command = ssh_agent.get_git_ssh_command(hostname)
    if not ssh_command:
        raise RuntimeError("Failed to get SSH command")

    os.environ['GIT_SSH_COMMAND'] = ssh_command
    return True

# Example: Complex Git operations
def manage_git_workflow(repo_path: str):
    if not setup_git_operations():
        return False

    repo = Repo(repo_path)

    # Create and checkout new branch
    new_branch = repo.create_head('feature/new-feature')
    new_branch.checkout()

    # Make changes
    with open(os.path.join(repo_path, 'new_file.txt'), 'w') as f:
        f.write('New content')

    # Stage and commit
    repo.index.add(['new_file.txt'])
    repo.index.commit('Add new file')

    # Push to remote
    repo.remotes.origin.push(new_branch)
```

## 🔧 Common Use Cases

### CI/CD Pipelines

```python
import os
from persistent_ssh_agent import PersistentSSHAgent

def setup_ci_ssh():
    """Set up SSH for CI environment."""
    ssh_agent = PersistentSSHAgent()

    # Set up SSH key from environment
    key_path = os.environ.get('SSH_PRIVATE_KEY_PATH')
    if not key_path:
        raise ValueError("SSH key path not provided")

    if ssh_agent._start_ssh_agent(key_path):
        print("✅ SSH agent started successfully")
        return True

    raise RuntimeError("Failed to start SSH agent")
```

### Multi-Host Management

```python
async def setup_multiple_hosts(hosts: list[str]) -> dict[str, bool]:
    """Set up SSH for multiple hosts concurrently."""
    ssh_agent = PersistentSSHAgent()
    results = {}

    for host in hosts:
        results[host] = ssh_agent.setup_ssh(host)

    return results

# Usage
hosts = ['github.com', 'gitlab.com', 'bitbucket.org']
status = await setup_multiple_hosts(hosts)
```

## 💡 Best Practices

### Key Management

- 🔑 Store SSH keys in standard locations (`~/.ssh/`)
- 🔒 Use Ed25519 keys for better security
- 📝 Maintain organized SSH config files

### Error Handling

```python
from typing import Optional
from pathlib import Path

def safe_git_operation(repo_url: str, local_path: Path) -> Optional[Repo]:
    """Safely perform Git operations with proper error handling."""
    ssh_agent = PersistentSSHAgent()
    try:
        hostname = ssh_agent._extract_hostname(repo_url)
        if not hostname:
            raise ValueError("Invalid repository URL")

        if not ssh_agent.setup_ssh(hostname):
            raise RuntimeError("SSH setup failed")

        return Repo.clone_from(repo_url, local_path)
    except Exception as e:
        logger.error(f"Git operation failed: {e}")
        return None
```

## 🔍 Troubleshooting

### Common Issues

1. **SSH Agent Issues**
   ```bash
   # Check SSH agent status
   ssh-add -l

   # Start SSH agent manually
   eval $(ssh-agent -s)
   ```

2. **Key Problems**
   ```bash
   # Fix key permissions
   chmod 600 ~/.ssh/id_ed25519

   # Test SSH connection
   ssh -T git@github.com
   ```

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

