mdb-engine 0.4.10__py3-none-any.whl → 0.4.11__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 +7 -5
- mdb_engine/auth/csrf.py +8 -3
- mdb_engine/core/engine.py +109 -20
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/METADATA +1 -1
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/RECORD +9 -9
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/WHEEL +0 -0
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/entry_points.txt +0 -0
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/licenses/LICENSE +0 -0
- {mdb_engine-0.4.10.dist-info → mdb_engine-0.4.11.dist-info}/top_level.txt +0 -0
mdb_engine/__init__.py
CHANGED
|
@@ -82,11 +82,13 @@ from .repositories import Entity, MongoRepository, Repository, UnitOfWork
|
|
|
82
82
|
from .utils import clean_mongo_doc, clean_mongo_docs
|
|
83
83
|
|
|
84
84
|
__version__ = (
|
|
85
|
-
"0.4.
|
|
86
|
-
# -
|
|
87
|
-
# -
|
|
88
|
-
# -
|
|
89
|
-
# -
|
|
85
|
+
"0.4.11" # Automatic WebSocket support improvements
|
|
86
|
+
# - Improved CORS config merging with proper wildcard handling
|
|
87
|
+
# - WebSocket route verification after registration
|
|
88
|
+
# - Startup verification logging for CORS config and WebSocket routes
|
|
89
|
+
# - Enhanced CSRF middleware error messages with path and CORS status
|
|
90
|
+
# - Better logging throughout WebSocket registration process
|
|
91
|
+
# - All WebSocket multi-app SSO features now work automatically
|
|
90
92
|
)
|
|
91
93
|
|
|
92
94
|
__all__ = [
|
mdb_engine/auth/csrf.py
CHANGED
|
@@ -210,14 +210,15 @@ class CSRFMiddleware(BaseHTTPMiddleware):
|
|
|
210
210
|
are registered on parent app), then falls back to request host.
|
|
211
211
|
"""
|
|
212
212
|
try:
|
|
213
|
-
#
|
|
213
|
+
# For WebSocket routes on parent app, request.app is parent app
|
|
214
|
+
# Parent app has merged CORS config from all child apps
|
|
214
215
|
cors_config = getattr(request.app.state, "cors_config", None)
|
|
215
216
|
if cors_config and cors_config.get("allow_origins"):
|
|
216
217
|
origins = cors_config["allow_origins"]
|
|
217
218
|
if origins:
|
|
218
219
|
return origins if isinstance(origins, list) else [origins]
|
|
219
|
-
except (AttributeError, TypeError, KeyError):
|
|
220
|
-
|
|
220
|
+
except (AttributeError, TypeError, KeyError) as e:
|
|
221
|
+
logger.debug(f"Could not read CORS config from app.state: {e}")
|
|
221
222
|
|
|
222
223
|
# Fallback: Check if this is a multi-app setup and try to find mounted app's CORS config
|
|
223
224
|
try:
|
|
@@ -249,6 +250,7 @@ class CSRFMiddleware(BaseHTTPMiddleware):
|
|
|
249
250
|
origin = f"{scheme}://{host}"
|
|
250
251
|
return [origin]
|
|
251
252
|
except (AttributeError, TypeError):
|
|
253
|
+
# Return empty list if we can't determine origin (will reject)
|
|
252
254
|
return []
|
|
253
255
|
|
|
254
256
|
def _validate_websocket_origin(self, request: Request) -> bool:
|
|
@@ -275,9 +277,12 @@ class CSRFMiddleware(BaseHTTPMiddleware):
|
|
|
275
277
|
if origin == allowed or origin.rstrip("/") == allowed.rstrip("/"):
|
|
276
278
|
return True
|
|
277
279
|
|
|
280
|
+
cors_config = getattr(request.app.state, "cors_config", None)
|
|
281
|
+
cors_enabled = cors_config.get("enabled", False) if cors_config else False
|
|
278
282
|
logger.warning(
|
|
279
283
|
f"WebSocket upgrade rejected - invalid Origin: {origin} "
|
|
280
284
|
f"(allowed: {allowed_origins}, app: {getattr(request.app, 'title', 'unknown')}, "
|
|
285
|
+
f"path: {request.url.path}, CORS enabled: {cors_enabled}, "
|
|
281
286
|
f"has_cors_config: {hasattr(request.app.state, 'cors_config')})"
|
|
282
287
|
)
|
|
283
288
|
return False
|
mdb_engine/core/engine.py
CHANGED
|
@@ -2212,7 +2212,18 @@ class MongoDBEngine:
|
|
|
2212
2212
|
# Merge allow_origins lists
|
|
2213
2213
|
child_origins = child_cors.get("allow_origins", [])
|
|
2214
2214
|
parent_origins = parent_cors.get("allow_origins", [])
|
|
2215
|
-
|
|
2215
|
+
|
|
2216
|
+
# CRITICAL: Handle wildcard origins correctly
|
|
2217
|
+
# If any child or parent has wildcard, merged config gets wildcard
|
|
2218
|
+
if "*" in child_origins:
|
|
2219
|
+
merged_origins = ["*"] # Wildcard takes precedence
|
|
2220
|
+
elif "*" in parent_origins:
|
|
2221
|
+
merged_origins = ["*"] # Keep wildcard if already set
|
|
2222
|
+
else:
|
|
2223
|
+
# Merge unique origins
|
|
2224
|
+
merged_origins = list(set(parent_origins + child_origins))
|
|
2225
|
+
if not merged_origins:
|
|
2226
|
+
merged_origins = ["*"] # Default to wildcard if empty
|
|
2216
2227
|
|
|
2217
2228
|
# CRITICAL: If ANY child app requires credentials, parent must allow them
|
|
2218
2229
|
# This is essential for SSO cookie-based authentication
|
|
@@ -2225,16 +2236,17 @@ class MongoDBEngine:
|
|
|
2225
2236
|
parent_app.state.cors_config = {
|
|
2226
2237
|
**parent_cors,
|
|
2227
2238
|
**child_cors,
|
|
2228
|
-
"allow_origins": merged_origins
|
|
2239
|
+
"allow_origins": merged_origins,
|
|
2229
2240
|
# If ANY child requires credentials, parent gets True (for SSO)
|
|
2230
2241
|
"allow_credentials": merged_allow_credentials,
|
|
2231
2242
|
}
|
|
2232
2243
|
else:
|
|
2233
2244
|
# Parent has no CORS config, use child's
|
|
2234
2245
|
parent_app.state.cors_config = child_cors
|
|
2235
|
-
logger.
|
|
2236
|
-
f"✅ Merged CORS config from
|
|
2237
|
-
f"
|
|
2246
|
+
logger.info(
|
|
2247
|
+
f"✅ Merged CORS config from '{slug}': "
|
|
2248
|
+
f"origins={parent_app.state.cors_config.get('allow_origins')}, "
|
|
2249
|
+
f"credentials={parent_app.state.cors_config.get('allow_credentials')}"
|
|
2238
2250
|
)
|
|
2239
2251
|
|
|
2240
2252
|
async def _register_websocket_routes(
|
|
@@ -2246,6 +2258,7 @@ class MongoDBEngine:
|
|
|
2246
2258
|
"""Register WebSocket routes on parent app for a child app."""
|
|
2247
2259
|
websockets_config = child_manifest.get("websockets")
|
|
2248
2260
|
if not websockets_config:
|
|
2261
|
+
logger.debug(f"No WebSocket configuration found for app '{slug}'")
|
|
2249
2262
|
return
|
|
2250
2263
|
|
|
2251
2264
|
try:
|
|
@@ -2253,6 +2266,9 @@ class MongoDBEngine:
|
|
|
2253
2266
|
|
|
2254
2267
|
from ..routing.websockets import create_websocket_endpoint
|
|
2255
2268
|
|
|
2269
|
+
registered_count = 0
|
|
2270
|
+
failed_count = 0
|
|
2271
|
+
|
|
2256
2272
|
for endpoint_name, endpoint_config in websockets_config.items():
|
|
2257
2273
|
ws_path = endpoint_config.get("path", f"/{endpoint_name}")
|
|
2258
2274
|
# Combine mount prefix with WebSocket path
|
|
@@ -2273,24 +2289,65 @@ class MongoDBEngine:
|
|
|
2273
2289
|
|
|
2274
2290
|
ping_interval = endpoint_config.get("ping_interval", 30)
|
|
2275
2291
|
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2292
|
+
try:
|
|
2293
|
+
# Create WebSocket handler
|
|
2294
|
+
handler = create_websocket_endpoint(
|
|
2295
|
+
app_slug=slug,
|
|
2296
|
+
path=ws_path,
|
|
2297
|
+
endpoint_name=endpoint_name,
|
|
2298
|
+
handler=None,
|
|
2299
|
+
require_auth=require_auth,
|
|
2300
|
+
ping_interval=ping_interval,
|
|
2301
|
+
)
|
|
2285
2302
|
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2303
|
+
# Register on parent app with full path
|
|
2304
|
+
ws_router = APIRouter()
|
|
2305
|
+
ws_router.websocket(full_ws_path)(handler)
|
|
2306
|
+
parent_app.include_router(ws_router)
|
|
2307
|
+
|
|
2308
|
+
logger.info(
|
|
2309
|
+
f"✅ Registered WebSocket route '{full_ws_path}' "
|
|
2310
|
+
f"for mounted app '{slug}' (mounted at '{path_prefix}', "
|
|
2311
|
+
f"auth: {require_auth}, ping: {ping_interval}s)"
|
|
2312
|
+
)
|
|
2313
|
+
|
|
2314
|
+
# Verify route was actually registered
|
|
2315
|
+
registered_routes = [
|
|
2316
|
+
r
|
|
2317
|
+
for r in parent_app.routes
|
|
2318
|
+
if hasattr(r, "path") and full_ws_path in str(getattr(r, "path", ""))
|
|
2319
|
+
]
|
|
2320
|
+
if registered_routes:
|
|
2321
|
+
registered_count += 1
|
|
2322
|
+
logger.debug(
|
|
2323
|
+
f"✅ Verified WebSocket route '{full_ws_path}' "
|
|
2324
|
+
f"registered for '{slug}'"
|
|
2325
|
+
)
|
|
2326
|
+
else:
|
|
2327
|
+
failed_count += 1
|
|
2328
|
+
logger.warning(
|
|
2329
|
+
f"⚠️ WebSocket route '{full_ws_path}' not found after registration "
|
|
2330
|
+
f"for '{slug}' - route may not be accessible"
|
|
2331
|
+
)
|
|
2332
|
+
except (ValueError, TypeError, AttributeError, RuntimeError) as e:
|
|
2333
|
+
failed_count += 1
|
|
2334
|
+
logger.error(
|
|
2335
|
+
f"Failed to register WebSocket route '{full_ws_path}' "
|
|
2336
|
+
f"for mounted app '{slug}': {e}",
|
|
2337
|
+
exc_info=True,
|
|
2338
|
+
)
|
|
2290
2339
|
|
|
2340
|
+
# Summary logging
|
|
2341
|
+
total_routes = len(websockets_config)
|
|
2342
|
+
if registered_count > 0:
|
|
2291
2343
|
logger.info(
|
|
2292
|
-
f"✅
|
|
2293
|
-
f"
|
|
2344
|
+
f"✅ WebSocket registration summary for '{slug}': "
|
|
2345
|
+
f"{registered_count}/{total_routes} routes registered successfully"
|
|
2346
|
+
)
|
|
2347
|
+
if failed_count > 0:
|
|
2348
|
+
logger.warning(
|
|
2349
|
+
f"⚠️ WebSocket registration issues for '{slug}': "
|
|
2350
|
+
f"{failed_count}/{total_routes} routes failed to register"
|
|
2294
2351
|
)
|
|
2295
2352
|
except ImportError:
|
|
2296
2353
|
logger.warning(
|
|
@@ -2668,6 +2725,38 @@ class MongoDBEngine:
|
|
|
2668
2725
|
# This ensures the state reflects the final mounted_apps list
|
|
2669
2726
|
app.state.mounted_apps = mounted_apps
|
|
2670
2727
|
|
|
2728
|
+
# VERIFICATION: Log final configuration state
|
|
2729
|
+
logger.info("=" * 60)
|
|
2730
|
+
logger.info("MDB-Engine Multi-App Configuration Verification")
|
|
2731
|
+
logger.info("=" * 60)
|
|
2732
|
+
|
|
2733
|
+
# Verify CORS config
|
|
2734
|
+
cors_config = getattr(app.state, "cors_config", None)
|
|
2735
|
+
if cors_config:
|
|
2736
|
+
logger.info(
|
|
2737
|
+
f"✅ CORS Config: enabled={cors_config.get('enabled')}, "
|
|
2738
|
+
f"origins={cors_config.get('allow_origins')}, "
|
|
2739
|
+
f"credentials={cors_config.get('allow_credentials')}"
|
|
2740
|
+
)
|
|
2741
|
+
else:
|
|
2742
|
+
logger.warning("⚠️ No CORS config found on parent app")
|
|
2743
|
+
|
|
2744
|
+
# Verify WebSocket routes
|
|
2745
|
+
ws_routes = [
|
|
2746
|
+
r for r in app.routes if hasattr(r, "path") and "/ws" in str(getattr(r, "path", ""))
|
|
2747
|
+
]
|
|
2748
|
+
if ws_routes:
|
|
2749
|
+
logger.info(f"✅ Found {len(ws_routes)} WebSocket route(s):")
|
|
2750
|
+
for route in ws_routes:
|
|
2751
|
+
route_path = getattr(route, "path", "unknown")
|
|
2752
|
+
logger.info(f" 🔌 {route_path}")
|
|
2753
|
+
else:
|
|
2754
|
+
logger.warning(
|
|
2755
|
+
"⚠️ No WebSocket routes found - check manifest.json websockets config"
|
|
2756
|
+
)
|
|
2757
|
+
|
|
2758
|
+
logger.info("=" * 60)
|
|
2759
|
+
|
|
2671
2760
|
yield
|
|
2672
2761
|
|
|
2673
2762
|
# Shutdown is handled by parent app
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
mdb_engine/README.md,sha256=T3EFGcPopY9LslYW3lxgG3hohWkAOmBNbYG0FDMUJiY,3502
|
|
2
|
-
mdb_engine/__init__.py,sha256=
|
|
2
|
+
mdb_engine/__init__.py,sha256=Fs_kQ4wpgcfaZcqFh7IJNmbB-nvo9Z1DwUYML3palCM,3554
|
|
3
3
|
mdb_engine/config.py,sha256=DTAyxfKB8ogyI0v5QR9Y-SJOgXQr_eDBCKxNBSqEyLc,7269
|
|
4
4
|
mdb_engine/constants.py,sha256=eaotvW57TVOg7rRbLziGrVNoP7adgw_G9iVByHezc_A,7837
|
|
5
5
|
mdb_engine/dependencies.py,sha256=MJuYQhZ9ZGzXlip1ha5zba9Rvn04HDPWahJFJH81Q2s,14107
|
|
@@ -14,7 +14,7 @@ mdb_engine/auth/casbin_models.py,sha256=7XtFmRBhhjw1nKprnluvjyJoTj5fzdPeQwVvo6fI
|
|
|
14
14
|
mdb_engine/auth/config_defaults.py,sha256=1YI_hIHuTiEXpkEYMcufNHdLr1oxPiJylg3CKrJCSGY,2012
|
|
15
15
|
mdb_engine/auth/config_helpers.py,sha256=Qharb2YagLOKDGtE7XhYRDbBoQ_KGykrcIKrsOwWIJ4,6303
|
|
16
16
|
mdb_engine/auth/cookie_utils.py,sha256=j04qXq5GiJrnnJUAP5Z_N1CAFbx9CZiyF5u9xIiQ3vo,4876
|
|
17
|
-
mdb_engine/auth/csrf.py,sha256=
|
|
17
|
+
mdb_engine/auth/csrf.py,sha256=7zLiX9IEvgBXp3DjVBmcaYATS6cTelQReUYYkiVas6M,17626
|
|
18
18
|
mdb_engine/auth/decorators.py,sha256=LkVVEuRrT0Iz8EwctN14BEi3fSV-xtN6DaGXgtbiYYo,12287
|
|
19
19
|
mdb_engine/auth/dependencies.py,sha256=JB1iYvZJgTR6gcaiGe_GJFCS6NdUKMxWBZRv6vVxnzw,27112
|
|
20
20
|
mdb_engine/auth/helpers.py,sha256=BCrid985cYh-3h5ZMUV9TES0q40uJXio4oYKQZta7KA,1970
|
|
@@ -46,7 +46,7 @@ mdb_engine/core/app_registration.py,sha256=7szt2a7aBkpSppjmhdkkPPYMKGKo0MkLKZeEe
|
|
|
46
46
|
mdb_engine/core/app_secrets.py,sha256=bo-syg9UUATibNyXEZs-0TTYWG-JaY-2S0yNSGA12n0,10524
|
|
47
47
|
mdb_engine/core/connection.py,sha256=XnwuPG34pJ7kJGJ84T0mhj1UZ6_CLz_9qZf6NRYGIS8,8346
|
|
48
48
|
mdb_engine/core/encryption.py,sha256=RZ5LPF5g28E3ZBn6v1IMw_oas7u9YGFtBcEj8lTi9LM,7515
|
|
49
|
-
mdb_engine/core/engine.py,sha256=
|
|
49
|
+
mdb_engine/core/engine.py,sha256=vLD4Wt1dqAGx15uQqapw2NnSHQLwJl5TetBJpzWNSTs,150167
|
|
50
50
|
mdb_engine/core/index_management.py,sha256=9-r7MIy3JnjQ35sGqsbj8K_I07vAUWtAVgSWC99lJcE,5555
|
|
51
51
|
mdb_engine/core/manifest.py,sha256=jguhjVPAHMZGxOJcdSGouv9_XiKmxUjDmyjn2yXHCj4,139205
|
|
52
52
|
mdb_engine/core/ray_integration.py,sha256=vexYOzztscvRYje1xTNmXJbi99oJxCaVJAwKfTNTF_E,13610
|
|
@@ -89,9 +89,9 @@ mdb_engine/routing/__init__.py,sha256=reupjHi_RTc2ZBA4AH5XzobAmqy4EQIsfSUcTkFknU
|
|
|
89
89
|
mdb_engine/routing/websockets.py,sha256=3X4OjQv_Nln4UmeifJky0gFhMG8A6alR77I8g1iIOLY,29311
|
|
90
90
|
mdb_engine/utils/__init__.py,sha256=lDxQSGqkV4fVw5TWIk6FA6_eey_ZnEtMY0fir3cpAe8,236
|
|
91
91
|
mdb_engine/utils/mongo.py,sha256=Oqtv4tQdpiiZzrilGLEYQPo8Vmh8WsTQypxQs8Of53s,3369
|
|
92
|
-
mdb_engine-0.4.
|
|
93
|
-
mdb_engine-0.4.
|
|
94
|
-
mdb_engine-0.4.
|
|
95
|
-
mdb_engine-0.4.
|
|
96
|
-
mdb_engine-0.4.
|
|
97
|
-
mdb_engine-0.4.
|
|
92
|
+
mdb_engine-0.4.11.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
93
|
+
mdb_engine-0.4.11.dist-info/METADATA,sha256=P7zS3dkTt-ZqKU4c2yp8pjn57v-1u6gV9S9rtp91PN0,15811
|
|
94
|
+
mdb_engine-0.4.11.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
95
|
+
mdb_engine-0.4.11.dist-info/entry_points.txt,sha256=INCbYdFbBzJalwPwxliEzLmPfR57IvQ7RAXG_pn8cL8,48
|
|
96
|
+
mdb_engine-0.4.11.dist-info/top_level.txt,sha256=PH0UEBwTtgkm2vWvC9He_EOMn7hVn_Wg_Jyc0SmeO8k,11
|
|
97
|
+
mdb_engine-0.4.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|