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
@@ -0,0 +1,204 @@
1
+ """
2
+ Resource limiting for MongoDB Engine.
3
+
4
+ This module provides resource limit enforcement to prevent resource exhaustion
5
+ and ensure fair resource usage across applications.
6
+
7
+ Features:
8
+ - Query timeout enforcement
9
+ - Result size limits
10
+ - Document size validation
11
+ - Connection limit tracking
12
+ """
13
+
14
+ import logging
15
+ from typing import Any
16
+
17
+ from bson import encode as bson_encode
18
+ from bson.errors import InvalidDocument
19
+
20
+ from ..constants import (
21
+ DEFAULT_MAX_TIME_MS,
22
+ MAX_CURSOR_BATCH_SIZE,
23
+ MAX_DOCUMENT_SIZE,
24
+ MAX_QUERY_RESULT_SIZE,
25
+ MAX_QUERY_TIME_MS,
26
+ )
27
+ from ..exceptions import ResourceLimitExceeded
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class ResourceLimiter:
33
+ """
34
+ Enforces resource limits on MongoDB operations.
35
+
36
+ This class provides resource limit enforcement to prevent:
37
+ - Query timeouts
38
+ - Excessive result sizes
39
+ - Oversized documents
40
+ - Resource exhaustion
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ default_timeout_ms: int = DEFAULT_MAX_TIME_MS,
46
+ max_timeout_ms: int = MAX_QUERY_TIME_MS,
47
+ max_result_size: int = MAX_QUERY_RESULT_SIZE,
48
+ max_batch_size: int = MAX_CURSOR_BATCH_SIZE,
49
+ max_document_size: int = MAX_DOCUMENT_SIZE,
50
+ ):
51
+ """
52
+ Initialize the resource limiter.
53
+
54
+ Args:
55
+ default_timeout_ms: Default query timeout in milliseconds
56
+ max_timeout_ms: Maximum allowed query timeout in milliseconds
57
+ max_result_size: Maximum number of documents in a result set
58
+ max_batch_size: Maximum batch size for cursor operations
59
+ max_document_size: Maximum document size in bytes
60
+ """
61
+ self.default_timeout_ms = default_timeout_ms
62
+ self.max_timeout_ms = max_timeout_ms
63
+ self.max_result_size = max_result_size
64
+ self.max_batch_size = max_batch_size
65
+ self.max_document_size = max_document_size
66
+
67
+ def enforce_query_timeout(
68
+ self, kwargs: dict[str, Any], default_timeout: int | None = None
69
+ ) -> dict[str, Any]:
70
+ """
71
+ Enforce query timeout by adding maxTimeMS if not present.
72
+
73
+ Args:
74
+ kwargs: Query keyword arguments
75
+ default_timeout: Default timeout to use (defaults to self.default_timeout_ms)
76
+
77
+ Returns:
78
+ Updated kwargs with maxTimeMS added if needed
79
+ """
80
+ kwargs = dict(kwargs) # Create a copy to avoid mutating original
81
+
82
+ default = default_timeout if default_timeout is not None else self.default_timeout_ms
83
+
84
+ # Check if maxTimeMS is already set
85
+ if "maxTimeMS" in kwargs:
86
+ user_timeout = kwargs["maxTimeMS"]
87
+ # Validate user-provided timeout doesn't exceed maximum
88
+ if user_timeout > self.max_timeout_ms:
89
+ logger.warning(
90
+ f"Query timeout {user_timeout}ms exceeds maximum {self.max_timeout_ms}ms. "
91
+ f"Capping to {self.max_timeout_ms}ms"
92
+ )
93
+ kwargs["maxTimeMS"] = self.max_timeout_ms
94
+ else:
95
+ # Add default timeout
96
+ kwargs["maxTimeMS"] = default
97
+
98
+ return kwargs
99
+
100
+ def enforce_result_limit(self, limit: int | None, max_limit: int | None = None) -> int:
101
+ """
102
+ Enforce maximum result limit.
103
+
104
+ Args:
105
+ limit: Requested limit (None means no limit)
106
+ max_limit: Maximum allowed limit (defaults to self.max_result_size)
107
+
108
+ Returns:
109
+ Enforced limit value (capped to maximum if needed)
110
+ """
111
+ max_allowed = max_limit if max_limit is not None else self.max_result_size
112
+
113
+ if limit is None:
114
+ # No limit requested, return max allowed
115
+ return max_allowed
116
+
117
+ if limit > max_allowed:
118
+ logger.warning(
119
+ f"Result limit {limit} exceeds maximum {max_allowed}. " f"Capping to {max_allowed}"
120
+ )
121
+ return max_allowed
122
+
123
+ return limit
124
+
125
+ def enforce_batch_size(self, batch_size: int | None, max_batch: int | None = None) -> int:
126
+ """
127
+ Enforce maximum batch size for cursor operations.
128
+
129
+ Args:
130
+ batch_size: Requested batch size (None means use default)
131
+ max_batch: Maximum allowed batch size (defaults to self.max_batch_size)
132
+
133
+ Returns:
134
+ Enforced batch size
135
+ """
136
+ max_allowed = max_batch if max_batch is not None else self.max_batch_size
137
+
138
+ if batch_size is None:
139
+ return max_allowed
140
+
141
+ if batch_size > max_allowed:
142
+ logger.warning(
143
+ f"Batch size {batch_size} exceeds maximum {max_allowed}. "
144
+ f"Capping to {max_allowed}"
145
+ )
146
+ return max_allowed
147
+
148
+ return batch_size
149
+
150
+ def validate_document_size(self, document: dict[str, Any]) -> None:
151
+ """
152
+ Validate that a document doesn't exceed size limits.
153
+
154
+ Uses actual BSON encoding for accurate size calculation.
155
+
156
+ Args:
157
+ document: Document to validate
158
+
159
+ Raises:
160
+ ResourceLimitExceeded: If document exceeds size limit
161
+ """
162
+ try:
163
+ # Use actual BSON encoding for accurate size
164
+ bson_bytes = bson_encode(document)
165
+ actual_size = len(bson_bytes)
166
+
167
+ if actual_size > self.max_document_size:
168
+ raise ResourceLimitExceeded(
169
+ f"Document size {actual_size} bytes exceeds maximum "
170
+ f"{self.max_document_size} bytes",
171
+ limit_type="document_size",
172
+ limit_value=self.max_document_size,
173
+ actual_value=actual_size,
174
+ )
175
+ except ResourceLimitExceeded:
176
+ # Re-raise our validation exceptions immediately
177
+ raise
178
+ except InvalidDocument as e:
179
+ # If BSON encoding fails, log warning but don't fail
180
+ # MongoDB will catch this anyway during actual insert
181
+ logger.warning(f"Could not encode document as BSON for size validation: {e}")
182
+
183
+ def validate_documents_size(self, documents: list[dict[str, Any]]) -> None:
184
+ """
185
+ Validate that multiple documents don't exceed size limits.
186
+
187
+ Args:
188
+ documents: List of documents to validate
189
+
190
+ Raises:
191
+ ResourceLimitExceeded: If any document exceeds size limit
192
+ """
193
+ for idx, doc in enumerate(documents):
194
+ try:
195
+ self.validate_document_size(doc)
196
+ except ResourceLimitExceeded as e:
197
+ # Add document index to error context
198
+ raise ResourceLimitExceeded(
199
+ f"{e.message} (document index: {idx})",
200
+ limit_type=e.limit_type,
201
+ limit_value=e.limit_value,
202
+ actual_value=e.actual_value,
203
+ context={**(e.context or {}), "document_index": idx},
204
+ ) from e