fastapi-m8 4.2.0__tar.gz → 4.2.2__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.
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.github/workflows/CI.yaml +9 -9
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.github/workflows/PiPy.yml +5 -5
- fastapi_m8-4.2.2/CLAUDE.md +8 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/PKG-INFO +29 -2
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/README.md +27 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/constraints-all.txt +1 -1
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/constraints.txt +1 -1
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_version.py +1 -1
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/pyproject.toml +2 -2
- fastapi_m8-4.2.0/CLAUDE.md +0 -7
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.codacy.yml +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.dockerignore +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.env.example +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.gitattributes +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.github/FUNDING.yml +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.github/dependabot.yml +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.gitignore +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.gitleaks.toml +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/.pydocstyle +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/AGENTS.md +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/CHANGELOG.md +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/LICENSE +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/REPOSITORY_CONTEXT.md +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/SECURITY.md +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/__init__.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_api_key.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_app.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_async_stub.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_compat.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_deps.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_engine.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_events.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_health.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_internal_auth.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_revocation.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/_route_audit.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/config.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/scripts/__init__.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/scripts/docker_start.sh +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/fastapi_m8/scripts/pre_start.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/__init__.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/conftest.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_api_key.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_api_key_deps.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_app.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_app_extra.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_async_stub.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_ci_policy.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_compat.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_config.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_config_file_secrets.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_deps.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_engine.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_event_signing_gate.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_events.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_fixture_matrix_contract.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_health.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_host_header_routing.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_internal_auth.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_meta.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_packaging.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_pre_start.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_public_typing.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_revocation.py +0 -0
- {fastapi_m8-4.2.0 → fastapi_m8-4.2.2}/tests/test_route_audit.py +0 -0
|
@@ -16,10 +16,10 @@ jobs:
|
|
|
16
16
|
lint:
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
20
|
|
|
21
21
|
- name: Set up Python
|
|
22
|
-
uses: actions/setup-python@
|
|
22
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
23
23
|
with:
|
|
24
24
|
python-version: "3.14"
|
|
25
25
|
cache: "pip"
|
|
@@ -36,10 +36,10 @@ jobs:
|
|
|
36
36
|
typecheck:
|
|
37
37
|
runs-on: ubuntu-latest
|
|
38
38
|
steps:
|
|
39
|
-
- uses: actions/checkout@
|
|
39
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
40
40
|
|
|
41
41
|
- name: Set up Python
|
|
42
|
-
uses: actions/setup-python@
|
|
42
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
43
43
|
with:
|
|
44
44
|
python-version: "3.14"
|
|
45
45
|
cache: "pip"
|
|
@@ -53,10 +53,10 @@ jobs:
|
|
|
53
53
|
security:
|
|
54
54
|
runs-on: ubuntu-latest
|
|
55
55
|
steps:
|
|
56
|
-
- uses: actions/checkout@
|
|
56
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
57
57
|
|
|
58
58
|
- name: Set up Python
|
|
59
|
-
uses: actions/setup-python@
|
|
59
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
60
60
|
with:
|
|
61
61
|
python-version: "3.14"
|
|
62
62
|
|
|
@@ -87,10 +87,10 @@ jobs:
|
|
|
87
87
|
python-version: ["3.12", "3.13", "3.14"]
|
|
88
88
|
|
|
89
89
|
steps:
|
|
90
|
-
- uses: actions/checkout@
|
|
90
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
91
91
|
|
|
92
92
|
- name: Set up Python ${{ matrix.python-version }}
|
|
93
|
-
uses: actions/setup-python@
|
|
93
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
94
94
|
with:
|
|
95
95
|
python-version: ${{ matrix.python-version }}
|
|
96
96
|
cache: "pip"
|
|
@@ -121,7 +121,7 @@ jobs:
|
|
|
121
121
|
runs-on: ubuntu-latest
|
|
122
122
|
|
|
123
123
|
steps:
|
|
124
|
-
- uses: actions/checkout@
|
|
124
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
125
125
|
with:
|
|
126
126
|
fetch-depth: 0
|
|
127
127
|
|
|
@@ -12,9 +12,9 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
16
16
|
|
|
17
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
18
18
|
with:
|
|
19
19
|
python-version: "3.x"
|
|
20
20
|
|
|
@@ -51,7 +51,7 @@ jobs:
|
|
|
51
51
|
path: dist/
|
|
52
52
|
|
|
53
53
|
- name: Publish release distributions to PyPI
|
|
54
|
-
uses: pypa/gh-action-pypi-publish@
|
|
54
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
55
55
|
|
|
56
56
|
sbom:
|
|
57
57
|
name: Generate & attach SBOM
|
|
@@ -63,9 +63,9 @@ jobs:
|
|
|
63
63
|
id-token: write
|
|
64
64
|
|
|
65
65
|
steps:
|
|
66
|
-
- uses: actions/checkout@
|
|
66
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
67
67
|
|
|
68
|
-
- uses: actions/setup-python@
|
|
68
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
69
69
|
with:
|
|
70
70
|
python-version: "3.x"
|
|
71
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastapi-m8
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.2
|
|
4
4
|
Summary: FastAPI application framework for m8 consumer microservices.
|
|
5
5
|
Author-email: Eli Serra <e.serra173@gmail.com>
|
|
6
6
|
License: Apache License
|
|
@@ -215,7 +215,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
215
215
|
Classifier: Topic :: Software Development :: Libraries
|
|
216
216
|
Requires-Python: >=3.12
|
|
217
217
|
Requires-Dist: anyio>=4.0
|
|
218
|
-
Requires-Dist: auth-sdk-m8[config,events,fastapi,observability,security]<4.0.0,>=3.1.
|
|
218
|
+
Requires-Dist: auth-sdk-m8[config,events,fastapi,observability,security]<4.0.0,>=3.1.2
|
|
219
219
|
Requires-Dist: fastapi>=0.136.3
|
|
220
220
|
Requires-Dist: httpx>=0.27.0
|
|
221
221
|
Requires-Dist: packaging>=24.0
|
|
@@ -659,6 +659,18 @@ untouched.
|
|
|
659
659
|
| `SERVICE_TOKEN_SCOPES` | No | `["introspection"]` | Scopes requested when minting a service token; fa-auth narrows to the subset the bootstrap credential was granted. |
|
|
660
660
|
| `SERVICE_TOKEN_REFRESH_LEEWAY_SECONDS` | No | `30` | Refresh a cached service token this many seconds before its `exp` so a call never races expiry. |
|
|
661
661
|
|
|
662
|
+
> **Ordinary expiry never surfaces as a `503`.** The refresh check runs lazily
|
|
663
|
+
> on every call, before the private request is sent: once past
|
|
664
|
+
> `exp - SERVICE_TOKEN_REFRESH_LEEWAY_SECONDS`, the client re-exchanges first.
|
|
665
|
+
> Continuous traffic therefore never presents an actually expired service
|
|
666
|
+
> token to the issuer. The one case where a `503` legitimately occurs is a
|
|
667
|
+
> withdrawn/rotated consumer secret, or a request whose latency races the
|
|
668
|
+
> leeway margin — the issuer answers `401`, the cached token is dropped, and
|
|
669
|
+
> that single request fails closed while the next one re-mints and succeeds
|
|
670
|
+
> (never retried automatically — introspection consumes the caller's quota).
|
|
671
|
+
> Accepted operational behavior; documented rather than pre-empted by a
|
|
672
|
+
> second re-mint mechanism, since the proactive one above already covers it.
|
|
673
|
+
|
|
662
674
|
### Remote API-Key Principal
|
|
663
675
|
|
|
664
676
|
Resolves a user API key presented by an external client to its owner's current
|
|
@@ -1168,6 +1180,21 @@ The value must match across the stack.
|
|
|
1168
1180
|
**Stateless** — maximum scalability, simplest setup. Logout does not invalidate
|
|
1169
1181
|
in-flight access tokens; they expire naturally.
|
|
1170
1182
|
|
|
1183
|
+
**Hybrid** — refresh-session state is revoked immediately (so a revoked user
|
|
1184
|
+
cannot mint a new access token), but an already-issued access token is not
|
|
1185
|
+
checked against the issuer and stays valid for the rest of its own lifetime.
|
|
1186
|
+
This is not a weaker or open-ended window: `TokenValidator.validate_access_token`
|
|
1187
|
+
enforces the JWT `exp` claim unconditionally, on every request, regardless of
|
|
1188
|
+
`TOKEN_MODE` (`auth_sdk_m8/security/token_validator.py`), and no `hybrid`/
|
|
1189
|
+
`stateless` code path in `build_auth_deps` skips or extends that check — only
|
|
1190
|
+
the *additional* revocation-client call is gated on `settings.is_stateful`. The
|
|
1191
|
+
stale-access-token window is therefore bounded by exactly
|
|
1192
|
+
`ACCESS_TOKEN_EXPIRE_MINUTES` and nothing longer; it must never be read as
|
|
1193
|
+
"immediate revocation" for the access token itself. Consumers that need
|
|
1194
|
+
immediate enforcement of a role/privilege downgrade — not just eventual
|
|
1195
|
+
expiry — must run `stateful` with `ACCESS_REVOCATION_FAILURE_MODE=fail_closed`
|
|
1196
|
+
instead of relying on hybrid/stateless.
|
|
1197
|
+
|
|
1171
1198
|
**Stateful** — highest security. On each request a consumer performs an HTTP call to
|
|
1172
1199
|
`fa-auth-m8` to verify the JWT's JTI has not been revoked. Requires `INTROSPECTION_URL`
|
|
1173
1200
|
and `PRIVATE_API_SECRET` in consumer settings.
|
|
@@ -402,6 +402,18 @@ untouched.
|
|
|
402
402
|
| `SERVICE_TOKEN_SCOPES` | No | `["introspection"]` | Scopes requested when minting a service token; fa-auth narrows to the subset the bootstrap credential was granted. |
|
|
403
403
|
| `SERVICE_TOKEN_REFRESH_LEEWAY_SECONDS` | No | `30` | Refresh a cached service token this many seconds before its `exp` so a call never races expiry. |
|
|
404
404
|
|
|
405
|
+
> **Ordinary expiry never surfaces as a `503`.** The refresh check runs lazily
|
|
406
|
+
> on every call, before the private request is sent: once past
|
|
407
|
+
> `exp - SERVICE_TOKEN_REFRESH_LEEWAY_SECONDS`, the client re-exchanges first.
|
|
408
|
+
> Continuous traffic therefore never presents an actually expired service
|
|
409
|
+
> token to the issuer. The one case where a `503` legitimately occurs is a
|
|
410
|
+
> withdrawn/rotated consumer secret, or a request whose latency races the
|
|
411
|
+
> leeway margin — the issuer answers `401`, the cached token is dropped, and
|
|
412
|
+
> that single request fails closed while the next one re-mints and succeeds
|
|
413
|
+
> (never retried automatically — introspection consumes the caller's quota).
|
|
414
|
+
> Accepted operational behavior; documented rather than pre-empted by a
|
|
415
|
+
> second re-mint mechanism, since the proactive one above already covers it.
|
|
416
|
+
|
|
405
417
|
### Remote API-Key Principal
|
|
406
418
|
|
|
407
419
|
Resolves a user API key presented by an external client to its owner's current
|
|
@@ -911,6 +923,21 @@ The value must match across the stack.
|
|
|
911
923
|
**Stateless** — maximum scalability, simplest setup. Logout does not invalidate
|
|
912
924
|
in-flight access tokens; they expire naturally.
|
|
913
925
|
|
|
926
|
+
**Hybrid** — refresh-session state is revoked immediately (so a revoked user
|
|
927
|
+
cannot mint a new access token), but an already-issued access token is not
|
|
928
|
+
checked against the issuer and stays valid for the rest of its own lifetime.
|
|
929
|
+
This is not a weaker or open-ended window: `TokenValidator.validate_access_token`
|
|
930
|
+
enforces the JWT `exp` claim unconditionally, on every request, regardless of
|
|
931
|
+
`TOKEN_MODE` (`auth_sdk_m8/security/token_validator.py`), and no `hybrid`/
|
|
932
|
+
`stateless` code path in `build_auth_deps` skips or extends that check — only
|
|
933
|
+
the *additional* revocation-client call is gated on `settings.is_stateful`. The
|
|
934
|
+
stale-access-token window is therefore bounded by exactly
|
|
935
|
+
`ACCESS_TOKEN_EXPIRE_MINUTES` and nothing longer; it must never be read as
|
|
936
|
+
"immediate revocation" for the access token itself. Consumers that need
|
|
937
|
+
immediate enforcement of a role/privilege downgrade — not just eventual
|
|
938
|
+
expiry — must run `stateful` with `ACCESS_REVOCATION_FAILURE_MODE=fail_closed`
|
|
939
|
+
instead of relying on hybrid/stateless.
|
|
940
|
+
|
|
914
941
|
**Stateful** — highest security. On each request a consumer performs an HTTP call to
|
|
915
942
|
`fa-auth-m8` to verify the JWT's JTI has not been revoked. Requires `INTROSPECTION_URL`
|
|
916
943
|
and `PRIVATE_API_SECRET` in consumer settings.
|
|
@@ -16,7 +16,7 @@ anyio==4.14.1
|
|
|
16
16
|
# fastapi-m8 (pyproject.toml)
|
|
17
17
|
# httpx
|
|
18
18
|
# starlette
|
|
19
|
-
auth-sdk-m8[config,events,fastapi,observability,security]==3.1.
|
|
19
|
+
auth-sdk-m8[config,events,fastapi,observability,security]==3.1.2
|
|
20
20
|
# via
|
|
21
21
|
# fastapi-m8
|
|
22
22
|
# fastapi-m8 (pyproject.toml)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fastapi-m8"
|
|
7
|
-
version = "4.2.
|
|
7
|
+
version = "4.2.2"
|
|
8
8
|
description = "FastAPI application framework for m8 consumer microservices."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -26,7 +26,7 @@ dependencies = [
|
|
|
26
26
|
"httpx>=0.27.0",
|
|
27
27
|
"packaging>=24.0",
|
|
28
28
|
"anyio>=4.0",
|
|
29
|
-
"auth-sdk-m8[config,security,fastapi,observability,events]>=3.1.
|
|
29
|
+
"auth-sdk-m8[config,security,fastapi,observability,events]>=3.1.2,<4.0.0",
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
[project.optional-dependencies]
|
fastapi_m8-4.2.0/CLAUDE.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|