CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pygit2

Python bindings for libgit2 providing comprehensive Git repository operations and version control functionality.

Pending
Overview
Eval results
Files

auth.mddocs/

Authentication

Credential management for Git operations supporting various authentication methods including SSH keys, username/password, and SSH agent. Provides secure authentication for remote operations with flexible credential providers.

Capabilities

Credential Types

Different credential types for various authentication scenarios.

class Username:
    def __init__(self, username: str):
        """
        Username-only credentials.
        
        Parameters:
        - username: Username for authentication
        """

class UserPass:
    def __init__(self, username: str, password: str):
        """
        Username and password credentials.
        
        Parameters:
        - username: Username for authentication
        - password: Password or personal access token
        """

class Keypair:
    def __init__(
        self,
        username: str,
        pubkey_path: str,
        privkey_path: str,
        passphrase: str = ''
    ):
        """
        SSH key pair credentials from files.
        
        Parameters:
        - username: Username for SSH authentication (usually 'git')
        - pubkey_path: Path to public key file
        - privkey_path: Path to private key file  
        - passphrase: Private key passphrase (empty if none)
        """

class KeypairFromAgent:
    def __init__(self, username: str):
        """
        SSH key pair credentials from SSH agent.
        
        Parameters:
        - username: Username for SSH authentication (usually 'git')
        """

class KeypairFromMemory:
    def __init__(
        self,
        username: str,
        pubkey_data: str,
        privkey_data: str,
        passphrase: str = ''
    ):
        """
        SSH key pair credentials from memory.
        
        Parameters:
        - username: Username for SSH authentication
        - pubkey_data: Public key data as string
        - privkey_data: Private key data as string
        - passphrase: Private key passphrase (empty if none)
        """

Credential Type Constants

Constants for identifying credential types in authentication callbacks.

# Credential Type Flags
GIT_CREDENTIAL_USERPASS_PLAINTEXT: int  # Username/password
GIT_CREDENTIAL_SSH_KEY: int             # SSH key pair
GIT_CREDENTIAL_SSH_CUSTOM: int          # Custom SSH authentication
GIT_CREDENTIAL_DEFAULT: int             # Default credentials
GIT_CREDENTIAL_SSH_INTERACTIVE: int     # Interactive SSH
GIT_CREDENTIAL_USERNAME: int            # Username only
GIT_CREDENTIAL_SSH_MEMORY: int          # SSH key from memory

Credential Helper Functions

Utility functions for credential management.

def get_credentials(
    url: str,
    username_from_url: str,
    allowed_types: int
):
    """
    Default credential provider function.
    
    Parameters:
    - url: Remote URL requesting credentials
    - username_from_url: Username extracted from URL
    - allowed_types: Bitfield of allowed credential types
    
    Returns:
    Appropriate credential object or None
    """

Authentication in Remote Operations

Authentication is typically handled through RemoteCallbacks credential method.

class RemoteCallbacks:
    def credentials(
        self,
        url: str,
        username_from_url: str,
        allowed_types: int
    ):
        """
        Provide credentials for remote operation.
        
        Parameters:
        - url: Remote URL needing authentication
        - username_from_url: Username from URL (if any)
        - allowed_types: Credential types allowed by remote
        
        Returns:
        Credential object matching allowed types
        """
        return None
    
    def certificate_check(
        self,
        certificate,
        valid: bool,
        host: str
    ) -> bool:
        """
        Verify server certificate for HTTPS.
        
        Parameters:
        - certificate: Server certificate
        - valid: True if certificate passed basic validation
        - host: Hostname being connected to
        
        Returns:
        True to accept certificate, False to reject
        """
        return valid

Usage Examples

SSH Key Authentication

import pygit2

# SSH key from files
class SSHKeyCallbacks(pygit2.RemoteCallbacks):
    def credentials(self, url, username_from_url, allowed_types):
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            return pygit2.Keypair(
                'git',
                '/home/user/.ssh/id_rsa.pub',
                '/home/user/.ssh/id_rsa',
                'my_passphrase'  # Empty string if no passphrase
            )
        return None

