mdb-engine 0.1.6__py3-none-any.whl → 0.4.12__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.
- mdb_engine/__init__.py +116 -11
- mdb_engine/auth/ARCHITECTURE.md +112 -0
- mdb_engine/auth/README.md +654 -11
- mdb_engine/auth/__init__.py +136 -29
- mdb_engine/auth/audit.py +592 -0
- mdb_engine/auth/base.py +252 -0
- mdb_engine/auth/casbin_factory.py +265 -70
- mdb_engine/auth/config_defaults.py +5 -5
- mdb_engine/auth/config_helpers.py +19 -18
- mdb_engine/auth/cookie_utils.py +12 -16
- mdb_engine/auth/csrf.py +483 -0
- mdb_engine/auth/decorators.py +10 -16
- mdb_engine/auth/dependencies.py +69 -71
- mdb_engine/auth/helpers.py +3 -3
- mdb_engine/auth/integration.py +61 -88
- mdb_engine/auth/jwt.py +11 -15
- mdb_engine/auth/middleware.py +79 -35
- mdb_engine/auth/oso_factory.py +21 -41
- mdb_engine/auth/provider.py +270 -171
- mdb_engine/auth/rate_limiter.py +505 -0
- mdb_engine/auth/restrictions.py +21 -36
- mdb_engine/auth/session_manager.py +24 -41
- mdb_engine/auth/shared_middleware.py +977 -0
- mdb_engine/auth/shared_users.py +775 -0
- mdb_engine/auth/token_lifecycle.py +10 -12
- mdb_engine/auth/token_store.py +17 -32
- mdb_engine/auth/users.py +99 -159
- mdb_engine/auth/utils.py +236 -42
- mdb_engine/cli/commands/generate.py +546 -10
- mdb_engine/cli/commands/validate.py +3 -7
- mdb_engine/cli/utils.py +7 -7
- mdb_engine/config.py +13 -28
- mdb_engine/constants.py +65 -0
- mdb_engine/core/README.md +117 -6
- mdb_engine/core/__init__.py +39 -7
- mdb_engine/core/app_registration.py +31 -50
- mdb_engine/core/app_secrets.py +289 -0
- mdb_engine/core/connection.py +20 -12
- mdb_engine/core/encryption.py +222 -0
- mdb_engine/core/engine.py +2862 -115
- mdb_engine/core/index_management.py +12 -16
- mdb_engine/core/manifest.py +628 -204
- mdb_engine/core/ray_integration.py +436 -0
- mdb_engine/core/seeding.py +13 -21
- mdb_engine/core/service_initialization.py +20 -30
- mdb_engine/core/types.py +40 -43
- mdb_engine/database/README.md +140 -17
- mdb_engine/database/__init__.py +17 -6
- mdb_engine/database/abstraction.py +37 -50
- mdb_engine/database/connection.py +51 -30
- mdb_engine/database/query_validator.py +367 -0
- mdb_engine/database/resource_limiter.py +204 -0
- mdb_engine/database/scoped_wrapper.py +747 -237
- mdb_engine/dependencies.py +427 -0
- mdb_engine/di/__init__.py +34 -0
- mdb_engine/di/container.py +247 -0
- mdb_engine/di/providers.py +206 -0
- mdb_engine/di/scopes.py +139 -0
- mdb_engine/embeddings/README.md +54 -24
- mdb_engine/embeddings/__init__.py +31 -24
- mdb_engine/embeddings/dependencies.py +38 -155
- mdb_engine/embeddings/service.py +78 -75
- mdb_engine/exceptions.py +104 -12
- mdb_engine/indexes/README.md +30 -13
- mdb_engine/indexes/__init__.py +1 -0
- mdb_engine/indexes/helpers.py +11 -11
- mdb_engine/indexes/manager.py +59 -123
- mdb_engine/memory/README.md +95 -4
- mdb_engine/memory/__init__.py +1 -2
- mdb_engine/memory/service.py +363 -1168
- mdb_engine/observability/README.md +4 -2
- mdb_engine/observability/__init__.py +26 -9
- mdb_engine/observability/health.py +17 -17
- mdb_engine/observability/logging.py +10 -10
- mdb_engine/observability/metrics.py +40 -19
- mdb_engine/repositories/__init__.py +34 -0
- mdb_engine/repositories/base.py +325 -0
- mdb_engine/repositories/mongo.py +233 -0
- mdb_engine/repositories/unit_of_work.py +166 -0
- mdb_engine/routing/README.md +1 -1
- mdb_engine/routing/__init__.py +1 -3
- mdb_engine/routing/websockets.py +41 -75
- mdb_engine/utils/__init__.py +3 -1
- mdb_engine/utils/mongo.py +117 -0
- mdb_engine-0.4.12.dist-info/METADATA +492 -0
- mdb_engine-0.4.12.dist-info/RECORD +97 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/WHEEL +1 -1
- mdb_engine-0.1.6.dist-info/METADATA +0 -213
- mdb_engine-0.1.6.dist-info/RECORD +0 -75
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/entry_points.txt +0 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/licenses/LICENSE +0 -0
- {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
from datetime import datetime
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import Any
|
|
12
12
|
|
|
13
13
|
from ..config import ACCESS_TOKEN_TTL as CONFIG_ACCESS_TTL
|
|
14
14
|
from .jwt import extract_token_metadata
|
|
@@ -16,7 +16,7 @@ from .jwt import extract_token_metadata
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def get_token_expiry_time(token: str, secret_key: str) ->
|
|
19
|
+
def get_token_expiry_time(token: str, secret_key: str) -> datetime | None:
|
|
20
20
|
"""
|
|
21
21
|
Get the expiration time of a token.
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ def get_token_expiry_time(token: str, secret_key: str) -> Optional[datetime]:
|
|
|
31
31
|
metadata = extract_token_metadata(token, secret_key)
|
|
32
32
|
if metadata and metadata.get("exp"):
|
|
33
33
|
exp_timestamp = metadata["exp"]
|
|
34
|
-
if isinstance(exp_timestamp,
|
|
34
|
+
if isinstance(exp_timestamp, int | float):
|
|
35
35
|
return datetime.utcfromtimestamp(exp_timestamp)
|
|
36
36
|
return None
|
|
37
37
|
except (ValueError, TypeError, AttributeError, KeyError) as e:
|
|
@@ -40,7 +40,7 @@ def get_token_expiry_time(token: str, secret_key: str) -> Optional[datetime]:
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
def is_token_expiring_soon(
|
|
43
|
-
token: str, secret_key: str, threshold_seconds:
|
|
43
|
+
token: str, secret_key: str, threshold_seconds: int | None = None
|
|
44
44
|
) -> bool:
|
|
45
45
|
"""
|
|
46
46
|
Check if a token is expiring soon.
|
|
@@ -68,9 +68,7 @@ def is_token_expiring_soon(
|
|
|
68
68
|
return False
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def should_refresh_token(
|
|
72
|
-
token: str, secret_key: str, refresh_threshold: Optional[int] = None
|
|
73
|
-
) -> bool:
|
|
71
|
+
def should_refresh_token(token: str, secret_key: str, refresh_threshold: int | None = None) -> bool:
|
|
74
72
|
"""
|
|
75
73
|
Determine if a token should be refreshed.
|
|
76
74
|
|
|
@@ -97,7 +95,7 @@ def should_refresh_token(
|
|
|
97
95
|
return False
|
|
98
96
|
|
|
99
97
|
|
|
100
|
-
def get_token_age(token: str, secret_key: str) ->
|
|
98
|
+
def get_token_age(token: str, secret_key: str) -> float | None:
|
|
101
99
|
"""
|
|
102
100
|
Get the age of a token in seconds.
|
|
103
101
|
|
|
@@ -112,7 +110,7 @@ def get_token_age(token: str, secret_key: str) -> Optional[float]:
|
|
|
112
110
|
metadata = extract_token_metadata(token, secret_key)
|
|
113
111
|
if metadata and metadata.get("iat"):
|
|
114
112
|
iat_timestamp = metadata["iat"]
|
|
115
|
-
if isinstance(iat_timestamp,
|
|
113
|
+
if isinstance(iat_timestamp, int | float):
|
|
116
114
|
issued_at = datetime.utcfromtimestamp(iat_timestamp)
|
|
117
115
|
age = (datetime.utcnow() - issued_at).total_seconds()
|
|
118
116
|
return age
|
|
@@ -122,7 +120,7 @@ def get_token_age(token: str, secret_key: str) -> Optional[float]:
|
|
|
122
120
|
return None
|
|
123
121
|
|
|
124
122
|
|
|
125
|
-
def get_time_until_expiry(token: str, secret_key: str) ->
|
|
123
|
+
def get_time_until_expiry(token: str, secret_key: str) -> float | None:
|
|
126
124
|
"""
|
|
127
125
|
Get time until token expiry in seconds.
|
|
128
126
|
|
|
@@ -146,7 +144,7 @@ def get_time_until_expiry(token: str, secret_key: str) -> Optional[float]:
|
|
|
146
144
|
|
|
147
145
|
|
|
148
146
|
def validate_token_version(
|
|
149
|
-
token: str, secret_key: str, required_version:
|
|
147
|
+
token: str, secret_key: str, required_version: str | None = None
|
|
150
148
|
) -> bool:
|
|
151
149
|
"""
|
|
152
150
|
Validate token version compatibility.
|
|
@@ -177,7 +175,7 @@ def validate_token_version(
|
|
|
177
175
|
return False
|
|
178
176
|
|
|
179
177
|
|
|
180
|
-
def get_token_info(token: str, secret_key: str) ->
|
|
178
|
+
def get_token_info(token: str, secret_key: str) -> dict[str, Any] | None:
|
|
181
179
|
"""
|
|
182
180
|
Get comprehensive token information.
|
|
183
181
|
|
mdb_engine/auth/token_store.py
CHANGED
|
@@ -8,11 +8,13 @@ This module is part of MDB_ENGINE - MongoDB Engine.
|
|
|
8
8
|
|
|
9
9
|
import logging
|
|
10
10
|
from datetime import datetime, timedelta
|
|
11
|
-
from typing import Optional
|
|
12
11
|
|
|
13
12
|
try:
|
|
14
|
-
from pymongo.errors import (
|
|
15
|
-
|
|
13
|
+
from pymongo.errors import (
|
|
14
|
+
ConnectionFailure,
|
|
15
|
+
OperationFailure,
|
|
16
|
+
ServerSelectionTimeoutError,
|
|
17
|
+
)
|
|
16
18
|
except ImportError:
|
|
17
19
|
ConnectionFailure = Exception
|
|
18
20
|
OperationFailure = Exception
|
|
@@ -54,9 +56,7 @@ class TokenBlacklist:
|
|
|
54
56
|
|
|
55
57
|
try:
|
|
56
58
|
# Create unique index on jti
|
|
57
|
-
await self.collection.create_index(
|
|
58
|
-
"jti", unique=True, name="jti_unique_idx"
|
|
59
|
-
)
|
|
59
|
+
await self.collection.create_index("jti", unique=True, name="jti_unique_idx")
|
|
60
60
|
|
|
61
61
|
# Create TTL index on expires_at (auto-delete expired entries)
|
|
62
62
|
await self.collection.create_index(
|
|
@@ -78,9 +78,9 @@ class TokenBlacklist:
|
|
|
78
78
|
async def revoke_token(
|
|
79
79
|
self,
|
|
80
80
|
jti: str,
|
|
81
|
-
user_id:
|
|
82
|
-
expires_at:
|
|
83
|
-
reason:
|
|
81
|
+
user_id: str | None = None,
|
|
82
|
+
expires_at: datetime | None = None,
|
|
83
|
+
reason: str | None = None,
|
|
84
84
|
) -> bool:
|
|
85
85
|
"""
|
|
86
86
|
Revoke a token by adding it to the blacklist.
|
|
@@ -110,9 +110,7 @@ class TokenBlacklist:
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
# Use upsert to handle duplicate jti gracefully
|
|
113
|
-
await self.collection.update_one(
|
|
114
|
-
{"jti": jti}, {"$set": blacklist_entry}, upsert=True
|
|
115
|
-
)
|
|
113
|
+
await self.collection.update_one({"jti": jti}, {"$set": blacklist_entry}, upsert=True)
|
|
116
114
|
|
|
117
115
|
logger.debug(f"Token {jti} added to blacklist (reason: {reason})")
|
|
118
116
|
return True
|
|
@@ -158,15 +156,11 @@ class TokenBlacklist:
|
|
|
158
156
|
ValueError,
|
|
159
157
|
TypeError,
|
|
160
158
|
) as e:
|
|
161
|
-
logger.error(
|
|
162
|
-
f"Error checking token revocation status for {jti}: {e}", exc_info=True
|
|
163
|
-
)
|
|
159
|
+
logger.error(f"Error checking token revocation status for {jti}: {e}", exc_info=True)
|
|
164
160
|
# On error, assume not revoked (fail open for availability)
|
|
165
161
|
return False
|
|
166
162
|
|
|
167
|
-
async def revoke_all_user_tokens(
|
|
168
|
-
self, user_id: str, reason: Optional[str] = None
|
|
169
|
-
) -> int:
|
|
163
|
+
async def revoke_all_user_tokens(self, user_id: str, reason: str | None = None) -> int:
|
|
170
164
|
"""
|
|
171
165
|
Revoke all tokens for a specific user.
|
|
172
166
|
|
|
@@ -189,8 +183,7 @@ class TokenBlacklist:
|
|
|
189
183
|
"user_id": user_id,
|
|
190
184
|
"revoked_at": datetime.utcnow(),
|
|
191
185
|
"reason": reason or "logout_all",
|
|
192
|
-
"expires_at": datetime.utcnow()
|
|
193
|
-
+ timedelta(days=30), # Keep for 30 days
|
|
186
|
+
"expires_at": datetime.utcnow() + timedelta(days=30), # Keep for 30 days
|
|
194
187
|
}
|
|
195
188
|
|
|
196
189
|
# Use upsert to update or create marker
|
|
@@ -213,9 +206,7 @@ class TokenBlacklist:
|
|
|
213
206
|
ValueError,
|
|
214
207
|
TypeError,
|
|
215
208
|
) as e:
|
|
216
|
-
logger.error(
|
|
217
|
-
f"Error revoking all tokens for user {user_id}: {e}", exc_info=True
|
|
218
|
-
)
|
|
209
|
+
logger.error(f"Error revoking all tokens for user {user_id}: {e}", exc_info=True)
|
|
219
210
|
return 0
|
|
220
211
|
|
|
221
212
|
async def is_user_revoked(self, user_id: str) -> bool:
|
|
@@ -231,9 +222,7 @@ class TokenBlacklist:
|
|
|
231
222
|
try:
|
|
232
223
|
await self.ensure_indexes()
|
|
233
224
|
|
|
234
|
-
marker = await self.collection.find_one(
|
|
235
|
-
{"user_id": user_id, "type": "user_revocation"}
|
|
236
|
-
)
|
|
225
|
+
marker = await self.collection.find_one({"user_id": user_id, "type": "user_revocation"})
|
|
237
226
|
|
|
238
227
|
if marker:
|
|
239
228
|
# Check if marker hasn't expired
|
|
@@ -269,9 +258,7 @@ class TokenBlacklist:
|
|
|
269
258
|
Number of entries deleted
|
|
270
259
|
"""
|
|
271
260
|
try:
|
|
272
|
-
result = await self.collection.delete_many(
|
|
273
|
-
{"expires_at": {"$lt": datetime.utcnow()}}
|
|
274
|
-
)
|
|
261
|
+
result = await self.collection.delete_many({"expires_at": {"$lt": datetime.utcnow()}})
|
|
275
262
|
deleted_count = result.deleted_count
|
|
276
263
|
if deleted_count > 0:
|
|
277
264
|
logger.info(f"Cleared {deleted_count} expired blacklist entries")
|
|
@@ -283,7 +270,5 @@ class TokenBlacklist:
|
|
|
283
270
|
ValueError,
|
|
284
271
|
TypeError,
|
|
285
272
|
) as e:
|
|
286
|
-
logger.error(
|
|
287
|
-
f"Error clearing expired blacklist entries: {e}", exc_info=True
|
|
288
|
-
)
|
|
273
|
+
logger.error(f"Error clearing expired blacklist entries: {e}", exc_info=True)
|
|
289
274
|
return 0
|