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.
Files changed (92) hide show
  1. mdb_engine/__init__.py +116 -11
  2. mdb_engine/auth/ARCHITECTURE.md +112 -0
  3. mdb_engine/auth/README.md +654 -11
  4. mdb_engine/auth/__init__.py +136 -29
  5. mdb_engine/auth/audit.py +592 -0
  6. mdb_engine/auth/base.py +252 -0
  7. mdb_engine/auth/casbin_factory.py +265 -70
  8. mdb_engine/auth/config_defaults.py +5 -5
  9. mdb_engine/auth/config_helpers.py +19 -18
  10. mdb_engine/auth/cookie_utils.py +12 -16
  11. mdb_engine/auth/csrf.py +483 -0
  12. mdb_engine/auth/decorators.py +10 -16
  13. mdb_engine/auth/dependencies.py +69 -71
  14. mdb_engine/auth/helpers.py +3 -3
  15. mdb_engine/auth/integration.py +61 -88
  16. mdb_engine/auth/jwt.py +11 -15
  17. mdb_engine/auth/middleware.py +79 -35
  18. mdb_engine/auth/oso_factory.py +21 -41
  19. mdb_engine/auth/provider.py +270 -171
  20. mdb_engine/auth/rate_limiter.py +505 -0
  21. mdb_engine/auth/restrictions.py +21 -36
  22. mdb_engine/auth/session_manager.py +24 -41
  23. mdb_engine/auth/shared_middleware.py +977 -0
  24. mdb_engine/auth/shared_users.py +775 -0
  25. mdb_engine/auth/token_lifecycle.py +10 -12
  26. mdb_engine/auth/token_store.py +17 -32
  27. mdb_engine/auth/users.py +99 -159
  28. mdb_engine/auth/utils.py +236 -42
  29. mdb_engine/cli/commands/generate.py +546 -10
  30. mdb_engine/cli/commands/validate.py +3 -7
  31. mdb_engine/cli/utils.py +7 -7
  32. mdb_engine/config.py +13 -28
  33. mdb_engine/constants.py +65 -0
  34. mdb_engine/core/README.md +117 -6
  35. mdb_engine/core/__init__.py +39 -7
  36. mdb_engine/core/app_registration.py +31 -50
  37. mdb_engine/core/app_secrets.py +289 -0
  38. mdb_engine/core/connection.py +20 -12
  39. mdb_engine/core/encryption.py +222 -0
  40. mdb_engine/core/engine.py +2862 -115
  41. mdb_engine/core/index_management.py +12 -16
  42. mdb_engine/core/manifest.py +628 -204
  43. mdb_engine/core/ray_integration.py +436 -0
  44. mdb_engine/core/seeding.py +13 -21
  45. mdb_engine/core/service_initialization.py +20 -30
  46. mdb_engine/core/types.py +40 -43
  47. mdb_engine/database/README.md +140 -17
  48. mdb_engine/database/__init__.py +17 -6
  49. mdb_engine/database/abstraction.py +37 -50
  50. mdb_engine/database/connection.py +51 -30
  51. mdb_engine/database/query_validator.py +367 -0
  52. mdb_engine/database/resource_limiter.py +204 -0
  53. mdb_engine/database/scoped_wrapper.py +747 -237
  54. mdb_engine/dependencies.py +427 -0
  55. mdb_engine/di/__init__.py +34 -0
  56. mdb_engine/di/container.py +247 -0
  57. mdb_engine/di/providers.py +206 -0
  58. mdb_engine/di/scopes.py +139 -0
  59. mdb_engine/embeddings/README.md +54 -24
  60. mdb_engine/embeddings/__init__.py +31 -24
  61. mdb_engine/embeddings/dependencies.py +38 -155
  62. mdb_engine/embeddings/service.py +78 -75
  63. mdb_engine/exceptions.py +104 -12
  64. mdb_engine/indexes/README.md +30 -13
  65. mdb_engine/indexes/__init__.py +1 -0
  66. mdb_engine/indexes/helpers.py +11 -11
  67. mdb_engine/indexes/manager.py +59 -123
  68. mdb_engine/memory/README.md +95 -4
  69. mdb_engine/memory/__init__.py +1 -2
  70. mdb_engine/memory/service.py +363 -1168
  71. mdb_engine/observability/README.md +4 -2
  72. mdb_engine/observability/__init__.py +26 -9
  73. mdb_engine/observability/health.py +17 -17
  74. mdb_engine/observability/logging.py +10 -10
  75. mdb_engine/observability/metrics.py +40 -19
  76. mdb_engine/repositories/__init__.py +34 -0
  77. mdb_engine/repositories/base.py +325 -0
  78. mdb_engine/repositories/mongo.py +233 -0
  79. mdb_engine/repositories/unit_of_work.py +166 -0
  80. mdb_engine/routing/README.md +1 -1
  81. mdb_engine/routing/__init__.py +1 -3
  82. mdb_engine/routing/websockets.py +41 -75
  83. mdb_engine/utils/__init__.py +3 -1
  84. mdb_engine/utils/mongo.py +117 -0
  85. mdb_engine-0.4.12.dist-info/METADATA +492 -0
  86. mdb_engine-0.4.12.dist-info/RECORD +97 -0
  87. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/WHEEL +1 -1
  88. mdb_engine-0.1.6.dist-info/METADATA +0 -213
  89. mdb_engine-0.1.6.dist-info/RECORD +0 -75
  90. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/entry_points.txt +0 -0
  91. {mdb_engine-0.1.6.dist-info → mdb_engine-0.4.12.dist-info}/licenses/LICENSE +0 -0
  92. {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, Dict, Optional
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) -> Optional[datetime]:
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, (int, float)):
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: Optional[int] = None
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) -> Optional[float]:
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, (int, float)):
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) -> Optional[float]:
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: Optional[str] = None
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) -> Optional[Dict[str, Any]]:
178
+ def get_token_info(token: str, secret_key: str) -> dict[str, Any] | None:
181
179
  """
182
180
  Get comprehensive token information.
183
181
 
@@ -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 (ConnectionFailure, OperationFailure,
15
- ServerSelectionTimeoutError)
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: Optional[str] = None,
82
- expires_at: Optional[datetime] = None,
83
- reason: Optional[str] = None,
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