# Use with remote operations
repo = pygit2.Repository('/path/to/repo')
callbacks = SSHKeyCallbacks()
origin = repo.remotes['origin']
origin.fetch(callbacks=callbacks)

SSH Agent Authentication

# Use SSH agent for key management
class SSHAgentCallbacks(pygit2.RemoteCallbacks):
    def credentials(self, url, username_from_url, allowed_types):
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            return pygit2.KeypairFromAgent('git')
        return None

callbacks = SSHAgentCallbacks()
origin.fetch(callbacks=callbacks)

Username/Password Authentication

# HTTPS with username/password
class HTTPSCallbacks(pygit2.RemoteCallbacks):
    def credentials(self, url, username_from_url, allowed_types):
        if allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT:
            # For GitHub, use personal access token as password
            return pygit2.UserPass('username', 'personal_access_token')
        return None

callbacks = HTTPSCallbacks()
origin.push(['refs/heads/main'], callbacks=callbacks)

Multi-Method Authentication

# Support multiple authentication methods
class FlexibleCallbacks(pygit2.RemoteCallbacks):
    def __init__(self, ssh_key_path=None, username=None, password=None):
        self.ssh_key_path = ssh_key_path
        self.username = username
        self.password = password
    
    def credentials(self, url, username_from_url, allowed_types):
        # Try SSH key first
        if (allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY and 
            self.ssh_key_path):
            return pygit2.Keypair(
                'git',
                f'{self.ssh_key_path}.pub',
                self.ssh_key_path,
                ''
            )
        
        # Try SSH agent
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            return pygit2.KeypairFromAgent('git')
        
        # Try username/password
        if (allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT and
            self.username and self.password):
            return pygit2.UserPass(self.username, self.password)
        
        # Try username only
        if (allowed_types & pygit2.GIT_CREDENTIAL_USERNAME and
            self.username):
            return pygit2.Username(self.username)
        
        return None

# Use flexible authentication
callbacks = FlexibleCallbacks(
    ssh_key_path='/home/user/.ssh/id_rsa',
    username='myuser',
    password='mytoken'
)

In-Memory SSH Keys

# Load SSH keys from strings (useful for CI/CD)
class MemoryKeyCallbacks(pygit2.RemoteCallbacks):
    def __init__(self, private_key_data, public_key_data, passphrase=''):
        self.private_key_data = private_key_data
        self.public_key_data = public_key_data
        self.passphrase = passphrase
    
    def credentials(self, url, username_from_url, allowed_types):
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            return pygit2.KeypairFromMemory(
                'git',
                self.public_key_data,
                self.private_key_data,
                self.passphrase
            )
        return None

# Read keys from environment or config
import os
private_key = os.environ.get('SSH_PRIVATE_KEY')
public_key = os.environ.get('SSH_PUBLIC_KEY')

if private_key and public_key:
    callbacks = MemoryKeyCallbacks(private_key, public_key)
    origin.fetch(callbacks=callbacks)

Certificate Verification

# Custom certificate verification
class SecureCallbacks(pygit2.RemoteCallbacks):
    def certificate_check(self, certificate, valid, host):
        # Always verify certificates in production
        if not valid:
            print(f"Invalid certificate for {host}")
            return False
        
        # Additional custom verification
        if 'github.com' in host:
            # Accept GitHub certificates
            return True
        elif 'company.com' in host:
            # Custom verification for company servers
            return self.verify_company_cert(certificate)
        
        # Default to system validation
        return valid
    
    def verify_company_cert(self, certificate):
        # Custom certificate verification logic
        return True
    
    def credentials(self, url, username_from_url, allowed_types):
        if allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT:
            return pygit2.UserPass('user', 'token')
        return None

Environment-Based Authentication

import os

class EnvironmentCallbacks(pygit2.RemoteCallbacks):
    def credentials(self, url, username_from_url, allowed_types):
        # SSH key from environment
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            ssh_key = os.environ.get('GIT_SSH_KEY')
            if ssh_key:
                public_key = ssh_key + '.pub'
                if os.path.exists(ssh_key) and os.path.exists(public_key):
                    passphrase = os.environ.get('GIT_SSH_PASSPHRASE', '')
                    return pygit2.Keypair('git', public_key, ssh_key, passphrase)
        
        # Username/password from environment
        if allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT:
            username = os.environ.get('GIT_USERNAME')
            password = os.environ.get('GIT_PASSWORD') or os.environ.get('GIT_TOKEN')
            if username and password:
                return pygit2.UserPass(username, password)
        
        return None

