CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-secretstorage

Python bindings to FreeDesktop.org Secret Service API for secure password and credential storage

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

exception-handling.mddocs/

Exception Handling

Comprehensive exception hierarchy for handling various error conditions in SecretStorage operations. All exceptions derive from the base SecretStorageException class, providing structured error handling for different failure scenarios.

Capabilities

Exception Hierarchy

SecretStorage defines a clear exception hierarchy for different types of errors that can occur during secret storage operations.

class SecretStorageException(Exception):
    """
    Base exception class for all SecretStorage errors.
    
    All other SecretStorage exceptions inherit from this class,
    allowing for broad exception handling when needed.
    """

class SecretServiceNotAvailableException(SecretStorageException):
    """
    Raised when the Secret Service API is not available.
    
    This can occur when:
    - D-Bus session bus is not running
    - Secret Service daemon (GNOME Keyring, KWallet, etc.) is not installed
    - Required environment variables are not set
    - D-Bus connection cannot be established
    """

class LockedException(SecretStorageException):
    """
    Raised when an operation cannot be performed because the collection or item is locked.
    
    Operations that require unlocked collections/items:
    - Reading secret data
    - Creating/modifying items
    - Deleting collections/items
    - Setting labels and attributes
    
    Use unlock() methods to resolve this condition.
    """

class ItemNotFoundException(SecretStorageException):
    """
    Raised when an item or collection does not exist or has been deleted.
    
    This can occur when:
    - Accessing an item that was deleted by another process
    - Using invalid D-Bus object paths
    - Accessing collections that don't exist
    - D-Bus objects that have become invalid
    """

class PromptDismissedException(ItemNotFoundException):
    """
    Raised when a user dismisses an authentication or confirmation prompt.
    
    This can occur during operations that require user interaction:
    - Unlocking collections or items
    - Creating new collections
    - Deleting collections or items
    - Any operation requiring user authentication
    """

Error Handling Patterns

Basic Exception Handling:

import secretstorage

try:
    connection = secretstorage.dbus_init()
    collection = secretstorage.get_default_collection(connection)
    item = collection.create_item("Test", {"app": "myapp"}, b"secret")
    
except secretstorage.SecretServiceNotAvailableException as e:
    print(f"Secret service not available: {e}")
    # Fallback to alternative storage method
    
except secretstorage.LockedException as e:
    print(f"Collection is locked: {e}")
    # Attempt to unlock or inform user
    
except secretstorage.PromptDismissedException as e:
    print(f"User dismissed prompt: {e}")
    # Handle user cancellation
    
except secretstorage.SecretStorageException as e:
    print(f"General SecretStorage error: {e}")
    # Handle any other SecretStorage-specific errors

Handling Locked Collections:

import secretstorage

connection = secretstorage.dbus_init()
collection = secretstorage.get_default_collection(connection)

try:
    # Attempt operation that requires unlocked collection
    secret = item.get_secret()
    
except secretstorage.LockedException:
    # Try to unlock
    try:
        dismissed = collection.unlock()
        if dismissed:
            print("User dismissed unlock prompt")
            # Handle user cancellation
        else:
            # Retry the operation
            secret = item.get_secret()
            
    except secretstorage.PromptDismissedException:
        print("Failed to unlock - user dismissed prompt")
        # Handle inability to unlock

Service Availability Check:

import secretstorage

try:
    connection = secretstorage.dbus_init()
    
    # Check if service is available before proceeding
    if not secretstorage.check_service_availability(connection):
        print("Secret service not available")
        # Use alternative storage
    else:
        # Proceed with secret service operations
        collection = secretstorage.get_default_collection(connection)
        
except secretstorage.SecretServiceNotAvailableException:
    print("Cannot connect to D-Bus or secret service")
    # Fallback to alternative storage method

Robust Item Creation:

import secretstorage

def store_secret_safely(label, attributes, secret_data):
    """Safely store a secret with comprehensive error handling."""
    try:
        connection = secretstorage.dbus_init()
        collection = secretstorage.get_default_collection(connection)
        
        # Ensure collection is unlocked
        if collection.is_locked():
            dismissed = collection.unlock()
            if dismissed:
                raise secretstorage.PromptDismissedException("Collection unlock dismissed")
        
        # Create the item
        item = collection.create_item(label, attributes, secret_data)
        return item
        
    except secretstorage.SecretServiceNotAvailableException:
        print("Secret service unavailable - using alternative storage")
        # Implement fallback storage mechanism
        return None
        
    except secretstorage.LockedException:
        print("Cannot unlock collection")
        return None
        
    except secretstorage.PromptDismissedException:
        print("User cancelled operation")
        return None
        
    except secretstorage.SecretStorageException as e:
        print(f"Unexpected secret storage error: {e}")
        return None

Item Search with Error Handling:

import secretstorage

def find_secrets_safely(attributes):
    """Find secrets with proper error handling."""
    try:
        connection = secretstorage.dbus_init()
        items = list(secretstorage.search_items(connection, attributes))
        
        results = []
        for item in items:
            try:
                # Check if we can access the item
                if not item.is_locked():
                    secret = item.get_secret()
                    results.append({
                        'label': item.get_label(),
                        'attributes': item.get_attributes(),
                        'secret': secret
                    })
                else:
                    # Attempt to unlock item
                    dismissed = item.unlock()
                    if not dismissed:
                        secret = item.get_secret()
                        results.append({
                            'label': item.get_label(),
                            'attributes': item.get_attributes(),
                            'secret': secret
                        })
                        
            except secretstorage.ItemNotFoundException:
                # Item was deleted during iteration
                continue
                
            except secretstorage.LockedException:
                # Item couldn't be unlocked
                results.append({
                    'label': item.get_label(),
                    'attributes': item.get_attributes(),
                    'secret': None,
                    'locked': True
                })
                
        return results
        
    except secretstorage.SecretServiceNotAvailableException:
        print("Secret service not available")
        return []
        
    except secretstorage.SecretStorageException as e:
        print(f"Error searching secrets: {e}")
        return []

Exception Context

When Exceptions Occur

  • SecretServiceNotAvailableException: During dbus_init(), get_default_collection(), or any operation when the service becomes unavailable
  • LockedException: When calling get_secret(), set_secret(), create_item(), delete(), or set_label() on locked collections/items
  • ItemNotFoundException: When accessing deleted items, non-existent collections, or invalid D-Bus paths
  • PromptDismissedException: During unlock(), create_collection(), delete(), or any operation requiring user authentication

Best Practices

  1. Always handle SecretServiceNotAvailableException for graceful degradation
  2. Check lock status before performing sensitive operations
  3. Implement retry logic for prompt dismissals when appropriate
  4. Use specific exception types rather than catching all exceptions
  5. Provide meaningful error messages to users
  6. Have fallback storage mechanisms for when secret service is unavailable

Types

# All exception classes inherit from Python's built-in Exception class
class Exception:
    """Base class for all Python exceptions."""

Install with Tessl CLI

npx tessl i tessl/pypi-secretstorage

docs

collection-operations.md

connection-management.md

exception-handling.md

index.md

item-management.md

search-operations.md

tile.json