Skip to content

Commit 8617367

Browse files
committed
refactor(rate-limiter): review fixes, Redis hardening, key-format parity tests
- Extract _dispatch_hook() shared by prompt_pre_fetch and tool_pre_invoke, reducing each hook to a single-line wrapper - Elevate Redis val_i64/val_f64 parse-error logging from warn to error so silent fail-open degradation surfaces in operator dashboards - Clamp sliding-window reset_timestamp with .max(1) so it is always strictly in the future even when the oldest entry expires in < 1 s - Add 5 s tokio::time::timeout around Redis connection establishment to prevent indefinite blocking on network partition - Replace silent except-pass in EVALSHA SHA tracking with logger.debug - Document dual Lua-script invariant (rolling-upgrade key-format parity) in both Python RedisBackend docstring and Rust redis_backend.rs header - Add 7 parametrized test_redis_key_format_parity_* tests validating that Python and Rust produce identical Redis keys for the same inputs - Revert unrelated .pyi stub changes for encoded_exfil_detection, pii_filter, retry_with_backoff, and secrets_detection Signed-off-by: Jonathan Springer <jps@s390x.com>
1 parent 8e632ea commit 8617367

16 files changed

Lines changed: 1612 additions & 891 deletions

File tree

.secrets.baseline

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "package-lock.json|Cargo.lock|^.secrets.baseline$|scripts/sign_image.sh|scripts/zap|sonar-project.properties|^/Users/brian/dev/github.ibm.com/contextforge-org/sps-pipeline-config/.secrets.baseline$|^./.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2026-03-28T19:41:44Z",
6+
"generated_at": "2026-04-02T13:34:26Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -10510,83 +10510,83 @@
1051010510
"type": "Secret Keyword",
1051110511
"verified_result": null
1051210512
},
10513-
{
10514-
"hashed_secret": "f5cd573c18bf811f82a886ceb6866b05d5ef02cd",
10515-
"is_secret": false,
10516-
"is_verified": false,
10517-
"line_number": 885,
10518-
"type": "Secret Keyword",
10519-
"verified_result": null
10520-
},
1052110513
{
1052210514
"hashed_secret": "8ce647089e0614d3b924f4a0b8fb78268562ec7c",
1052310515
"is_secret": false,
1052410516
"is_verified": false,
10525-
"line_number": 1430,
10517+
"line_number": 1426,
1052610518
"type": "Secret Keyword",
1052710519
"verified_result": null
1052810520
},
1052910521
{
1053010522
"hashed_secret": "dc6f6cc49f767ae38db110a9e6c1adf5c651ecbf",
1053110523
"is_secret": false,
1053210524
"is_verified": false,
10533-
"line_number": 1474,
10525+
"line_number": 1470,
1053410526
"type": "Secret Keyword",
1053510527
"verified_result": null
1053610528
},
1053710529
{
1053810530
"hashed_secret": "7939ea1cdfc6d73115b0d736fa04012be2b25b18",
1053910531
"is_secret": false,
1054010532
"is_verified": false,
10541-
"line_number": 1565,
10533+
"line_number": 1561,
1054210534
"type": "Secret Keyword",
1054310535
"verified_result": null
1054410536
},
1054510537
{
1054610538
"hashed_secret": "91014bcbf183cf77807b4bd24f2e8652f67b56a0",
1054710539
"is_secret": false,
1054810540
"is_verified": false,
10549-
"line_number": 2073,
10541+
"line_number": 2069,
1055010542
"type": "Secret Keyword",
1055110543
"verified_result": null
1055210544
},
1055310545
{
1055410546
"hashed_secret": "61ac75f7e6677b79c219ce819d954e05f61b5d2c",
1055510547
"is_secret": false,
1055610548
"is_verified": false,
10557-
"line_number": 2091,
10549+
"line_number": 2087,
1055810550
"type": "Secret Keyword",
1055910551
"verified_result": null
1056010552
},
1056110553
{
1056210554
"hashed_secret": "8223fafd35f399e55c3cf611c3d6ebbf43d68d71",
1056310555
"is_secret": false,
1056410556
"is_verified": false,
10565-
"line_number": 2737,
10557+
"line_number": 2733,
1056610558
"type": "Secret Keyword",
1056710559
"verified_result": null
1056810560
},
1056910561
{
1057010562
"hashed_secret": "dfd99b5f25f839608a3c275c0f8ceb363f8f0bc0",
1057110563
"is_secret": false,
1057210564
"is_verified": false,
10573-
"line_number": 3514,
10565+
"line_number": 3510,
1057410566
"type": "Secret Keyword",
1057510567
"verified_result": null
1057610568
},
1057710569
{
1057810570
"hashed_secret": "5038e18712161fca54e52805726d3c70b296eff6",
1057910571
"is_secret": false,
1058010572
"is_verified": false,
10581-
"line_number": 3623,
10573+
"line_number": 3619,
10574+
"type": "Secret Keyword",
10575+
"verified_result": null
10576+
},
10577+
{
10578+
"hashed_secret": "f5cd573c18bf811f82a886ceb6866b05d5ef02cd",
10579+
"is_secret": false,
10580+
"is_verified": false,
10581+
"line_number": 3697,
1058210582
"type": "Secret Keyword",
1058310583
"verified_result": null
1058410584
},
1058510585
{
1058610586
"hashed_secret": "79bead8e6d65862a00cffaa12ccde1189ec34d29",
1058710587
"is_secret": false,
1058810588
"is_verified": false,
10589-
"line_number": 3822,
10589+
"line_number": 4080,
1059010590
"type": "Secret Keyword",
1059110591
"verified_result": null
1059210592
}

