Metadata-Version: 2.4
Name: drogue
Version: 0.1.0
Summary: Production-ready rate limiting and DDoS protection for Python web frameworks
Author: Drogue Contributors
License-Expression: MIT
License-File: LICENSE
Keywords: ddos,django,fastapi,rate-limiting,security,throttling
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Framework :: Django
Classifier: Framework :: FastAPI
Classifier: Framework :: Flask
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.10
Provides-Extra: adaptive
Requires-Dist: psutil>=5.0.0; extra == 'adaptive'
Provides-Extra: all
Requires-Dist: django>=4.2; extra == 'all'
Requires-Dist: djangorestframework>=3.14; extra == 'all'
Requires-Dist: fastapi>=0.100.0; extra == 'all'
Requires-Dist: flask>=3.0.0; extra == 'all'
Requires-Dist: opentelemetry-api>=1.0.0; extra == 'all'
Requires-Dist: opentelemetry-sdk>=1.0.0; extra == 'all'
Requires-Dist: prometheus-client>=0.17.0; extra == 'all'
Requires-Dist: psutil>=5.0.0; extra == 'all'
Requires-Dist: redis[hiredis]>=5.0.0; extra == 'all'
Requires-Dist: starlette>=0.27.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: drf
Requires-Dist: django>=4.2; extra == 'drf'
Requires-Dist: djangorestframework>=3.14; extra == 'drf'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
Requires-Dist: starlette>=0.27.0; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=3.0.0; extra == 'flask'
Provides-Extra: opentelemetry
Requires-Dist: opentelemetry-api>=1.0.0; extra == 'opentelemetry'
Requires-Dist: opentelemetry-sdk>=1.0.0; extra == 'opentelemetry'
Provides-Extra: prometheus
Requires-Dist: prometheus-client>=0.17.0; extra == 'prometheus'
Provides-Extra: redis
Requires-Dist: redis[hiredis]>=5.0.0; extra == 'redis'
Description-Content-Type: text/markdown

