Metadata-Version: 2.4
Name: foxxelabs-sentinel-client
Version: 0.2.0
Summary: Django middleware client for FoxxeLabs Sentinel threat intelligence
Author: FoxxeLabs Limited
License: Proprietary
Project-URL: Homepage, https://sentinel-foxxelabs.fly.dev
Project-URL: Source, https://github.com/todd427/sentinel
Keywords: django,middleware,security,threat-intelligence,sentinel
Classifier: Framework :: Django
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27.0
Requires-Dist: Django>=4.0
Dynamic: license-file

# foxxelabs-sentinel-client

Django client for [FoxxeLabs Sentinel](https://sentinel-foxxelabs.fly.dev) —
centralised IP threat intelligence. Drop it into a Django project to:

- **Block** known-bad IPs before they hit your views (`SentinelBlockMiddleware`).
- **Emit** 4xx/5xx probe events to Sentinel for scoring (`SentinelEmitterMiddleware`, fire-and-forget).
- Pull and cache the blocklist hourly (`BlocklistCache`).

The import package is `sentinel_client` (the distribution is
`foxxelabs-sentinel-client`).

## Install

```bash
pip install foxxelabs-sentinel-client
```

## Configure

In `settings.py`:

```python
SENTINEL_URL = "https://sentinel-foxxelabs.fly.dev"
SENTINEL_API_KEY = "..."            # your project's Sentinel key
SENTINEL_PROJECT_NAME = "my-app"    # identifies this project to Sentinel

MIDDLEWARE = [
    "sentinel_client.middleware.SentinelBlockMiddleware",   # FIRST — blocks before processing
    # ... your other middleware ...
    "sentinel_client.middleware.SentinelEmitterMiddleware", # LAST — reports 4xx/5xx
]
```

`SentinelBlockMiddleware` returns `403` for blocklisted IPs; the emitter is
fire-and-forget and silently drops errors, so Sentinel downtime has zero impact
on request processing.

## Resilience

If Sentinel is unreachable, the emitter swallows the error and the blocklist
cache retains its last-known-good copy. Your app keeps serving.

## License

Proprietary — © FoxxeLabs Limited. All rights reserved.
