prodkit 0.3.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {prodkit-0.3.0 → prodkit-0.4.0}/CHANGELOG.md +12 -0
- prodkit-0.4.0/PKG-INFO +480 -0
- prodkit-0.4.0/README.md +410 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/pyproject.toml +10 -1
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/__init__.py +1 -1
- prodkit-0.4.0/src/prodkit/cli/__main__.py +6 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/cli/app.py +171 -3
- prodkit-0.4.0/src/prodkit/generators/__init__.py +36 -0
- prodkit-0.4.0/src/prodkit/generators/base.py +104 -0
- prodkit-0.4.0/src/prodkit/generators/compose.py +95 -0
- prodkit-0.4.0/src/prodkit/generators/docker.py +140 -0
- prodkit-0.4.0/src/prodkit/generators/env.py +121 -0
- prodkit-0.4.0/src/prodkit/generators/github.py +87 -0
- prodkit-0.4.0/src/prodkit/generators/nginx.py +111 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/tracing/__init__.py +1 -1
- prodkit-0.4.0/tests/integration/test_cli_generate.py +131 -0
- prodkit-0.4.0/tests/unit/test_generators.py +211 -0
- prodkit-0.3.0/PKG-INFO +0 -370
- prodkit-0.3.0/README.md +0 -300
- {prodkit-0.3.0 → prodkit-0.4.0}/.gitignore +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/LICENSE +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/cli/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/cli/loader.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/contracts/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/contracts/plugin.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/config.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/context.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/doctor.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/event_bus.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/exceptions.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/lifecycle.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/plugin_manager.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/production.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/core/registry.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/_redis.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/cache/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/compression/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/cors/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/errors/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/health/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/logging/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/metrics/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/rate_limit/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/rate_limit/backends.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/request_id/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/plugins/security/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/src/prodkit/py.typed +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/conftest.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/integration/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/integration/test_cli.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/integration/test_logging.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/integration/test_production.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/__init__.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_cache.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_config.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_doctor.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_kernel.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_metrics.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_rate_limit.py +0 -0
- {prodkit-0.3.0 → prodkit-0.4.0}/tests/unit/test_tracing.py +0 -0
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.0] - 2026-08-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`prodkit generate` CLI suite**:
|
|
14
|
+
- `prodkit generate docker`: hardened, multi-stage non-root Dockerfile and `.dockerignore`.
|
|
15
|
+
- `prodkit generate compose`: `docker-compose.yml` with healthchecks, environment mapping, and conditional Redis service detection.
|
|
16
|
+
- `prodkit generate nginx`: production reverse-proxy config with W3C traceparent pass-through, request-ID correlation, and gzip compression.
|
|
17
|
+
- `prodkit generate github`: `.github/workflows/ci.yml` with matrix testing across Python 3.10-3.13, linting, typechecking, coverage, and `prodkit doctor --strict` CI gate.
|
|
18
|
+
- `prodkit generate env`: `.env.example` template covering all `ProdKitConfig` parameters and defaults.
|
|
19
|
+
- `prodkit generate all`: single-command scaffolding for all deployment assets.
|
|
20
|
+
- **Generator Engine** (`prodkit.generators`): decoupled generator classes (`DockerGenerator`, `ComposeGenerator`, `NginxGenerator`, `GitHubGenerator`, `EnvGenerator`) supporting programmatic rendering, `--dry-run` previews, `--force` overwriting, and context-aware templating.
|
|
21
|
+
|
|
10
22
|
## [0.3.0] - 2026-08-14
|
|
11
23
|
|
|
12
24
|
### Added
|
prodkit-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: prodkit
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: The production framework for FastAPI. One line. Production ready.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Pushkarpant/PRODKIT
|
|
6
|
+
Project-URL: Documentation, https://github.com/Pushkarpant/PRODKIT#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/Pushkarpant/PRODKIT
|
|
8
|
+
Project-URL: Changelog, https://github.com/Pushkarpant/PRODKIT/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/Pushkarpant/PRODKIT/issues
|
|
10
|
+
Author-email: Pushkar Pant <pantpushkar4@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: fastapi,health-check,logging,metrics,middleware,observability,opentelemetry,production,security,tracing
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: fastapi>=0.110
|
|
28
|
+
Requires-Dist: pydantic-settings>=2.1
|
|
29
|
+
Requires-Dist: pydantic>=2.5
|
|
30
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: brotli-asgi>=1.4; extra == 'all'
|
|
33
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == 'all'
|
|
34
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20; extra == 'all'
|
|
35
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'all'
|
|
36
|
+
Requires-Dist: prometheus-client>=0.20; extra == 'all'
|
|
37
|
+
Requires-Dist: redis>=5.0; extra == 'all'
|
|
38
|
+
Requires-Dist: rich>=13; extra == 'all'
|
|
39
|
+
Requires-Dist: typer>=0.12; extra == 'all'
|
|
40
|
+
Provides-Extra: brotli
|
|
41
|
+
Requires-Dist: brotli-asgi>=1.4; extra == 'brotli'
|
|
42
|
+
Provides-Extra: cli
|
|
43
|
+
Requires-Dist: rich>=13; extra == 'cli'
|
|
44
|
+
Requires-Dist: typer>=0.12; extra == 'cli'
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: anyio[trio]>=4.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: fakeredis[lua]>=2.21; extra == 'dev'
|
|
48
|
+
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
49
|
+
Requires-Dist: import-linter>=2.0; extra == 'dev'
|
|
50
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
51
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == 'dev'
|
|
52
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'dev'
|
|
53
|
+
Requires-Dist: prometheus-client>=0.20; extra == 'dev'
|
|
54
|
+
Requires-Dist: pytest-anyio>=0.0.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
56
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
57
|
+
Requires-Dist: rich>=13; extra == 'dev'
|
|
58
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
59
|
+
Requires-Dist: tomli>=2.0; extra == 'dev'
|
|
60
|
+
Requires-Dist: typer>=0.12; extra == 'dev'
|
|
61
|
+
Provides-Extra: metrics
|
|
62
|
+
Requires-Dist: prometheus-client>=0.20; extra == 'metrics'
|
|
63
|
+
Provides-Extra: otel
|
|
64
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == 'otel'
|
|
65
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.20; extra == 'otel'
|
|
66
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == 'otel'
|
|
67
|
+
Provides-Extra: redis
|
|
68
|
+
Requires-Dist: redis>=5.0; extra == 'redis'
|
|
69
|
+
Description-Content-Type: text/markdown
|
|
70
|
+
|
|
71
|
+
<div align="center">
|
|
72
|
+
|
|
73
|
+
# ⚡ ProdKit
|
|
74
|
+
|
|
75
|
+
### *One line. Production ready.*
|
|
76
|
+
|
|
77
|
+
The production engine for **[FastAPI](https://fastapi.tiangolo.com/)**.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from fastapi import FastAPI
|
|
81
|
+
from prodkit import Production
|
|
82
|
+
|
|
83
|
+
app = FastAPI()
|
|
84
|
+
Production(app) # 👈 That's it. Production hardened.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
[](https://pypi.org/project/prodkit/)
|
|
88
|
+
[](https://pypi.org/project/prodkit/)
|
|
89
|
+
[](https://github.com/Pushkarpant/PRODKIT/actions/workflows/ci.yml)
|
|
90
|
+
[](https://github.com/Pushkarpant/PRODKIT/blob/main/LICENSE)
|
|
91
|
+
[](https://github.com/astral-sh/ruff)
|
|
92
|
+
|
|
93
|
+
[⚡ Quick Start](#quick-start) · [📦 Installation](#installation) · [✨ What You Get](#what-you-get) · [🩺 CLI Doctor](#cli-doctor) · [🚀 Generators](#generators) · [🎛️ Configuration](#configuration) · [🔌 Plugins](#plugins) · [🗺️ Roadmap](#roadmap)
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<br/>
|
|
100
|
+
|
|
101
|
+
## 🎯 The Problem & Solution
|
|
102
|
+
|
|
103
|
+
<details open>
|
|
104
|
+
<summary><b>💡 Why does ProdKit exist? (Click to toggle comparison)</b></summary>
|
|
105
|
+
|
|
106
|
+
<br/>
|
|
107
|
+
|
|
108
|
+
Every FastAPI service that goes to production re-implements the exact same **~500 lines of glue code**: security headers, JSON access logs, request-ID correlation, RFC 9457 error normalization, Kubernetes health probes, CORS safety, and rate-limiting.
|
|
109
|
+
|
|
110
|
+
FastAPI is a micro-framework and deliberately omits this. **ProdKit provides the production batteries in a single import.**
|
|
111
|
+
|
|
112
|
+
| Without ProdKit ❌ | With ProdKit (`Production(app)`) ✅ |
|
|
113
|
+
|---|---|
|
|
114
|
+
| 🔴 Plain error 500s leak python stack traces to clients | 🛡️ RFC 9457 `problem+json` — 500s opaque to users, traced in logs |
|
|
115
|
+
| 🔴 Ad-hoc log lines without correlation IDs | 📋 Structured JSON logs with auto-injected `X-Request-ID` |
|
|
116
|
+
| 🔴 Missing security headers (vulnerable to clickjacking/sniffing) | 🔒 OWASP-hardened headers (`nosniff`, `DENY`, HSTS, CSP) |
|
|
117
|
+
| 🔴 Wildcard CORS combined with credentials footgun | 🚫 Refuses unsafe prod configs at startup with named key error |
|
|
118
|
+
| 🔴 Hand-rolled `/health` endpoints that don't check dependencies | 🏥 Native `/health`, `/live`, and `/ready` with dependency checks |
|
|
119
|
+
| 🔴 Hard to update when security standards evolve | 🔄 `pip install -U prodkit` upgrades all your apps in seconds |
|
|
120
|
+
|
|
121
|
+
</details>
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
<a id="quick-start"></a>
|
|
126
|
+
## 💻 Interactive Quick Start
|
|
127
|
+
|
|
128
|
+
### 1️⃣ Run Your App
|
|
129
|
+
```python
|
|
130
|
+
# main.py
|
|
131
|
+
from fastapi import FastAPI
|
|
132
|
+
from prodkit import Production
|
|
133
|
+
|
|
134
|
+
app = FastAPI(title="Payment Service")
|
|
135
|
+
Production(app) # Auto-configures production profile
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@app.get("/charge")
|
|
139
|
+
def charge():
|
|
140
|
+
return {"status": "success"}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uvicorn main:app
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 2️⃣ Inspect Production Headers & Request Tracing
|
|
148
|
+
|
|
149
|
+
<details open>
|
|
150
|
+
<summary><b>🔍 <code>curl -i http://localhost:8000/charge</code> (Click to inspect output)</b></summary>
|
|
151
|
+
|
|
152
|
+
```http
|
|
153
|
+
HTTP/1.1 200 OK
|
|
154
|
+
content-type: application/json
|
|
155
|
+
x-request-id: 26fdc49565614c2a9ef1a3b8d4e0f712
|
|
156
|
+
x-content-type-options: nosniff
|
|
157
|
+
x-frame-options: DENY
|
|
158
|
+
strict-transport-security: max-age=63072000; includeSubDomains
|
|
159
|
+
referrer-policy: strict-origin-when-cross-origin
|
|
160
|
+
permissions-policy: camera=(), microphone=(), geolocation=()
|
|
161
|
+
x-xss-protection: 0
|
|
162
|
+
|
|
163
|
+
{"status":"success"}
|
|
164
|
+
```
|
|
165
|
+
</details>
|
|
166
|
+
|
|
167
|
+
<details>
|
|
168
|
+
<summary><b>🏥 <code>curl -i http://localhost:8000/ready</code> (Kubernetes Readiness Check)</b></summary>
|
|
169
|
+
|
|
170
|
+
```http
|
|
171
|
+
HTTP/1.1 200 OK
|
|
172
|
+
content-type: application/json
|
|
173
|
+
|
|
174
|
+
{
|
|
175
|
+
"status": "ready",
|
|
176
|
+
"checks": [
|
|
177
|
+
{ "name": "request-id", "passed": true },
|
|
178
|
+
{ "name": "logging", "passed": true },
|
|
179
|
+
{ "name": "security", "passed": true }
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
</details>
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
<a id="installation"></a>
|
|
188
|
+
## 📦 Installation
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# Base framework (zero extra dependencies)
|
|
192
|
+
pip install prodkit
|
|
193
|
+
|
|
194
|
+
# Recommended extras
|
|
195
|
+
pip install "prodkit[cli]" # Includes `prodkit doctor` CLI (typer + rich)
|
|
196
|
+
pip install "prodkit[metrics]" # Prometheus /metrics endpoint
|
|
197
|
+
pip install "prodkit[otel]" # OpenTelemetry tracing
|
|
198
|
+
pip install "prodkit[redis]" # Distributed Redis rate-limiting & cache
|
|
199
|
+
pip install "prodkit[all]" # All available plugins and extras
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
| Extra | Adds | Dependencies |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `cli` | `prodkit doctor`, `generate`, `inspect`, `init` | `typer`, `rich` |
|
|
205
|
+
| `metrics` | Prometheus metrics endpoint (`/metrics`) | `prometheus-client` |
|
|
206
|
+
| `otel` | W3C distributed tracing with OpenTelemetry | `opentelemetry-api`, `opentelemetry-sdk` |
|
|
207
|
+
| `redis` | Multi-worker rate limiting & distributed cache | `redis` / `fakeredis` |
|
|
208
|
+
| `brotli` | High-ratio Brotli response compression | `brotli` |
|
|
209
|
+
| `all` | Everything above | All optional extras |
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
<a id="what-you-get"></a>
|
|
214
|
+
## ✨ What You Get Out of the Box
|
|
215
|
+
|
|
216
|
+
ProdKit includes **11 modular built-in plugins**, organized with explicit middleware execution priorities:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
100 RequestID (Outer-most: generates/extracts X-Request-ID)
|
|
220
|
+
200 Structured Logging (Correlates log lines with Request ID & timing)
|
|
221
|
+
290 OpenTelemetry (Request tracing spans & W3C context propagation)
|
|
222
|
+
300 Prometheus Metrics (Exposes /metrics with route-template labels)
|
|
223
|
+
400 Security Headers (OWASP nosniff, HSTS, X-Frame-Options, CSP)
|
|
224
|
+
500 CORS Safety (Strict origin validation, refuses wildcard+creds)
|
|
225
|
+
600 Rate Limiting (Per-IP window limits, memory or Redis backend)
|
|
226
|
+
700 Compression (Gzip & Brotli response compression)
|
|
227
|
+
[ Your FastAPI App Code ]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
<details>
|
|
231
|
+
<summary><b>📖 Expand Complete Feature Matrix</b></summary>
|
|
232
|
+
|
|
233
|
+
<br/>
|
|
234
|
+
|
|
235
|
+
| Icon | Feature | Description | Default |
|
|
236
|
+
|:---:|---|---|:---:|
|
|
237
|
+
| 🆔 | **Request IDs** | `X-Request-ID` attached to every response, bound to async context for log correlation. | `On` |
|
|
238
|
+
| 📋 | **Structured Logging** | Production JSON logs (Datadog/CloudWatch/Loki ready) or colorful console logs in dev. | `On` |
|
|
239
|
+
| 🛡️ | **Security Headers** | `nosniff`, `X-Frame-Options: DENY`, `Strict-Transport-Security`, `Referrer-Policy`. | `On` |
|
|
240
|
+
| 🚨 | **Error Normalization** | [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) `problem+json` standard. 500 tracebacks hidden in prod. | `On` |
|
|
241
|
+
| ❤️ | **Health Probes** | K8s endpoints: `/health` (liveness), `/live`, and `/ready` (aggregates plugin checks). | `On` |
|
|
242
|
+
| 🌐 | **CORS Guard** | Prevents insecure wildcard credentials (`origins=["*"]` + `credentials=True` fails boot). | `Configured` |
|
|
243
|
+
| 📦 | **Compression** | Automatic Gzip (and optional Brotli) compression for payloads > 500 bytes. | `On` |
|
|
244
|
+
| 🚦 | **Rate Limiting** | Per-IP sliding limits (`100/minute`), returns `429 Too Many Requests` with `Retry-After`. | `Opt-in` |
|
|
245
|
+
| 📊 | **Prometheus Metrics** | Scrapeable `/metrics` endpoint (request totals, duration histograms, in-flight gauges). | `Opt-in` |
|
|
246
|
+
| 🗄️ | **Cache Service** | Injection-ready cache (`MemoryCache` or `RedisCache`) registered in app context. | `Opt-in` |
|
|
247
|
+
| 🔭 | **OpenTelemetry** | Auto-instrumentation of HTTP requests with OTLP/Console exporters & W3C headers. | `Opt-in` |
|
|
248
|
+
|
|
249
|
+
</details>
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
<a id="cli-doctor"></a>
|
|
254
|
+
## 🩺 CLI — `prodkit doctor`
|
|
255
|
+
|
|
256
|
+
Run static & runtime security audits against your app and get a **0–100 Production Score**:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
prodkit doctor --app main:app
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
Production Readiness Audit
|
|
264
|
+
┌───┬────────────────────────┬─────────────────────┬──────────────────────────┐
|
|
265
|
+
│ ✔ │ Security headers │ nosniff, X-Frame... │ │
|
|
266
|
+
│ ✔ │ Structured logging │ json @ INFO │ │
|
|
267
|
+
│ ✔ │ Error normalization │ 500s opaque │ │
|
|
268
|
+
│ ✔ │ Request IDs │ enabled (header) │ │
|
|
269
|
+
│ ✔ │ Health probes │ /health /ready │ │
|
|
270
|
+
│ ⚠ │ Rate limiting │ memory backend │ set backend="redis" ... │
|
|
271
|
+
│ ⚠ │ Content-Security-Policy│ default-src missing │ set CSP for web apps │
|
|
272
|
+
└───┴────────────────────────┴─────────────────────┴──────────────────────────┘
|
|
273
|
+
Production Score: 88 / 100 [ 2 Warning(s) ]
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 🚦 Gate CI/CD Builds
|
|
277
|
+
Enforce production standards in GitHub Actions or GitLab CI:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Fails CI build (exit code 1) if production readiness score falls below threshold
|
|
281
|
+
prodkit doctor --app main:app --strict --min-score 90
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
<a id="generators"></a>
|
|
287
|
+
## 🚀 Infrastructure & Deployment Generators (`prodkit generate`)
|
|
288
|
+
|
|
289
|
+
Scaffold production-grade deployment assets tailored to your application's resolved configuration and active plugins:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Generate all deployment assets at once
|
|
293
|
+
prodkit generate all
|
|
294
|
+
|
|
295
|
+
# Preview generated assets without writing to disk
|
|
296
|
+
prodkit generate all --dry-run
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
```text
|
|
300
|
+
Generated deployment assets
|
|
301
|
+
┌─────────┬──────────────────────────┬────────────────────────────────────────┐
|
|
302
|
+
│ Status │ File │ Description │
|
|
303
|
+
├─────────┼──────────────────────────┼────────────────────────────────────────┤
|
|
304
|
+
│ created │ Dockerfile │ Multi-stage, non-root production image │
|
|
305
|
+
│ created │ .dockerignore │ Docker build ignore file │
|
|
306
|
+
│ created │ docker-compose.yml │ Multi-service Compose definition │
|
|
307
|
+
│ created │ nginx.conf │ Hardened Nginx reverse-proxy │
|
|
308
|
+
│ created │ .github/workflows/ci.yml │ CI quality & testing with doctor gate │
|
|
309
|
+
│ created │ .env.example │ Environment configuration template │
|
|
310
|
+
└─────────┴──────────────────────────┴────────────────────────────────────────┘
|
|
311
|
+
Successfully generated 6 file(s).
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 🧩 Individual Generators
|
|
315
|
+
|
|
316
|
+
| Command | Generated Artifact | Key Features |
|
|
317
|
+
|---|---|---|
|
|
318
|
+
| `prodkit generate docker` | `Dockerfile`, `.dockerignore` | Multi-stage builder, non-root `appuser:10001`, `HEALTHCHECK`, `uvicorn` workers |
|
|
319
|
+
| `prodkit generate compose` | `docker-compose.yml` | Healthcheck dependencies, auto-detects Redis services and network volumes |
|
|
320
|
+
| `prodkit generate nginx` | `nginx.conf` | Reverse-proxy, W3C `traceparent` propagation, `X-Request-ID`, gzip compression |
|
|
321
|
+
| `prodkit generate github` | `.github/workflows/ci.yml` | Python 3.10–3.13 matrix, `ruff`, `mypy --strict`, `pytest`, `prodkit doctor` gate |
|
|
322
|
+
| `prodkit generate env` | `.env.example` | Dynamic schema documentation with defaults and production notes |
|
|
323
|
+
|
|
324
|
+
<details>
|
|
325
|
+
<summary><b>🛠️ More CLI Commands (<code>inspect</code>, <code>plugins</code>, <code>init</code>)</b></summary>
|
|
326
|
+
|
|
327
|
+
<br/>
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# View resolved configuration, active plugins, and middleware execution stack:
|
|
331
|
+
prodkit inspect --app main:app
|
|
332
|
+
|
|
333
|
+
# List all active plugins and their implemented lifecycle hooks:
|
|
334
|
+
prodkit plugins --app main:app
|
|
335
|
+
|
|
336
|
+
# Scaffold starter prodkit.toml configuration file:
|
|
337
|
+
prodkit init --example
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
</details>
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
<a id="configuration"></a>
|
|
345
|
+
## 🎛️ Configuration
|
|
346
|
+
|
|
347
|
+
ProdKit merges configuration across **4 priority layers** (highest wins):
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
Python Args ──► Environment Vars ──► prodkit.toml ──► Profile Defaults
|
|
351
|
+
(Highest) (Lowest)
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
<details open>
|
|
355
|
+
<summary><b>⚙️ Choose Configuration Style (Click to tab)</b></summary>
|
|
356
|
+
|
|
357
|
+
#### Option A: Python Arguments
|
|
358
|
+
```python
|
|
359
|
+
Production(
|
|
360
|
+
app,
|
|
361
|
+
environment="production",
|
|
362
|
+
cors={"origins": ["https://app.example.com"]},
|
|
363
|
+
rate_limit={"default": "100/minute", "backend": "redis"},
|
|
364
|
+
metrics=True,
|
|
365
|
+
tracing={"exporter": "otlp", "sample_rate": 0.2},
|
|
366
|
+
)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
#### Option B: `prodkit.toml`
|
|
370
|
+
```toml
|
|
371
|
+
[prodkit]
|
|
372
|
+
environment = "production"
|
|
373
|
+
|
|
374
|
+
[logging]
|
|
375
|
+
level = "INFO"
|
|
376
|
+
format = "json"
|
|
377
|
+
|
|
378
|
+
[rate_limit]
|
|
379
|
+
enabled = true
|
|
380
|
+
default = "100/minute"
|
|
381
|
+
backend = "redis"
|
|
382
|
+
|
|
383
|
+
[metrics]
|
|
384
|
+
enabled = true
|
|
385
|
+
path = "/metrics"
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### Option C: Environment Variables (`__` for nested keys)
|
|
389
|
+
```bash
|
|
390
|
+
export PRODKIT_ENVIRONMENT=production
|
|
391
|
+
export PRODKIT_LOGGING__LEVEL=WARNING
|
|
392
|
+
export PRODKIT_RATE_LIMIT__BACKEND=redis
|
|
393
|
+
export PRODKIT_METRICS__ENABLED=true
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
</details>
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
<a id="plugins"></a>
|
|
401
|
+
## 🔌 Writing a Custom Plugin
|
|
402
|
+
|
|
403
|
+
All features in ProdKit (including built-ins) are plugins implementing the `Plugin` contract.
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
from prodkit import Plugin, Check, Audit, Production
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class DatabaseHealthPlugin(Plugin):
|
|
410
|
+
name = "db-health"
|
|
411
|
+
requires = [] # Dependency ordering
|
|
412
|
+
|
|
413
|
+
async def startup(self, ctx):
|
|
414
|
+
# Async resource setup
|
|
415
|
+
ctx.registry.provide("db_pool", await connect_db())
|
|
416
|
+
|
|
417
|
+
async def shutdown(self, ctx):
|
|
418
|
+
pool = ctx.registry.get("db_pool")
|
|
419
|
+
await pool.close()
|
|
420
|
+
|
|
421
|
+
def checks(self, ctx):
|
|
422
|
+
# Feeds into K8s /ready probe
|
|
423
|
+
is_connected = ctx.registry.get("db_pool").is_active()
|
|
424
|
+
return [Check(name="database", passed=is_connected)]
|
|
425
|
+
|
|
426
|
+
def doctor(self, ctx):
|
|
427
|
+
# Feeds into `prodkit doctor` score
|
|
428
|
+
return [Audit(name="Database Connection", status="ok", detail="Pool initialized")]
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
Production(app, plugins=[DatabaseHealthPlugin()])
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## 🛡️ Plays Nice With Your App
|
|
437
|
+
|
|
438
|
+
- **Zero Lock-in**: Mutates/wraps the FastAPI instance. Remove `Production(app)` anytime to return to plain FastAPI.
|
|
439
|
+
- **Lifespan Composition**: Your custom `@asynccontextmanager` lifespan is preserved and wrapped (Plugin startup → App lifespan → Plugin shutdown).
|
|
440
|
+
- **Your Code Wins**: If your route explicitly sets a header or error handler, your application code takes precedence.
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
<a id="roadmap"></a>
|
|
445
|
+
## 🗺️ Project Status & Roadmap
|
|
446
|
+
|
|
447
|
+
| Version | Status | Highlights |
|
|
448
|
+
|---|---|---|
|
|
449
|
+
| **v0.1.0** | ✅ Released | Core kernel, security headers, JSON logs, RFC 9457 error normalization, `/health` |
|
|
450
|
+
| **v0.2.0** | ✅ Released | `prodkit doctor` CLI, readiness score, in-memory rate limiting |
|
|
451
|
+
| **v0.3.0** | ✅ Released | Prometheus metrics, Redis backends, OpenTelemetry tracing, Cache service |
|
|
452
|
+
| **v0.4.0** | ✅ **Current** | **`prodkit generate` (Dockerfile, nginx, docker-compose, GitHub Actions CI, .env)** |
|
|
453
|
+
| **v0.5.0** | 🚧 Next | Public Plugin SDK & Ecosystem (`prodkit-sentry`, entry-point discovery) |
|
|
454
|
+
| **v1.0.0** | 🎯 Milestone | Frozen Public API, LTS release, Production case studies |
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## 🤝 Contributing & License
|
|
459
|
+
|
|
460
|
+
We welcome contributions! Please see [CONTRIBUTING.md](https://github.com/Pushkarpant/PRODKIT/blob/main/CONTRIBUTING.md) and [SECURITY.md](https://github.com/Pushkarpant/PRODKIT/blob/main/SECURITY.md).
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
git clone https://github.com/Pushkarpant/PRODKIT.git
|
|
464
|
+
cd PRODKIT
|
|
465
|
+
python -m venv .venv && source .venv/bin/activate # on Windows: .venv\Scripts\activate
|
|
466
|
+
pip install -e ".[dev,all]"
|
|
467
|
+
pytest
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Distributed under the **[MIT License](https://github.com/Pushkarpant/PRODKIT/blob/main/LICENSE)**.
|
|
471
|
+
|
|
472
|
+
<br/>
|
|
473
|
+
|
|
474
|
+
<div align="center">
|
|
475
|
+
|
|
476
|
+
**Built with ❤️ by [Pushkar Pant](https://github.com/Pushkarpant)**
|
|
477
|
+
|
|
478
|
+
*FastAPI builds APIs. ProdKit makes them production-ready.*
|
|
479
|
+
|
|
480
|
+
</div>
|