# drogue -- Rate Limiting and DDoS Protection for Python

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/tests-131%20passing-brightgreen.svg)](#development)

> Drop-in replacement for slowapi with DDoS detection, WebSocket support, and 9x faster trusted-user paths.

**Author:** Zlynv

---

## Why drogue?

**slowapi** requires `request: Request` in every endpoint, does not support WebSocket, and has no DDoS detection.

**drogue** fixes all three:

```python
# slowapi -- polluted signature, no WebSocket, no DDoS detection
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request):  # forced parameter
    return {"data": "value"}

# drogue -- clean signature, WebSocket support, DDoS detection
@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():  # clean
    return {"data": "value"}
```

**What drogue adds that slowapi does not have:**

- Clean signatures -- no `request: Request` needed
- WebSocket rate limiting -- `@limiter.limit_ws("100/minute")`
- DDoS detection -- Z-score anomaly detection plus streaming Sentinel Model
- Early warning -- probe pattern detection 30-120 seconds before attacks
- Trust caching -- 9x throughput for verified users (5 microseconds vs 43 microseconds)
- Defense randomization -- attackers cannot learn your thresholds
- Memory efficient -- 10MB in-process replaces 80MB Redis

---

## Install

```bash
pip install drogue

# With framework support
pip install drogue[fastapi]   # FastAPI + Starlette
pip install drogue[django]    # Django
pip install drogue[flask]     # Flask
pip install drogue[drf]       # Django REST Framework
pip install drogue[redis]     # Redis backend
pip install drogue[all]       # Everything
```

---

## Quick Start

```python
from fastapi import FastAPI
from drogue.adapters.fastapi import DrogueLimiter

app = FastAPI()
limiter = DrogueLimiter(app, default_limits=["100/minute"])

@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
    return {"data": "value"}

@app.get("/api/heavy")
@limiter.limit("3/minute")  # expensive endpoints get lower limits
async def heavy_operation():
    return {"result": "computed"}
```

That is it. No `request` parameter. No middleware setup. Works with Flask and Django too -- see [docs/getting-started](docs/getting-started.md).

---

## Features

**Rate Limiting** -- Token Bucket (burst-friendly), Sliding Window (most accurate), Fixed Window (simplest), cost-aware limits, blocking mode

**Storage** -- In-memory (5 microseconds), Redis (distributed), Count-Min Sketch (10MB for 1M keys)

**Frameworks** -- FastAPI (pure ASGI middleware), Flask (decorator plus hook), Django (decorator plus middleware)

**Protection** -- DDoS detection (Z-score plus streaming), probe detection (early warning), progressive auto-ban (5 levels), circuit breaker, CIDR filtering, adaptive limits, shadow mode, trust caching, defense randomization, honeypots

**Observability** -- Prometheus metrics, OpenTelemetry tracing, structured logging

---

## Performance

| Metric | drogue | Context |
|--------|--------|---------|
| Trusted user | ~5 microseconds | Faster than a function call |
| Standard user | ~43 microseconds | 7-23x faster than Redis round-trip |
| Suspicious user | ~200 microseconds | Full pipeline, still under 1ms |
| Throughput | 741K req/s | Token Bucket, single worker |
| Memory per key | 150 bytes | vs 800 bytes in Redis |
| Count-Min Sketch | 10MB | Replaces 800MB Redis for 1M keys |

*Measured on Intel i7-12700K, Python 3.12, asyncio single-worker, median of 10,000 requests.*

---

## Migrate from slowapi

**Before:**

```python
from slowapi import Limiter
from slowapi.util import get_remote_address
from starlette.requests import Request

limiter = Limiter(key_func=get_remote_address)

@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data(request: Request):
    return {"data": "value"}
```

**After:**

```python
from drogue.adapters.fastapi import DrogueLimiter

limiter = DrogueLimiter(app)

@app.get("/api/data")
@limiter.limit("10/minute")
async def get_data():
    return {"data": "value"}
```

**Migration checklist:**

1. Replace `from slowapi import Limiter` with `from drogue.adapters.fastapi import DrogueLimiter`
2. Replace `Limiter(key_func=get_remote_address)` with `DrogueLimiter(app)`
3. Remove `request: Request` from decorated endpoints
4. Rate limit headers work the same (X-RateLimit-Limit/Remaining/Reset)
5. Redis config: same URL format, add `storage_backend="redis"` to config

---

## Competitive Matrix

| Feature | drogue | slowapi | Next closest |
|---------|--------|---------|--------------|
| Cross-framework | FastAPI + Flask + Django | FastAPI only | Django only |
| Clean signatures | Yes | No | No (rateon only) |
| WebSocket | Yes | No | No |
| DDoS detection | Yes (Z-score + streaming) | No | No |
| Trust caching (9x speedup) | Yes | No | No |
| Count-Min Sketch | Yes (10MB for 1M keys) | No | No |
| Geo-blocking | No | No | Yes (fastapi-guard) |

---

## Known Limitations

- Ban state is in-memory only by default. Redis persistence planned for v0.3.
- Trust cache is per-process. Multi-worker setups need separate trust state per worker.
- Flask headers for dict-returning views do not inject automatically.

---

## Security

If you discover a security vulnerability, please open a GitHub issue with the [security] tag. We will respond within 48 hours.

---

## Roadmap

- **v0.2** -- Redis-backed ban state, WebSocket support for Django and Flask
- **v0.3** -- Trust cache cross-process sync, advanced Sentinel features
- **v1.0** -- Production-ready, full documentation site

---

## Development

```bash
git clone https://github.com/Zlynv/drogue.git
cd drogue
pip install -e ".[dev]"

# Run tests
pytest

# Run linting
ruff check src/drogue/

# Run integration tests
cd _integration_test && pip install -r requirements.txt && pytest
```

---

## License

MIT License. See [LICENSE](LICENSE) for details.

---

## Author

Created by [Zlynv](https://github.com/Zlynv).
