Commit bb521e8
fix(auth): eliminate duplicate DB sessions in auth and RBAC middleware (#3886)
* fix: eliminate duplicate DB sessions in auth and RBAC middleware
Implements session reuse pattern from PR #3600 and PR #3813 to achieve
1 shared database session per request across all middleware layers.
**Changes:**
- Auth middleware: Added _get_or_create_session() helper to reuse
request.state.db from ObservabilityMiddleware (lines 134, 159, 213)
- RBAC middleware: Updated deprecated get_db() to accept optional
request parameter and reuse middleware session when available
- Transaction control: Delegated all commit/rollback to get_db() per
PR #3813 (removed db.commit() from auth middleware)
- Added 7 unit tests for auth session reuse patterns
- Added 7 unit tests for RBAC get_db() deprecation
- Added 6 integration tests for end-to-end session sharing validation
**Impact:**
- Reduces session creation from 4-6 per request to 1 per request
- Prevents connection pool exhaustion under load
- Achieves 100% test coverage (435 statements, 0 missing)
**Security:**
- Transaction isolation maintained (get_db() controls all commits)
- Connection invalidation for PgBouncer compatibility
- Backwards compatible (existing dependency overrides work)
Closes #3622
Signed-off-by: Mohan Lakshmaiah <mohan.economist@gmail.com>
* fix: ensure auth logs are committed in hard-deny paths
Fixes critical bug where auth failure logs were lost when API requests
received hard-deny responses (401/403) that return JSONResponse immediately
without reaching get_db().
**Root Cause:**
- Auth middleware writes logs to session but delegated commit to get_db()
- Hard-deny API responses return JSONResponse immediately (lines 243-247)
- Route handler never runs, get_db() never called, logs never committed
- Browser requests work fine (continue to route handler at line 236)
**Fix:**
- Added db.commit() after logging in both success and failure paths
- Logs persist immediately, even if request doesn't reach get_db()
- For requests that continue to route handler, get_db() commits again (no-op)
- SQLAlchemy allows multiple commits - second commit is safe
**Test Coverage:**
- Added regression test: test_auth_failure_logs_committed_before_hard_deny_api_response
- All 29 auth middleware tests pass
- Maintained 100% code coverage
Signed-off-by: Mohan Lakshmaiah <mohan.economist@gmail.com>
* fix(build): use system uv binary consistently in Makefile
Replace hardcoded 'uv' commands with $(UV_BIN) variable reference
across all targets to ensure consistent resolution of the uv binary
path. Export UV_BIN to make it available to recursive make calls.
This fixes build failures where make targets tried to execute
'uv' from inside the activated virtual environment, where it
doesn't exist. The uv tool is a system-level package manager
and should be resolved from the system PATH or ~/.local/bin.
Changes:
- Use $(UV_BIN) in install, install-dev, install-db, update targets
- Use $(UV_BIN) in ensure_pip_package macro (fixes recursive make)
- Use $(UV_BIN) in sbom, alembic, pypiserver, maturin targets
- Export UV_BIN for visibility in child make processes
Benefits:
- Fixes "No such file or directory" errors for uv
- Makes Makefile more robust across different uv installations
- Maintains existing fallback logic (PATH or ~/.local/bin/uv)
- No breaking changes for existing setups
Signed-off-by: Mohan Lakshmaiah <mohan.economist@gmail.com>
* fix(auth): prevent stale session reference and ensure log persistence
Fix two bugs in auth middleware session handling:
1. _get_or_create_session() stored newly created sessions in
request.state.db but then closed them after logging, leaving a stale
closed-session reference for downstream get_db() to find. Remove the
request.state.db assignment for owned sessions so route handlers
create their own sessions via get_db().
2. Generic Exception path (non-HTTP auth failures) did not commit
security logs before closing the owned session, silently losing log
entries. Add db.commit() consistent with the success and hard-deny
paths.
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* fix(auth): rollback shared session on logging failure and rewrite integration tests
Address two findings from code review:
1. When security logging raises an exception (commit failure, connection
error), the shared session from ObservabilityMiddleware is left in
PendingRollbackError state. Downstream call_next()/get_db() then
inherits a broken session. Add db.rollback() (with invalidate()
fallback) in all three exception handlers — matching the pattern
used by ObservabilityMiddleware and main.py:get_db().
2. Rewrite integration tests: the originals targeted nonexistent routes
(/api/v1/servers, /admin/llm/providers) and had assertions too weak
to catch regressions (session_count <= 1 passes when 0 sessions are
created). New tests directly exercise _get_or_create_session(),
rbac.get_db() reuse, shared-session rollback, and the full
middleware stack via /health.
Test coverage: 100% (460 statements, 0 missing) across both auth
middleware and rbac modules.
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* chore: update secrets baseline after rebase
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
* chore: exclude .npmrc from sdist to fix check-manifest
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
---------
Signed-off-by: Mohan Lakshmaiah <mohan.economist@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>1 parent 2b1d01a commit bb521e8
8 files changed
Lines changed: 1100 additions & 54 deletions
File tree
- mcpgateway/middleware
- tests
- integration
- unit/mcpgateway/middleware
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
344 | 344 | | |
345 | 345 | | |
346 | 346 | | |
347 | | - | |
| 347 | + | |
348 | 348 | | |
349 | 349 | | |
350 | 350 | | |
351 | 351 | | |
352 | 352 | | |
353 | 353 | | |
354 | 354 | | |
355 | | - | |
| 355 | + | |
356 | 356 | | |
357 | 357 | | |
358 | 358 | | |
359 | 359 | | |
360 | 360 | | |
361 | 361 | | |
362 | 362 | | |
363 | | - | |
| 363 | + | |
364 | 364 | | |
365 | 365 | | |
366 | 366 | | |
367 | 367 | | |
368 | 368 | | |
369 | 369 | | |
370 | 370 | | |
371 | | - | |
| 371 | + | |
372 | 372 | | |
373 | 373 | | |
374 | 374 | | |
375 | 375 | | |
376 | 376 | | |
377 | 377 | | |
378 | 378 | | |
379 | | - | |
| 379 | + | |
380 | 380 | | |
381 | 381 | | |
382 | 382 | | |
383 | 383 | | |
384 | 384 | | |
385 | 385 | | |
386 | 386 | | |
387 | | - | |
| 387 | + | |
388 | 388 | | |
389 | 389 | | |
390 | 390 | | |
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
394 | 394 | | |
395 | | - | |
| 395 | + | |
396 | 396 | | |
397 | 397 | | |
398 | 398 | | |
399 | 399 | | |
400 | 400 | | |
401 | 401 | | |
402 | 402 | | |
403 | | - | |
| 403 | + | |
404 | 404 | | |
405 | 405 | | |
406 | 406 | | |
407 | 407 | | |
408 | 408 | | |
409 | 409 | | |
410 | 410 | | |
411 | | - | |
| 411 | + | |
412 | 412 | | |
413 | 413 | | |
414 | 414 | | |
| |||
8316 | 8316 | | |
8317 | 8317 | | |
8318 | 8318 | | |
8319 | | - | |
| 8319 | + | |
8320 | 8320 | | |
8321 | 8321 | | |
8322 | 8322 | | |
8323 | 8323 | | |
8324 | 8324 | | |
8325 | 8325 | | |
8326 | 8326 | | |
8327 | | - | |
| 8327 | + | |
8328 | 8328 | | |
8329 | 8329 | | |
8330 | 8330 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
192 | 192 | | |
193 | 193 | | |
194 | 194 | | |
| 195 | + | |
195 | 196 | | |
196 | 197 | | |
197 | 198 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
149 | | - | |
150 | | - | |
| 149 | + | |
| 150 | + | |
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
| |||
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
| 181 | + | |
181 | 182 | | |
182 | 183 | | |
183 | 184 | | |
| |||
192 | 193 | | |
193 | 194 | | |
194 | 195 | | |
195 | | - | |
| 196 | + | |
196 | 197 | | |
197 | 198 | | |
198 | 199 | | |
199 | | - | |
| 200 | + | |
200 | 201 | | |
201 | 202 | | |
202 | 203 | | |
203 | | - | |
| 204 | + | |
204 | 205 | | |
205 | 206 | | |
206 | 207 | | |
| |||
211 | 212 | | |
212 | 213 | | |
213 | 214 | | |
214 | | - | |
| 215 | + | |
215 | 216 | | |
216 | 217 | | |
217 | 218 | | |
| |||
2987 | 2988 | | |
2988 | 2989 | | |
2989 | 2990 | | |
2990 | | - | |
| 2991 | + | |
2991 | 2992 | | |
2992 | 2993 | | |
2993 | 2994 | | |
| |||
3865 | 3866 | | |
3866 | 3867 | | |
3867 | 3868 | | |
3868 | | - | |
3869 | | - | |
3870 | | - | |
| 3869 | + | |
| 3870 | + | |
| 3871 | + | |
3871 | 3872 | | |
3872 | 3873 | | |
3873 | 3874 | | |
| |||
6317 | 6318 | | |
6318 | 6319 | | |
6319 | 6320 | | |
6320 | | - | |
| 6321 | + | |
6321 | 6322 | | |
6322 | 6323 | | |
6323 | 6324 | | |
| |||
6409 | 6410 | | |
6410 | 6411 | | |
6411 | 6412 | | |
6412 | | - | |
| 6413 | + | |
6413 | 6414 | | |
6414 | 6415 | | |
6415 | 6416 | | |
| |||
6587 | 6588 | | |
6588 | 6589 | | |
6589 | 6590 | | |
6590 | | - | |
| 6591 | + | |
6591 | 6592 | | |
6592 | 6593 | | |
6593 | 6594 | | |
| |||
6756 | 6757 | | |
6757 | 6758 | | |
6758 | 6759 | | |
6759 | | - | |
| 6760 | + | |
6760 | 6761 | | |
6761 | 6762 | | |
6762 | 6763 | | |
| |||
6823 | 6824 | | |
6824 | 6825 | | |
6825 | 6826 | | |
6826 | | - | |
| 6827 | + | |
6827 | 6828 | | |
6828 | 6829 | | |
6829 | 6830 | | |
| |||
8171 | 8172 | | |
8172 | 8173 | | |
8173 | 8174 | | |
8174 | | - | |
| 8175 | + | |
8175 | 8176 | | |
8176 | 8177 | | |
8177 | 8178 | | |
| |||
0 commit comments