svc-infra 0.1.621__py3-none-any.whl → 0.1.623__py3-none-any.whl
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.
Potentially problematic release.
This version of svc-infra might be problematic. Click here for more details.
- svc_infra/cli/cmds/docs/docs_cmds.py +102 -179
- svc_infra/docs/acceptance-matrix.md +71 -0
- svc_infra/docs/acceptance.md +44 -0
- svc_infra/docs/adr/0002-background-jobs-and-scheduling.md +40 -0
- svc_infra/docs/adr/0003-webhooks-framework.md +24 -0
- svc_infra/docs/adr/0004-tenancy-model.md +42 -0
- svc_infra/docs/adr/0005-data-lifecycle.md +86 -0
- svc_infra/docs/adr/0006-ops-slos-and-metrics.md +47 -0
- svc_infra/docs/adr/0007-docs-and-sdks.md +83 -0
- svc_infra/docs/adr/0008-billing-primitives.md +109 -0
- svc_infra/docs/adr/0009-acceptance-harness.md +40 -0
- svc_infra/docs/api.md +59 -0
- svc_infra/docs/auth.md +11 -0
- svc_infra/docs/cache.md +18 -0
- svc_infra/docs/cli.md +74 -0
- svc_infra/docs/contributing.md +34 -0
- svc_infra/docs/data-lifecycle.md +52 -0
- svc_infra/docs/database.md +14 -0
- svc_infra/docs/docs-and-sdks.md +62 -0
- svc_infra/docs/environment.md +114 -0
- svc_infra/docs/idempotency.md +111 -0
- svc_infra/docs/jobs.md +67 -0
- svc_infra/docs/observability.md +16 -0
- svc_infra/docs/ops.md +33 -0
- svc_infra/docs/rate-limiting.md +121 -0
- svc_infra/docs/repo-review.md +48 -0
- svc_infra/docs/security.md +155 -0
- svc_infra/docs/tenancy.md +35 -0
- svc_infra/docs/webhooks.md +112 -0
- {svc_infra-0.1.621.dist-info → svc_infra-0.1.623.dist-info}/METADATA +16 -16
- {svc_infra-0.1.621.dist-info → svc_infra-0.1.623.dist-info}/RECORD +33 -5
- {svc_infra-0.1.621.dist-info → svc_infra-0.1.623.dist-info}/WHEEL +0 -0
- {svc_infra-0.1.621.dist-info → svc_infra-0.1.623.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Security: Configuration & Examples
|
|
2
|
+
|
|
3
|
+
This guide covers the security primitives built into svc-infra and how to wire them:
|
|
4
|
+
|
|
5
|
+
> ℹ️ Environment variables for the auth/security helpers are catalogued in [Environment Reference](environment.md).
|
|
6
|
+
|
|
7
|
+
- Password policy and breach checking
|
|
8
|
+
- Account lockout (exponential backoff)
|
|
9
|
+
- Sessions and refresh tokens (rotation + revocation)
|
|
10
|
+
- JWT key rotation
|
|
11
|
+
- Signed cookies
|
|
12
|
+
- CORS and security headers
|
|
13
|
+
- RBAC and ABAC
|
|
14
|
+
- MFA policy hooks
|
|
15
|
+
|
|
16
|
+
Module map (examples reference these):
|
|
17
|
+
- `svc_infra.security.lockout` (LockoutConfig, compute_lockout, record_attempt, get_lockout_status)
|
|
18
|
+
- `svc_infra.security.signed_cookies` (sign_cookie, verify_cookie)
|
|
19
|
+
- `svc_infra.security.audit` and `security.audit_service` (hash-chain audit logs)
|
|
20
|
+
- `svc_infra.api.fastapi.auth.gaurd` (password login with lockout checks)
|
|
21
|
+
- `svc_infra.api.fastapi.auth.routers.*` (sessions, oauth routes, etc.)
|
|
22
|
+
- `svc_infra.api.fastapi.auth.settings.get_auth_settings` (cookie + token settings)
|
|
23
|
+
- `svc_infra.api.fastapi.middleware.security_headers` and CORS setup (strict defaults)
|
|
24
|
+
|
|
25
|
+
## Password policy and breach checking
|
|
26
|
+
- Enforced by validators with a configurable policy.
|
|
27
|
+
- Breach checking uses the HIBP k-Anonymity range API; can be toggled via settings.
|
|
28
|
+
|
|
29
|
+
Example toggles (pseudo-config):
|
|
30
|
+
- `AUTH_PASSWORD_MIN_LENGTH=12`
|
|
31
|
+
- `AUTH_PASSWORD_REQUIRE_SYMBOL=True`
|
|
32
|
+
- `AUTH_PASSWORD_BREACH_CHECK=True`
|
|
33
|
+
|
|
34
|
+
## Account lockout
|
|
35
|
+
- Exponential backoff with a max cooldown cap to deter credential stuffing.
|
|
36
|
+
- Attempts tracked by user_id and/or IP hash.
|
|
37
|
+
- Login endpoint blocks with 429 + `Retry-After` during cooldown.
|
|
38
|
+
|
|
39
|
+
Key API (from `svc_infra.security.lockout`):
|
|
40
|
+
- `LockoutConfig(threshold=5, window_minutes=15, base_cooldown_seconds=30, max_cooldown_seconds=3600)`
|
|
41
|
+
- `compute_lockout(fail_count, cfg)` → `LockoutStatus(locked, next_allowed_at, failure_count)`
|
|
42
|
+
- `record_attempt(session, user_id, ip_hash, success)`
|
|
43
|
+
- `get_lockout_status(session, user_id, ip_hash, cfg)`
|
|
44
|
+
|
|
45
|
+
Login integration (simplified):
|
|
46
|
+
```python
|
|
47
|
+
from svc_infra.security.lockout import get_lockout_status, record_attempt
|
|
48
|
+
|
|
49
|
+
# Compute ip_hash from request.client.host
|
|
50
|
+
status = await get_lockout_status(session, user_id=None, ip_hash=ip_hash)
|
|
51
|
+
if status.locked:
|
|
52
|
+
raise HTTPException(429, headers={"Retry-After": ..})
|
|
53
|
+
|
|
54
|
+
user = await user_manager.user_db.get_by_email(email)
|
|
55
|
+
if not user:
|
|
56
|
+
await record_attempt(session, user_id=None, ip_hash=ip_hash, success=False)
|
|
57
|
+
raise HTTPException(400, "LOGIN_BAD_CREDENTIALS")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Sessions and refresh tokens
|
|
61
|
+
- Sessions are enumerable and revocable via the sessions router.
|
|
62
|
+
- Refresh tokens are rotated; old tokens are invalidated via a revocation list.
|
|
63
|
+
|
|
64
|
+
Operational notes:
|
|
65
|
+
- Persist sessions/tokens in a durable DB.
|
|
66
|
+
- Favor short access token TTLs if refresh flow is robust.
|
|
67
|
+
|
|
68
|
+
## JWT key rotation
|
|
69
|
+
- Primary secret plus `old_secrets` allow seamless rotation.
|
|
70
|
+
- Set environment variables:
|
|
71
|
+
- `AUTH_JWT__SECRET="..."`
|
|
72
|
+
- `AUTH_JWT__OLD_SECRETS="old1,old2"`
|
|
73
|
+
|
|
74
|
+
## Signed cookies
|
|
75
|
+
Module: `svc_infra.security.signed_cookies`
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from svc_infra.security.signed_cookies import sign_cookie, verify_cookie
|
|
79
|
+
|
|
80
|
+
sig = sign_cookie({"sub": "user-123"}, secret="k1", exp_seconds=3600)
|
|
81
|
+
payload = verify_cookie(sig, secret="k1", old_secrets=["k0"]) # returns dict
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## CORS and security headers
|
|
85
|
+
- Strict CORS defaults (deny by default). Provide allowlist entries.
|
|
86
|
+
- Security headers middleware sets common protections (X-Frame-Options, X-Content-Type-Options, etc.).
|
|
87
|
+
|
|
88
|
+
Use `svc_infra.security.add.add_security` to install the default middlewares on any
|
|
89
|
+
FastAPI app. By default it adds:
|
|
90
|
+
|
|
91
|
+
- `SecurityHeadersMiddleware` with strict defaults (HSTS, X-Frame-Options, etc.).
|
|
92
|
+
- A strict `CORSMiddleware` that only enables CORS when origins are provided (via
|
|
93
|
+
parameters or environment variables such as `CORS_ALLOW_ORIGINS`).
|
|
94
|
+
|
|
95
|
+
The helper also supports optional toggles so you can match the same cookie and
|
|
96
|
+
header configuration that `setup_service_api` uses.
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from fastapi import FastAPI
|
|
100
|
+
|
|
101
|
+
from svc_infra.security.add import add_security
|
|
102
|
+
|
|
103
|
+
app = FastAPI()
|
|
104
|
+
|
|
105
|
+
add_security(
|
|
106
|
+
app,
|
|
107
|
+
cors_origins=["https://app.example.com"],
|
|
108
|
+
headers_overrides={"Content-Security-Policy": "default-src 'self'"},
|
|
109
|
+
install_session_middleware=True, # adds Starlette's SessionMiddleware
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Environment variables (applied when parameters are omitted):
|
|
114
|
+
|
|
115
|
+
| Variable | Purpose |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `CORS_ALLOW_ORIGINS` | Comma-separated CORS origins (e.g. `https://app.example.com, https://admin.example.com`) |
|
|
118
|
+
| `CORS_ALLOW_METHODS` | Allowed HTTP methods (defaults to `*`) |
|
|
119
|
+
| `CORS_ALLOW_HEADERS` | Allowed headers (defaults to `*`) |
|
|
120
|
+
| `CORS_ALLOW_ORIGIN_REGEX` | Regex used when matching origins (ignored if not set) |
|
|
121
|
+
| `CORS_ALLOW_CREDENTIALS` | Toggle credentials support (`true` / `false`) |
|
|
122
|
+
| `SESSION_COOKIE_NAME` | Session cookie name (defaults to `svc_session`) |
|
|
123
|
+
| `SESSION_COOKIE_MAX_AGE_SECONDS` | Max age for the session cookie (defaults to `14400`) |
|
|
124
|
+
| `SESSION_COOKIE_SAMESITE` | SameSite policy (`lax` by default) |
|
|
125
|
+
| `SESSION_COOKIE_SECURE` | Force the session cookie to be HTTPS-only |
|
|
126
|
+
| `SESSION_SECRET` | Secret key for Starlette's SessionMiddleware |
|
|
127
|
+
|
|
128
|
+
When your service already uses `setup_service_api`, call `add_security` after
|
|
129
|
+
building the parent app if you need additional overrides while keeping the
|
|
130
|
+
defaults intact:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from svc_infra.api.fastapi.setup import setup_service_api
|
|
134
|
+
from svc_infra.security.add import add_security
|
|
135
|
+
|
|
136
|
+
app = setup_service_api(...)
|
|
137
|
+
|
|
138
|
+
add_security(
|
|
139
|
+
app,
|
|
140
|
+
headers_overrides={"Strict-Transport-Security": "max-age=63072000; includeSubDomains"},
|
|
141
|
+
enable_hsts_preload=False,
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## RBAC and ABAC
|
|
146
|
+
- RBAC decorators guard endpoints by role/permission.
|
|
147
|
+
- ABAC evaluates resource ownership and attributes (e.g., `owns_resource`).
|
|
148
|
+
|
|
149
|
+
## MFA policy hooks
|
|
150
|
+
- Policy decides when MFA is required; login returns 401 with `MFA_REQUIRED` and a pre-token when applicable.
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
- 429 on login: lockout active. Check `Retry-After` and `FailedAuthAttempt` rows.
|
|
154
|
+
- Token invalid post-refresh: confirm rotation + revocation writes.
|
|
155
|
+
- Cookie verification errors: check signing keys/exp.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Tenancy model and integration
|
|
2
|
+
|
|
3
|
+
This framework uses a soft-tenant isolation model by default: tenant_id is a column on tenant-scoped tables, and all queries are filtered by this value. Consumers can later adopt schema-per-tenant or DB-per-tenant strategies; the API surfaces remain compatible.
|
|
4
|
+
|
|
5
|
+
## How tenant is resolved
|
|
6
|
+
- `resolve_tenant_id(request)` looks up tenant id in this order:
|
|
7
|
+
1) Global override hook (set via `add_tenancy(app, resolver=...)`)
|
|
8
|
+
2) Auth identity (user.tenant_id or api_key.tenant_id) when auth is enabled
|
|
9
|
+
3) `X-Tenant-Id` request header
|
|
10
|
+
4) `request.state.tenant_id`
|
|
11
|
+
|
|
12
|
+
Use `TenantId` dependency to require it in routes, and `OptionalTenantId` to access it if present.
|
|
13
|
+
|
|
14
|
+
## Enforcement in data layer
|
|
15
|
+
- Wrap services with `TenantSqlService` to automatically:
|
|
16
|
+
- Apply `WHERE model.tenant_id == <tenant>` on list/get/update/delete/search/count.
|
|
17
|
+
- Inject `tenant_id` upon create when the model has the tenant field.
|
|
18
|
+
|
|
19
|
+
## Tenant-aware CRUD router
|
|
20
|
+
- When defining a `SqlResource`, set `tenant_field="tenant_id"` to mount a tenant-aware CRUD router. All endpoints will require `TenantId` and enforce scoping.
|
|
21
|
+
|
|
22
|
+
## Per-tenant rate limits / quotas
|
|
23
|
+
- Global middleware and per-route dependency support tenant-aware policies:
|
|
24
|
+
- `scope_by_tenant=True` puts requests in independent buckets per tenant.
|
|
25
|
+
- `limit_resolver(request, tenant_id)` lets you return dynamic limits (e.g., plan-based quotas).
|
|
26
|
+
|
|
27
|
+
## Export a tenant’s data (SQL)
|
|
28
|
+
- CLI command: `sql export-tenant`
|
|
29
|
+
- Example:
|
|
30
|
+
- `python -m svc_infra.cli sql export-tenant items --tenant-id t1 --output out.json`
|
|
31
|
+
- Flags:
|
|
32
|
+
- `--tenant-id` (required), `--tenant-field` (default `tenant_id`), `--limit` (optional), `--database-url` (or set `SQL_URL`).
|
|
33
|
+
|
|
34
|
+
## Migration to other isolation strategies
|
|
35
|
+
- Schema-per-tenant or DB-per-tenant can be layered by adapting the session factory or repository to select the schema/DB based on `tenant_id`. Your application code that relies on `TenantId` and tenant-aware services/routers remains the same.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Webhooks Framework
|
|
2
|
+
|
|
3
|
+
This module provides primitives to publish events to external consumers via webhooks, verify inbound signatures, and handle robust retries using the shared JobQueue and Outbox patterns.
|
|
4
|
+
|
|
5
|
+
> ℹ️ Webhook helper environment expectations live in [Environment Reference](environment.md).
|
|
6
|
+
|
|
7
|
+
## Quickstart
|
|
8
|
+
|
|
9
|
+
- Subscriptions and publishing:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from svc_infra.webhooks.service import InMemoryWebhookSubscriptions, WebhookService
|
|
13
|
+
from svc_infra.db.outbox import InMemoryOutboxStore
|
|
14
|
+
|
|
15
|
+
subs = InMemoryWebhookSubscriptions()
|
|
16
|
+
subs.add("invoice.created", "https://example.com/webhook", "sekrit")
|
|
17
|
+
svc = WebhookService(outbox=InMemoryOutboxStore(), subs=subs)
|
|
18
|
+
svc.publish("invoice.created", {"id": "inv_1", "version": 1})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- Delivery worker and headers:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from svc_infra.jobs.builtins.webhook_delivery import make_webhook_handler
|
|
25
|
+
from svc_infra.jobs.worker import process_one
|
|
26
|
+
|
|
27
|
+
handler = make_webhook_handler(
|
|
28
|
+
outbox=..., inbox=..., get_webhook_url_for_topic=lambda t: url, get_secret_for_topic=lambda t: secret,
|
|
29
|
+
)
|
|
30
|
+
# process_one(queue, handler) will POST JSON with headers:
|
|
31
|
+
# X-Event-Id, X-Topic, X-Attempt, X-Signature (HMAC-SHA256), X-Signature-Alg, X-Signature-Version, X-Payload-Version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Verification (FastAPI):
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from fastapi import Depends, FastAPI
|
|
38
|
+
from svc_infra.webhooks.fastapi import require_signature
|
|
39
|
+
from svc_infra.webhooks.signing import sign
|
|
40
|
+
|
|
41
|
+
app = FastAPI()
|
|
42
|
+
app.post("/webhook")(lambda body=Depends(require_signature(lambda: ["old","new"])): {"ok": True})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## FastAPI wiring
|
|
46
|
+
|
|
47
|
+
- Attach the router with shared in-memory stores (great for tests / local runs):
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from fastapi import FastAPI
|
|
51
|
+
|
|
52
|
+
from svc_infra.webhooks import add_webhooks
|
|
53
|
+
|
|
54
|
+
app = FastAPI()
|
|
55
|
+
add_webhooks(app)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Respect environment overrides for Redis-backed stores by exporting `REDIS_URL`
|
|
59
|
+
and selecting the backend via `WEBHOOKS_OUTBOX=redis` (optional
|
|
60
|
+
`WEBHOOKS_INBOX=redis` for the dedupe store). The helper records the chosen
|
|
61
|
+
instances on `app.state` for further customisation:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import os
|
|
65
|
+
|
|
66
|
+
os.environ["WEBHOOKS_OUTBOX"] = "redis"
|
|
67
|
+
os.environ["WEBHOOKS_INBOX"] = "redis"
|
|
68
|
+
|
|
69
|
+
app = FastAPI()
|
|
70
|
+
add_webhooks(app) # creates RedisOutboxStore / RedisInboxStore when redis-py is available
|
|
71
|
+
|
|
72
|
+
# Later you can inspect or extend behaviour:
|
|
73
|
+
app.state.webhooks_subscriptions.add("invoice.created", "https://example.com/webhook", "sekrit")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- Provide explicit overrides (e.g. dependency-injected SQL stores) or reuse your
|
|
77
|
+
existing job queue / scheduler. Passing a queue automatically registers the
|
|
78
|
+
outbox tick and delivery handler so your worker loop can process jobs:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from svc_infra.jobs.easy import easy_jobs
|
|
82
|
+
|
|
83
|
+
queue, scheduler = easy_jobs()
|
|
84
|
+
|
|
85
|
+
add_webhooks(
|
|
86
|
+
app,
|
|
87
|
+
outbox=my_outbox_store,
|
|
88
|
+
inbox=lambda: my_inbox_store, # factories are supported
|
|
89
|
+
queue=queue,
|
|
90
|
+
scheduler=scheduler,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# scheduler.add_task(...) is handled internally when both queue and scheduler are supplied
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Runner wiring
|
|
97
|
+
|
|
98
|
+
If you prefer explicit wiring, you can still register the tick manually:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from svc_infra.jobs.easy import easy_jobs
|
|
102
|
+
from svc_infra.jobs.builtins.outbox_processor import make_outbox_tick
|
|
103
|
+
|
|
104
|
+
queue, scheduler = easy_jobs() # uses JOBS_DRIVER and REDIS_URL
|
|
105
|
+
scheduler.add_task("outbox", 1, make_outbox_tick(outbox_store, queue))
|
|
106
|
+
# Start runner: `svc-infra jobs run`
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Notes
|
|
110
|
+
- Retries/backoff are handled by the JobQueue; delivery marks Inbox after success to prevent duplicates.
|
|
111
|
+
- For production subscriptions and inbox/outbox, provide persistent implementations and override DI in your app.
|
|
112
|
+
- Signature rotation supported via `verify_any` and FastAPI dependency accepting multiple secrets.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: svc-infra
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.623
|
|
4
4
|
Summary: Infrastructure for building and deploying prod-ready services
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: fastapi,sqlalchemy,alembic,auth,infra,async,pydantic
|
|
@@ -77,7 +77,7 @@ Description-Content-Type: text/markdown
|
|
|
77
77
|
# svc-infra
|
|
78
78
|
|
|
79
79
|
[](https://pypi.org/project/svc-infra/)
|
|
80
|
-
[](docs/)
|
|
80
|
+
[](src/svc_infra/docs/)
|
|
81
81
|
|
|
82
82
|
svc-infra packages the shared building blocks we use to ship production FastAPI services fast—HTTP APIs with secure auth, durable persistence, background execution, cache, observability, and webhook plumbing that all share the same batteries-included defaults.
|
|
83
83
|
|
|
@@ -85,17 +85,17 @@ svc-infra packages the shared building blocks we use to ship production FastAPI
|
|
|
85
85
|
|
|
86
86
|
| Helper | What it covers | Guide |
|
|
87
87
|
| --- | --- | --- |
|
|
88
|
-
| API | FastAPI bootstrap, envelopes, middleware, docs wiring | [FastAPI guide](docs/api.md) |
|
|
89
|
-
| Auth | Sessions, OAuth/OIDC, MFA, SMTP delivery | [Auth settings](docs/auth.md) |
|
|
90
|
-
| Database | SQL + Mongo wiring, Alembic helpers, inbox/outbox patterns | [Database guide](docs/database.md) |
|
|
91
|
-
| Jobs | JobQueue, scheduler, CLI worker | [Jobs quickstart](docs/jobs.md) |
|
|
92
|
-
| Cache | cashews decorators, namespace management, TTL helpers | [Cache guide](docs/cache.md) |
|
|
93
|
-
| Observability | Prometheus middleware, Grafana automation, OTEL hooks | [Observability guide](docs/observability.md) |
|
|
94
|
-
| Ops | Probes, breaker, SLOs & dashboards | [SLOs & Ops](docs/ops.md) |
|
|
95
|
-
| Webhooks | Subscription store, signing, retry worker | [Webhooks framework](docs/webhooks.md) |
|
|
96
|
-
| Security | Password policy, lockout, signed cookies, headers | [Security hardening](docs/security.md) |
|
|
97
|
-
| Contributing | Dev setup and quality gates | [Contributing guide](docs/contributing.md) |
|
|
98
|
-
| Data Lifecycle | Fixtures, retention, erasure, backups | [Data lifecycle](docs/data-lifecycle.md) |
|
|
88
|
+
| API | FastAPI bootstrap, envelopes, middleware, docs wiring | [FastAPI guide](src/svc_infra/docs/api.md) |
|
|
89
|
+
| Auth | Sessions, OAuth/OIDC, MFA, SMTP delivery | [Auth settings](src/svc_infra/docs/auth.md) |
|
|
90
|
+
| Database | SQL + Mongo wiring, Alembic helpers, inbox/outbox patterns | [Database guide](src/svc_infra/docs/database.md) |
|
|
91
|
+
| Jobs | JobQueue, scheduler, CLI worker | [Jobs quickstart](src/svc_infra/docs/jobs.md) |
|
|
92
|
+
| Cache | cashews decorators, namespace management, TTL helpers | [Cache guide](src/svc_infra/docs/cache.md) |
|
|
93
|
+
| Observability | Prometheus middleware, Grafana automation, OTEL hooks | [Observability guide](src/svc_infra/docs/observability.md) |
|
|
94
|
+
| Ops | Probes, breaker, SLOs & dashboards | [SLOs & Ops](src/svc_infra/docs/ops.md) |
|
|
95
|
+
| Webhooks | Subscription store, signing, retry worker | [Webhooks framework](src/svc_infra/docs/webhooks.md) |
|
|
96
|
+
| Security | Password policy, lockout, signed cookies, headers | [Security hardening](src/svc_infra/docs/security.md) |
|
|
97
|
+
| Contributing | Dev setup and quality gates | [Contributing guide](src/svc_infra/docs/contributing.md) |
|
|
98
|
+
| Data Lifecycle | Fixtures, retention, erasure, backups | [Data lifecycle](src/svc_infra/docs/data-lifecycle.md) |
|
|
99
99
|
|
|
100
100
|
## Minimal FastAPI bootstrap
|
|
101
101
|
|
|
@@ -123,9 +123,9 @@ async def handle_webhook(payload = Depends(require_signature(lambda: ["current",
|
|
|
123
123
|
- **API** – toggle logging/observability and docs exposure with `ENABLE_LOGGING`, `LOG_LEVEL`, `LOG_FORMAT`, `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and `CORS_ALLOW_ORIGINS`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/api/fastapi/setup.py†L47-L88】
|
|
124
124
|
- **Auth** – configure JWT secrets, SMTP, cookies, and policy using the `AUTH_…` settings family (e.g., `AUTH_JWT__SECRET`, `AUTH_SMTP_HOST`, `AUTH_SESSION_COOKIE_SECURE`). 【F:src/svc_infra/api/fastapi/auth/settings.py†L23-L91】
|
|
125
125
|
- **Database** – set connection URLs or components via `SQL_URL`/`SQL_URL_FILE`, `DB_DIALECT`, `DB_HOST`, `DB_USER`, `DB_PASSWORD`, plus Mongo knobs like `MONGO_URL`, `MONGO_DB`, and `MONGO_URL_FILE`. 【F:src/svc_infra/api/fastapi/db/sql/add.py†L55-L114】【F:src/svc_infra/db/sql/utils.py†L85-L206】【F:src/svc_infra/db/nosql/mongo/settings.py†L9-L13】【F:src/svc_infra/db/nosql/utils.py†L56-L113】
|
|
126
|
-
- **Jobs** – choose the queue backend with `JOBS_DRIVER` and provide Redis via `REDIS_URL`; interval schedules can be declared with `JOBS_SCHEDULE_JSON`. 【F:src/svc_infra/jobs/easy.py†L11-L27】【F:docs/jobs.md†L11-L48】
|
|
126
|
+
- **Jobs** – choose the queue backend with `JOBS_DRIVER` and provide Redis via `REDIS_URL`; interval schedules can be declared with `JOBS_SCHEDULE_JSON`. 【F:src/svc_infra/jobs/easy.py†L11-L27】【F:src/svc_infra/docs/jobs.md†L11-L48】
|
|
127
127
|
- **Cache** – namespace keys and lifetimes through `CACHE_PREFIX`, `CACHE_VERSION`, and TTL overrides `CACHE_TTL_DEFAULT`, `CACHE_TTL_SHORT`, `CACHE_TTL_LONG`. 【F:src/svc_infra/cache/README.md†L20-L173】【F:src/svc_infra/cache/ttl.py†L26-L55】
|
|
128
128
|
- **Observability** – turn metrics on/off or adjust scrape paths with `ENABLE_OBS`, `METRICS_PATH`, `OBS_SKIP_PATHS`, and Prometheus/Grafana flags like `SVC_INFRA_DISABLE_PROMETHEUS`, `SVC_INFRA_RATE_WINDOW`, `SVC_INFRA_DASHBOARD_REFRESH`, `SVC_INFRA_DASHBOARD_RANGE`. 【F:src/svc_infra/api/fastapi/ease.py†L67-L111】【F:src/svc_infra/obs/metrics/asgi.py†L49-L206】【F:src/svc_infra/obs/cloud_dash.py†L85-L108】
|
|
129
|
-
- **Webhooks** – reuse the jobs envs (`JOBS_DRIVER`, `REDIS_URL`) for the delivery worker and queue configuration. 【F:docs/webhooks.md†L32-L53】
|
|
130
|
-
- **Security** – enforce password policy, MFA, and rotation with auth prefixes such as `AUTH_PASSWORD_MIN_LENGTH`, `AUTH_PASSWORD_REQUIRE_SYMBOL`, `AUTH_JWT__SECRET`, and `AUTH_JWT__OLD_SECRETS`. 【F:docs/security.md†L24-L70】
|
|
129
|
+
- **Webhooks** – reuse the jobs envs (`JOBS_DRIVER`, `REDIS_URL`) for the delivery worker and queue configuration. 【F:src/svc_infra/docs/webhooks.md†L32-L53】
|
|
130
|
+
- **Security** – enforce password policy, MFA, and rotation with auth prefixes such as `AUTH_PASSWORD_MIN_LENGTH`, `AUTH_PASSWORD_REQUIRE_SYMBOL`, `AUTH_JWT__SECRET`, and `AUTH_JWT__OLD_SECRETS`. 【F:src/svc_infra/docs/security.md†L24-L70】
|
|
131
131
|
|
|
@@ -142,7 +142,7 @@ svc_infra/cli/cmds/db/sql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
142
142
|
svc_infra/cli/cmds/db/sql/alembic_cmds.py,sha256=uCreHg69Zf6B5gbv9Dm39jCRk6q2KQy_05A-75IP0Fg,9650
|
|
143
143
|
svc_infra/cli/cmds/db/sql/sql_export_cmds.py,sha256=YpkguUJFeFApMphVkhOJllTi25ejlsQaJarMe6vJD54,2685
|
|
144
144
|
svc_infra/cli/cmds/db/sql/sql_scaffold_cmds.py,sha256=MKc_T_tY1Y_wQl7XTlq8GhYWMMI1q1_vcFZVPOEcNUg,4601
|
|
145
|
-
svc_infra/cli/cmds/docs/docs_cmds.py,sha256=
|
|
145
|
+
svc_infra/cli/cmds/docs/docs_cmds.py,sha256=Gyi0cr22-SY8kThAutRSzW9LmZ1ek9LTpwFpvlclKWM,6407
|
|
146
146
|
svc_infra/cli/cmds/dx/__init__.py,sha256=wQtl3-kOgoESlpVkjl3YFtqkOnQSIvVsOdutiaZFejM,197
|
|
147
147
|
svc_infra/cli/cmds/dx/dx_cmds.py,sha256=XTKUJzS3UIYn6h3CHzDEWKYJaWn0TzGiUCq3OeW27E0,3326
|
|
148
148
|
svc_infra/cli/cmds/help.py,sha256=wGfZFMYaR2ZPwW2JwKDU7M3m4AtdCd8GRQ412AmEBUM,758
|
|
@@ -216,6 +216,34 @@ svc_infra/db/sql/uniq_hooks.py,sha256=6gCnO0_Y-rhB0p-VuY0mZ9m1u3haiLWI3Ns_iUTqF_
|
|
|
216
216
|
svc_infra/db/sql/utils.py,sha256=nzuDcDhnVNehx5Y9BZLgxw8fvpfYbxTfXQsgnznVf4w,32862
|
|
217
217
|
svc_infra/db/sql/versioning.py,sha256=okZu2ad5RAFXNLXJgGpcQvZ5bc6gPjRWzwiBT0rEJJw,400
|
|
218
218
|
svc_infra/db/utils.py,sha256=aTD49VJSEu319kIWJ1uijUoP51co4lNJ3S0_tvuyGio,802
|
|
219
|
+
svc_infra/docs/acceptance-matrix.md,sha256=1J0722pdxNGVtjI5tAZA2wzzr1UiagjvPgzB8zo0Ks8,2383
|
|
220
|
+
svc_infra/docs/acceptance.md,sha256=1e9Ym4YOwnKHLfCTjx9garKlSKEnxzIYunx4cqoWhZ8,2327
|
|
221
|
+
svc_infra/docs/adr/0002-background-jobs-and-scheduling.md,sha256=iscWFmDmMFcaON3W1FePZT9aHvlBLWCoB4QE7iA5BBI,2418
|
|
222
|
+
svc_infra/docs/adr/0003-webhooks-framework.md,sha256=CFFd4RrmbTbKPr_RRuEe4zdpbpU8C6vD_DimCd702zE,1405
|
|
223
|
+
svc_infra/docs/adr/0004-tenancy-model.md,sha256=ZaJesiWqVggrRLbTXCIyyaVNiDDjl0NWPt7dSrj5SIQ,2732
|
|
224
|
+
svc_infra/docs/adr/0005-data-lifecycle.md,sha256=XLFu2I0d_6Oc7e-MOy9UE_UuCkVHCvhWy8rUlVBeAcE,4897
|
|
225
|
+
svc_infra/docs/adr/0006-ops-slos-and-metrics.md,sha256=Qd17l0RKGXczLs2AKJewCAxr2g0SP7BpcLLViGknJnE,2453
|
|
226
|
+
svc_infra/docs/adr/0007-docs-and-sdks.md,sha256=uQ-q-5omaOXPL5tW5q0_1FE9P_OmO9aDHXqWSGme3eg,4481
|
|
227
|
+
svc_infra/docs/adr/0008-billing-primitives.md,sha256=trqzGWsyk_QXNtVRHXcTayEV4Sx1Zjhis93bCnsqDvo,5544
|
|
228
|
+
svc_infra/docs/adr/0009-acceptance-harness.md,sha256=jDmoWn2uJTeK28YZo75YR1ym6NdgcmPOlMfupZlCCBs,2146
|
|
229
|
+
svc_infra/docs/api.md,sha256=AlPL9kBS6_dM0NrOteDQ9WqalSfKf_p9_zdy1CtGJdU,2384
|
|
230
|
+
svc_infra/docs/auth.md,sha256=PRl9G4UW78cT_7c4koVh5NDlheNAr02CpJT2YFbEXto,1333
|
|
231
|
+
svc_infra/docs/cache.md,sha256=XUsJ8p6QFBWTNuqata1HJjB6accdPANipdoNAkKirqs,673
|
|
232
|
+
svc_infra/docs/cli.md,sha256=w5og4SWrLyizlJAJiFgcWu2jDSc1Wj3NCYqzbbvg8VE,1702
|
|
233
|
+
svc_infra/docs/contributing.md,sha256=a0PhmzCLFw8S3odxFbI3p5_FOiPMZLrxk15Ujrk7ao4,1175
|
|
234
|
+
svc_infra/docs/data-lifecycle.md,sha256=_XFZCj9qiYgEiN9jO_lq7RcpVIeLVN7REaFziiNCnEI,2684
|
|
235
|
+
svc_infra/docs/database.md,sha256=p_t-4ApQqa7ImhiV6wv0oklDTEZPn-snO1K1FoNtZpI,1129
|
|
236
|
+
svc_infra/docs/docs-and-sdks.md,sha256=v5Uz-CVNswiZ-ITiqo6tiOX5xGJSnftfbA7b3hrqHqI,2330
|
|
237
|
+
svc_infra/docs/environment.md,sha256=w84-1hL3zog6fYYgDLiQRQiAlS2CadjmZmu87Frzxy8,9700
|
|
238
|
+
svc_infra/docs/idempotency.md,sha256=jvemdVY4g6xoHW38OAZIS5JxA3SdK8a0iAayx18kIbk,3890
|
|
239
|
+
svc_infra/docs/jobs.md,sha256=iyDPo6oo7fJdBZ9e6Qt9x_kX4sX7_TUUdY89CFiZ61I,1586
|
|
240
|
+
svc_infra/docs/observability.md,sha256=qzu44CSmGwjdLkBj0TQ1LBMmXd7BO2hmJSdByZlBXck,1021
|
|
241
|
+
svc_infra/docs/ops.md,sha256=to47s3Z66-wQ4WvwEnD3xMrcmvKf-lowBqWqS-2n2HQ,1306
|
|
242
|
+
svc_infra/docs/rate-limiting.md,sha256=W_96ch1dIjD9NP9Ma45UgsNTqDh6wlMbhJgAN3Uc4do,3983
|
|
243
|
+
svc_infra/docs/repo-review.md,sha256=REz2zT1LXURQUB9yZiBn9ICXHkpdpBSJCRTp-AKH190,8153
|
|
244
|
+
svc_infra/docs/security.md,sha256=tjr5IlBYu47Z1qs2ZHQE-Low1ZOQDtZWoKjmaNXalG4,6121
|
|
245
|
+
svc_infra/docs/tenancy.md,sha256=k7mOvIQWZF1b3-CETyE8UsIPdhGjNNa9Q4j5AXAqQrQ,2023
|
|
246
|
+
svc_infra/docs/webhooks.md,sha256=b0F2vnkxOWdYWwCBAo9i39xdi11nbgEtl05JE3e0lrE,3671
|
|
219
247
|
svc_infra/dx/add.py,sha256=FAnLGP0BPm_q_VCEcpUwfj-b0mEse988chh9DHeS7GU,1474
|
|
220
248
|
svc_infra/dx/changelog.py,sha256=9SD29ZzKzbGTA6kHQXiPLtb7uueL1wrRiiLE2qMzz8o,1941
|
|
221
249
|
svc_infra/dx/checks.py,sha256=R6YqRvpKPr9zQgif4QVx2_Zl4s9YjehSkAvwlxK46lI,2267
|
|
@@ -296,7 +324,7 @@ svc_infra/webhooks/fastapi.py,sha256=BCNvGNxukf6dC2a4i-6en-PrjBGV19YvCWOot5lXWsA
|
|
|
296
324
|
svc_infra/webhooks/router.py,sha256=6JvAVPMEth_xxHX-IsIOcyMgHX7g1H0OVxVXKLuMp9w,1596
|
|
297
325
|
svc_infra/webhooks/service.py,sha256=hWgiJRXKBwKunJOx91C7EcLUkotDtD3Xp0RT6vj2IC0,1797
|
|
298
326
|
svc_infra/webhooks/signing.py,sha256=NCwdZzmravUe7HVIK_uXK0qqf12FG-_MVsgPvOw6lsM,784
|
|
299
|
-
svc_infra-0.1.
|
|
300
|
-
svc_infra-0.1.
|
|
301
|
-
svc_infra-0.1.
|
|
302
|
-
svc_infra-0.1.
|
|
327
|
+
svc_infra-0.1.623.dist-info/METADATA,sha256=b0847FKVzDHLtuU1uxB7G6qubJkOqpztMsuZmEhK43I,8316
|
|
328
|
+
svc_infra-0.1.623.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
329
|
+
svc_infra-0.1.623.dist-info/entry_points.txt,sha256=6x_nZOsjvn6hRZsMgZLgTasaCSKCgAjsGhACe_CiP0U,48
|
|
330
|
+
svc_infra-0.1.623.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|