Metadata-Version: 2.4
Name: sentinel-python-sdk
Version: 1.0.0
Summary: Sentinel Python SDK — automatic exception capture and reporting for Python services.
Author-email: Sentinel Platform <sentinel@notifications.sentinelai.dev>
License: MIT
Project-URL: Homepage, https://nexuspartner.dev
Project-URL: Repository, https://github.com/nicolaemorcov/sentinel-platform
Keywords: sentinel,monitoring,exceptions,apm,observability
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: async
Requires-Dist: httpx>=0.27; extra == "async"
Provides-Extra: fastapi
Requires-Dist: httpx>=0.27; extra == "fastapi"
Requires-Dist: starlette>=0.37; extra == "fastapi"
Requires-Dist: fastapi>=0.111; extra == "fastapi"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: fastapi>=0.111; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: starlette>=0.37; extra == "dev"

# sentinel-python-sdk

Automatic exception capture for Python services. When an unhandled exception escapes your application, this SDK captures it, scrubs PII, and reports it to the Sentinel gateway — without adding required dependencies or interfering with your existing error handling.

> **Requires Python 3.10+**

---

## Installation

```bash
# Core — stdlib only, zero required dependencies
pip install sentinel-python-sdk

# For FastAPI / async services
pip install "sentinel-python-sdk[fastapi]"

# For async dispatch only (without FastAPI)
pip install "sentinel-python-sdk[async]"
```

---

## Quick start

### Synchronous services (scripts, workers, Flask, Django, etc.)

```python
import sentinel_sdk

sentinel_sdk.configure(
    api_key="your-api-key",
    github_repo="owner/repo",
)
sentinel_sdk.install_hook()

# Any unhandled exception from this point is automatically reported.
```

### FastAPI

```python
from fastapi import FastAPI
import sentinel_sdk
from sentinel_sdk import SentinelMiddleware

sentinel_sdk.configure(
    api_key="your-api-key",
    github_repo="owner/repo",
)

app = FastAPI()
app.add_middleware(SentinelMiddleware)
```

Each request path (e.g. `/api/orders`) is used as the `endpoint` field in the reported exception.

---

## Configuration

```python
sentinel_sdk.configure(
    api_key="your-api-key",       # Required. Bearer token for the gateway.
    github_repo="owner/repo",     # Required. Repository to associate exceptions with.
    gateway_url="https://nexuspartner.dev",  # Default gateway endpoint.
    timeout_seconds=5.0,          # HTTP request timeout.
    max_retries=3,                 # Retry attempts on 5xx and network errors.
    retry_backoff_base=0.5,        # Base for exponential backoff (seconds).
    endpoint_label="<unknown>",    # Fallback endpoint for hook-captured exceptions.
    enabled=True,                  # Set False to disable all I/O (also reads SENTINEL_ENABLED env var).
)
```

`configure()` can be called once at startup. Calling it again overwrites the singleton — do not rely on this in production.

**Environment variable**: Set `SENTINEL_ENABLED=false` (or `0`, `no`, `off`) to disable the SDK without changing code. Useful in local development or CI.

---

## How it works

### Global exception hook

`install_hook()` replaces `sys.excepthook` and `threading.excepthook`. When an unhandled exception reaches either hook:

1. The SDK builds a payload from the exception type, message, and traceback.
2. PII is scrubbed from the message and traceback.
3. The payload is dispatched to the gateway in a background daemon thread (non-blocking).
4. The original hook is called — Python's default traceback printing is preserved.

```python
sentinel_sdk.uninstall_hook()  # Restores original hooks (safe to call at any time).
sentinel_sdk.hook.is_installed()  # True if hooks are active.
```

### ASGI middleware

`SentinelMiddleware` wraps each request handler. On an unhandled exception:

1. The exception is captured and dispatched asynchronously.
2. The exception is **re-raised** — your existing FastAPI error handlers and 500 responses are unaffected.

The SDK is an observer. It never swallows exceptions.

---

## PII scrubbing

All exception messages and tracebacks are scrubbed before leaving the process. The following patterns are redacted:

| Data type | Replacement |
|---|---|
| Email addresses | `[EMAIL]` |
| Credit card numbers (Luhn-validated) | `[CREDIT_CARD]` |
| IPv4 addresses | `[IP_ADDRESS]` |
| IPv6 addresses (`2001:db8::1`, `::1`) | `[IP_ADDRESS]` |
| Bearer / API tokens | `[REDACTED_TOKEN]` |
| `password=`, `api_key=`, `secret=`, `token=`, etc. | `<key>=[REDACTED_SECRET]` |

Scrubbing is stateless and never raises — if a pattern fails, the original text is returned unchanged.
Credit card patterns are validated with a Luhn checksum before redaction to eliminate false positives on order IDs, timestamps, and other long numeric strings.

---

## Retry behaviour

The dispatcher retries on:

- Network errors (connection refused, timeout, DNS failure)
- HTTP 5xx responses
- HTTP 429 (rate limited)

It does **not** retry on HTTP 4xx responses (authentication failures, bad payloads). These indicate a configuration problem and retrying would not help.

Backoff formula: `backoff_base × 2^attempt + random_jitter`

Dispatch errors are logged at `WARNING` level and never propagate to the caller.

---

## Payload structure

Exceptions are reported as JSON matching the Sentinel gateway contract:

```json
{
  "exceptionType": "module.ClassName",
  "errorMessage": "...",
  "stackTrace": "...",
  "endpoint": "/api/orders",
  "timestamp": "2026-04-11T14:23:01.123456+00:00",
  "githubRepo": "owner/repo",
  "language": "python"
}
```

---

## Development

```bash
git clone https://github.com/nicolaemorcov/sentinel-platform
cd sentinel-python-sdk
pip install -e ".[dev]"
python -m pytest
```

The test suite has 38 scrubber tests + additional module tests covering all modules. They run in under one second with no network calls.

---

## License

MIT