# Use environment-based authentication
callbacks = EnvironmentCallbacks()

Interactive Authentication

import getpass

class InteractiveCallbacks(pygit2.RemoteCallbacks):
    def credentials(self, url, username_from_url, allowed_types):
        print(f"Authentication required for {url}")
        
        # SSH key with prompt for passphrase
        if allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            ssh_key = input("SSH private key path [~/.ssh/id_rsa]: ")
            if not ssh_key:
                ssh_key = os.path.expanduser('~/.ssh/id_rsa')
            
            public_key = ssh_key + '.pub'
            if os.path.exists(ssh_key) and os.path.exists(public_key):
                passphrase = getpass.getpass("SSH key passphrase (empty if none): ")
                return pygit2.Keypair('git', public_key, ssh_key, passphrase)
        
        # Username/password with prompts
        if allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT:
            username = input(f"Username [{username_from_url}]: ") or username_from_url
            password = getpass.getpass("Password/Token: ")
            if username and password:
                return pygit2.UserPass(username, password)
        
        return None

# Note: Only use interactive auth in appropriate contexts
callbacks = InteractiveCallbacks()

Clone with Authentication

# Clone repository with authentication
def clone_with_auth(url, path, auth_method='ssh_agent'):
    if auth_method == 'ssh_agent':
        callbacks = SSHAgentCallbacks()
    elif auth_method == 'ssh_key':
        callbacks = SSHKeyCallbacks()
    elif auth_method == 'https':
        callbacks = HTTPSCallbacks()
    else:
        callbacks = FlexibleCallbacks()
    
    try:
        repo = pygit2.clone_repository(url, path, callbacks=callbacks)
        print(f"Successfully cloned {url} to {path}")
        return repo
    except pygit2.GitError as e:
        print(f"Clone failed: {e}")
        return None

# Clone with different auth methods
repo = clone_with_auth('git@github.com:user/repo.git', '/local/path', 'ssh_agent')
repo = clone_with_auth('https://github.com/user/repo.git', '/local/path', 'https')

Authentication Error Handling

class RobustCallbacks(pygit2.RemoteCallbacks):
    def __init__(self):
        self.auth_attempts = 0
        self.max_attempts = 3
    
    def credentials(self, url, username_from_url, allowed_types):
        self.auth_attempts += 1
        
        if self.auth_attempts > self.max_attempts:
            print("Maximum authentication attempts exceeded")
            return None
        
        print(f"Authentication attempt {self.auth_attempts}/{self.max_attempts}")
        
        # Try different methods based on attempt number
        if self.auth_attempts == 1 and allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            try:
                return pygit2.KeypairFromAgent('git')
            except Exception as e:
                print(f"SSH agent failed: {e}")
        
        if self.auth_attempts == 2 and allowed_types & pygit2.GIT_CREDENTIAL_SSH_KEY:
            key_path = os.path.expanduser('~/.ssh/id_rsa')
            if os.path.exists(key_path):
                return pygit2.Keypair('git', key_path + '.pub', key_path, '')
        
        if allowed_types & pygit2.GIT_CREDENTIAL_USERPASS_PLAINTEXT:
            # Final attempt with username/password
            username = input("Username: ")
            password = getpass.getpass("Password: ")
            return pygit2.UserPass(username, password)
        
        return None

callbacks = RobustCallbacks()
try:
    origin.fetch(callbacks=callbacks)
except pygit2.GitError as e:
    if "authentication" in str(e).lower():
        print("Authentication failed after all attempts")
    else:
        print(f"Other error: {e}")

Install with Tessl CLI

npx tessl i tessl/pypi-pygit2

docs

advanced.md

auth.md

config.md

diff.md

index.md

objects.md

references.md

remotes.md

repository.md

staging.md

tile.json