mcpgateway/auth.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,9 +1248,9 @@ def _set_trace_for_user(user_obj: EmailUser, *, teams: Any = _UNSET, auth_method
12481248
if request and global_context:
12491249
request.state.plugin_global_context = global_context
12501250

1251-
_propagate_tenant_id(request)
12521251
if plugin_manager and plugin_manager.config.plugin_settings.include_user_info:
12531252
_inject_userinfo_instate(request, user)
1253+
_propagate_tenant_id(request)
12541254

12551255
_set_trace_for_user(user)
12561256
return user
@@ -1378,9 +1378,9 @@ def _set_trace_for_user(user_obj: EmailUser, *, teams: Any = _UNSET, auth_method
13781378
headers={"WWW-Authenticate": "Bearer"},
13791379
)
13801380

1381-
_propagate_tenant_id(request)
13821381
if plugin_manager and plugin_manager.config.plugin_settings.include_user_info:
13831382
_inject_userinfo_instate(request, _user_from_cached_dict(cached_ctx.user))
1383+
_propagate_tenant_id(request)
13841384

13851385
cached_user = _user_from_cached_dict(cached_ctx.user)
13861386
_set_trace_for_user(
@@ -1517,9 +1517,9 @@ def _set_trace_for_user(user_obj: EmailUser, *, teams: Any = _UNSET, auth_method
15171517
headers={"WWW-Authenticate": "Bearer"},
15181518
)
15191519

1520-
_propagate_tenant_id(request)
15211520
if plugin_manager and plugin_manager.config.plugin_settings.include_user_info:
15221521
_inject_userinfo_instate(request, _batched_user)
1522+
_propagate_tenant_id(request)
15231523

15241524
_set_trace_for_user(
15251525
_batched_user,
@@ -1699,9 +1699,9 @@ def _set_trace_for_user(user_obj: EmailUser, *, teams: Any = _UNSET, auth_method
16991699
headers={"WWW-Authenticate": "Bearer"},
17001700
)
17011701

1702-
_propagate_tenant_id(request)
17031702
if plugin_manager and plugin_manager.config.plugin_settings.include_user_info:
17041703
_inject_userinfo_instate(request, user)
1704+
_propagate_tenant_id(request)
17051705

17061706
trace_teams = getattr(request.state, "token_teams", _UNSET) if request else _UNSET
17071707
_set_trace_for_user(user, teams=trace_teams, team_name=getattr(request.state, "trace_team_name", None) if request else None)
@@ -1717,6 +1717,9 @@ def _propagate_tenant_id(request: Optional[object] = None) -> None:
17171717
(the default) and the middleware has already created plugin_global_context.
17181718
17191719
Only writes when tenant_id is still None (no overwrite of plugin-set values).
1720+
1721+
Args:
1722+
request: The incoming request object, or ``None`` if unavailable.
17201723
"""
17211724
if not request:
17221725
return
@@ -1764,11 +1767,5 @@ def _inject_userinfo_instate(request: Optional[object] = None, user: Optional[Em
17641767
global_context.user["is_admin"] = user.is_admin
17651768
global_context.user["full_name"] = user.full_name
17661769

1767-
# Propagate team_id → tenant_id for by_tenant rate limiting (only when not already set)
1768-
if request and global_context.tenant_id is None:
1769-
team_id = getattr(getattr(request, "state", None), "team_id", None)
1770-
if team_id:
1771-
global_context.tenant_id = team_id
1772-
17731770
if request and global_context:
17741771
request.state.plugin_global_context = global_context

plugins/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ plugins:
212212
author: "Mihai Criveti"
213213
hooks: ["prompt_pre_fetch", "tool_pre_invoke"]
214214
tags: ["limits", "throttle"]
215-
mode: "enforce"
215+
mode: "disabled"
216216
priority: 20
217217
conditions: []
218218
config:

0 commit comments

Comments
 (0)