Metadata-Version: 2.4
Name: crittora-sdk-python
Version: 0.1.0
Summary: Python SDK for the Crittora API
Project-URL: Homepage, https://github.com/crittora/crittora-sdk-python
Project-URL: Repository, https://github.com/crittora/crittora-sdk-python
Project-URL: Issues, https://github.com/crittora/crittora-sdk-python/issues
Author: Crittora
License: MIT
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: requests<3,>=2.32.0
Provides-Extra: async
Requires-Dist: httpx<1,>=0.28.0; extra == 'async'
Provides-Extra: cognito
Requires-Dist: boto3<2,>=1.39.0; extra == 'cognito'
Provides-Extra: dev
Requires-Dist: build<2,>=1.2.0; extra == 'dev'
Requires-Dist: pytest<10,>=8.3.0; extra == 'dev'
Description-Content-Type: text/markdown

# crittora-sdk-python

`crittora-sdk-python` is a typed secure-message client for the Crittora API.

It supports exactly two application workflows:

- confidentiality only: `encrypt()` -> `decrypt()`
- confidentiality plus authenticity: `sign_encrypt()` -> `decrypt_verify()`

This package exposes a Python-native, instance-based client designed for predictable integration in production systems:

- explicit client construction
- explicit credentials and auth wiring
- transport-level timeout and retry controls
- typed request and response objects
- stable SDK exception classes
- sync and async client parity

## Table Of Contents

- [Runtime Support](#runtime-support)
- [Installation](#installation)
- [Design Principles](#design-principles)
- [Quick Start](#quick-start)
- [Authentication](#authentication)
- [Client Configuration](#client-configuration)
- [Supported Workflows](#supported-workflows)
- [Lifecycle](#lifecycle)
- [Errors](#errors)
- [Additional Documentation](#additional-documentation)

## Runtime Support

- Python 3.10 or later
- `requests` for the sync client
- optional `httpx` for the async client
- optional `boto3` for Cognito auth

## Installation

Base install:

```bash
pip install crittora-sdk-python
```

Async support:

```bash
pip install 'crittora-sdk-python[async]'
```

Cognito support:

```bash
pip install 'crittora-sdk-python[cognito]'
```

## Design Principles

The Python SDK is built around a few constraints that matter for SDK consumers:

- no hidden process-global configuration is required for the primary API
- client instances are isolated, so one process can talk to multiple environments safely
- public Python models use `snake_case`
- auth is composable rather than hard-coded into every request path
- errors preserve transport and backend context so callers can make policy decisions
- Python behavior should be idiomatic even when the JS SDK uses different naming

## Quick Start

### Sync client with bearer auth

```python
from crittora import ApiCredentials, BearerTokenAuth, CrittoraClient, Permission

client = CrittoraClient(
    base_url="https://api.crittoraapis.com",
    credentials=ApiCredentials(
        api_key="api-key",
        access_key="access-key",
        secret_key="secret-key",
    ),
    auth=BearerTokenAuth("id-token"),
    timeout=10.0,
)

result = client.encrypt(
    "sensitive data",
    permissions=[Permission(partner_id="partner-123", actions=["read"])],
)

print(result.encrypted_data)
```

### Scoped auth

If the same client configuration is reused across identities, create a base client and scope auth per request flow:

```python
from crittora import BearerTokenAuth, CrittoraClient

base_client = CrittoraClient()
user_client = base_client.with_auth(BearerTokenAuth(user_id_token))

decrypted = user_client.decrypt(encrypted_data)
```

### Async client

```python
from crittora import AsyncCrittoraClient

async with AsyncCrittoraClient() as client:
    result = await client.encrypt("hello")
```

## Authentication

The SDK supports two primary auth patterns:

### 1. Static bearer token

Use this when your application already manages a token lifecycle:

```python
from crittora import BearerTokenAuth, CrittoraClient

client = CrittoraClient(
    auth=BearerTokenAuth(id_token),
)
```

### 2. Cognito auth provider

Use the built-in Cognito provider when the SDK should perform login and hold the returned tokens:

```python
from crittora import CognitoAuthProvider, CognitoConfig, CrittoraClient

auth = CognitoAuthProvider(
    CognitoConfig(
        user_pool_id="us-east-1_Tmljk4Uiw",
        client_id="5cvaao4qgphfp38g433vi5e82u",
    )
)

tokens = auth.login(username="username", password="password")

client = CrittoraClient(auth=auth)
```

### Security Note

If `access_key` and `secret_key` represent privileged backend credentials, do not expose them in untrusted client-side environments. In that model, use the SDK behind your own backend boundary.

## Client Configuration

`CrittoraClient` accepts:

```python
CrittoraClient(
    *,
    base_url: str = "https://api.crittoraapis.com",
    credentials: ApiCredentials | None = None,
    auth: AuthProvider | None = None,
    timeout: float = 10.0,
    retry: RetryOptions | None = None,
    headers: dict[str, str] | None = None,
    user_agent: str | None = None,
    session: requests.Session | None = None,
)
```

`AsyncCrittoraClient` accepts the same configuration, replacing `session` with `client`.

Operational guidance:

- set `base_url` explicitly in non-production environments
- keep retry counts conservative unless the backend contract explicitly supports aggressive retries
- prefer a custom `user_agent` in services where request attribution matters
- inject your own HTTP client only when you need shared lifecycle or custom transport behavior

## Supported Workflows

### Confidentiality only

```python
encrypted = client.encrypt("hello")
decrypted = client.decrypt(encrypted.encrypted_data)
```

### Confidentiality plus authenticity

```python
envelope = client.sign_encrypt("hello")
verified = client.decrypt_verify(envelope.encrypted_data)
```

## Lifecycle

The sync client supports explicit cleanup and context-manager usage:

```python
with CrittoraClient() as client:
    client.encrypt("hello")
```

The async client supports `await client.close()` and `async with`:

```python
async with AsyncCrittoraClient() as client:
    await client.encrypt("hello")
```

When you inject your own HTTP client, its lifecycle remains your responsibility. The SDK only closes clients it creates itself.

## Errors

The SDK exposes one base exception and several specializations so callers can respond at the right layer:

- `ValidationError`
- `AuthError`
- `RequestError`
- `RateLimitError`
- `EncryptError`
- `DecryptError`

These exceptions preserve HTTP status, response details, and request identifiers where available.

## Additional Documentation

- [API Reference](docs/API.md)
- [Architecture Notes](docs/ARCHITECTURE.md)
- [Authentication Guide](docs/AUTH.md)
- [Environment Guide](docs/ENVIRONMENTS.md)
- [Migration Guide](docs/MIGRATION.md)
- [Releasing](docs/RELEASING.md)

## Examples

- [Sync Example](examples/sync_example.py)
- [Async Example](examples/async_example.py)
- [Cognito Example](examples/cognito_example.py)

## Publishing

This repo is configured for PyPI Trusted Publishing through GitHub Actions.

The publish workflow is:

- [publish.yml](.github/workflows/publish.yml)

Before the workflow can publish, you still need to configure the matching Trusted Publisher on PyPI for this repository and workflow. See:

- [Releasing](docs/RELEASING.md)
