Skip to content

Commit 0831c7e

Browse files
author
Olivier Gintrand
committed
fix(tests): use resolve_gateway_auth_headers (async) + restore _meta guard
- Rename stale build_gateway_auth_headers patches to async resolve_gateway_auth_headers across transport/resource/tool/identity propagation unit tests (callers now use the async resolver). - Remove duplicate build_ patch lines left next to resolve_ patches. - Restore validate_meta_data import + guard in read_resource direct-proxy branch, forward meta as model_dump() dict, log only meta keys (CWE-532). Signed-off-by: Olivier Gintrand <olivier.gintrand@forterro.com>
1 parent e632591 commit 0831c7e

5 files changed

Lines changed: 39 additions & 42 deletions

File tree

mcpgateway/transports/streamablehttp_transport.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
# First-Party
6666
from mcpgateway.cache.global_config_cache import global_config_cache
6767
from mcpgateway.common.models import LogLevel
68+
from mcpgateway.common.validators import validate_meta_data as _validate_meta_data
6869
from mcpgateway.config import settings
6970
from mcpgateway.db import Gateway as DbGateway
7071
from mcpgateway.db import Server as DbServer
@@ -2636,18 +2637,22 @@ async def read_resource(resource_uri: str) -> Union[str, bytes]:
26362637
meta = None
26372638
try:
26382639
request_ctx = mcp_app.request_context
2639-
meta = request_ctx.meta
2640+
if request_ctx and request_ctx.meta is not None:
2641+
meta = request_ctx.meta.model_dump()
2642+
# CWE-532: log only _meta keys, never values (may contain sensitive data)
26402643
logger.info(
2641-
"Using direct_proxy mode for resources/read %s, server %s, gateway %s (from %s header), forwarding _meta: %s",
2644+
"Using direct_proxy mode for resources/read %s, server %s, gateway %s (from %s header), forwarding _meta keys: %s",
26422645
resource_uri,
26432646
server_id,
26442647
gateway.id,
26452648
GATEWAY_ID_HEADER,
2646-
meta,
2649+
sorted(meta.keys()) if meta else None,
26472650
)
26482651
except (LookupError, AttributeError) as e:
26492652
logger.debug("No request context available for _meta extraction: %s", e)
26502653

2654+
# CWE-400: validate _meta limits before network I/O (bypassed in direct-proxy branch)
2655+
_validate_meta_data(meta)
26512656
contents = await _proxy_read_resource_to_gateway(gateway, str(resource_uri), user_context, meta)
26522657
if contents:
26532658
# Return first content (text or blob)

tests/unit/mcpgateway/services/test_resource_service.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7272,7 +7272,7 @@ async def mock_streamable_client(*_args, **_kwargs):
72727272
with (
72737273
patch("mcpgateway.services.resource_service.settings") as mock_settings,
72747274
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7275-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={"Authorization": "Bearer remote-token"}),
7275+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={"Authorization": "Bearer remote-token"}),
72767276
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
72777277
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
72787278
self._common_patches(resource_service),
@@ -7317,7 +7317,7 @@ async def mock_streamable_client(*_args, **_kwargs):
73177317
with (
73187318
patch("mcpgateway.services.resource_service.settings") as mock_settings,
73197319
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7320-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7320+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
73217321
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
73227322
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
73237323
self._common_patches(resource_service),
@@ -7360,7 +7360,7 @@ async def mock_streamable_client(*_args, **_kwargs):
73607360
with (
73617361
patch("mcpgateway.services.resource_service.settings") as mock_settings,
73627362
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7363-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7363+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
73647364
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
73657365
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
73667366
self._common_patches(resource_service),
@@ -7401,7 +7401,7 @@ async def mock_streamable_client(*_args, **_kwargs):
74017401
with (
74027402
patch("mcpgateway.services.resource_service.settings") as mock_settings,
74037403
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7404-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7404+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
74057405
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
74067406
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
74077407
self._common_patches(resource_service),
@@ -7458,7 +7458,7 @@ async def mock_streamable_client_error(*_args, **_kwargs):
74587458
with (
74597459
patch("mcpgateway.services.resource_service.settings") as mock_settings,
74607460
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7461-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7461+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
74627462
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client_error),
74637463
):
74647464
mock_settings.mcpgateway_direct_proxy_enabled = True
@@ -7499,7 +7499,7 @@ async def mock_streamable_client(*_args, **_kwargs):
74997499
with (
75007500
patch("mcpgateway.services.resource_service.settings") as mock_settings,
75017501
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7502-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7502+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
75037503
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
75047504
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
75057505
self._common_patches(resource_service),
@@ -7545,7 +7545,7 @@ async def mock_streamable_client(*_args, **kwargs):
75457545
with (
75467546
patch("mcpgateway.services.resource_service.settings") as mock_settings,
75477547
patch("mcpgateway.services.resource_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
7548-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={}),
7548+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
75497549
patch("mcpgateway.services.resource_service.streamablehttp_client", mock_streamable_client),
75507550
patch("mcpgateway.services.resource_service.ClientSession", return_value=client_session_cm),
75517551
self._common_patches(resource_service),

tests/unit/mcpgateway/services/test_tool_service.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8328,7 +8328,6 @@ async def mock_streamable_client(*_args, **_kwargs):
83288328
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway)),
83298329
patch("mcpgateway.services.tool_service.settings") as mock_settings,
83308330
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8331-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={"Authorization": "Bearer remote-token"}),
83328331
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={"Authorization": "Bearer remote-token"}),
83338332
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
83348333
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),
@@ -8368,7 +8367,6 @@ async def mock_streamable_client(*_args, **_kwargs):
83688367
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway)),
83698368
patch("mcpgateway.services.tool_service.settings") as mock_settings,
83708369
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8371-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
83728370
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
83738371
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
83748372
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),
@@ -8454,7 +8452,6 @@ async def mock_streamable_client_error(*_args, **_kwargs):
84548452
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway)),
84558453
patch("mcpgateway.services.tool_service.settings") as mock_settings,
84568454
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8457-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
84588455
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
84598456
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client_error),
84608457
):
@@ -8493,7 +8490,6 @@ async def mock_streamable_client(*_args, **kwargs):
84938490
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway)),
84948491
patch("mcpgateway.services.tool_service.settings") as mock_settings,
84958492
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8496-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={"Authorization": "Bearer xyz"}),
84978493
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={"Authorization": "Bearer xyz"}),
84988494
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
84998495
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),
@@ -8539,7 +8535,6 @@ async def mock_streamable_client(*_args, **kwargs):
85398535
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway)),
85408536
patch("mcpgateway.services.tool_service.settings") as mock_settings,
85418537
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8542-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
85438538
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
85448539
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
85458540
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),
@@ -8580,7 +8575,6 @@ async def mock_streamable_client(*_args, **_kwargs):
85808575
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway, tool_row=mock_tool)),
85818576
patch("mcpgateway.services.tool_service.settings") as mock_settings,
85828577
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8583-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
85848578
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
85858579
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
85868580
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),
@@ -8619,7 +8613,6 @@ async def mock_streamable_client(*_args, **_kwargs):
86198613
patch("mcpgateway.services.tool_service.fresh_db_session", self._make_fresh_db_session(mock_direct_gateway, tool_row=None)),
86208614
patch("mcpgateway.services.tool_service.settings") as mock_settings,
86218615
patch("mcpgateway.services.tool_service.check_gateway_access", new_callable=AsyncMock, return_value=True),
8622-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
86238616
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", new_callable=AsyncMock, return_value={}),
86248617
patch("mcpgateway.services.tool_service.streamablehttp_client", mock_streamable_client),
86258618
patch("mcpgateway.services.tool_service.ClientSession", return_value=client_session_cm),

tests/unit/mcpgateway/test_identity_propagation.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,7 @@ def __init__(self, uri, mimeType=None, text=""):
17361736
patch.object(service, "invoke_resource", AsyncMock(return_value="hello")),
17371737
patch("mcpgateway.services.resource_service.check_gateway_access", AsyncMock(return_value=True)),
17381738
patch.object(service, "_check_resource_access", AsyncMock(return_value=True)),
1739-
patch("mcpgateway.services.resource_service.build_gateway_auth_headers", return_value={"Authorization": "Bearer gateway"}),
1739+
patch("mcpgateway.services.resource_service.resolve_gateway_auth_headers", AsyncMock(return_value={"Authorization": "Bearer gateway"})),
17401740
patch("mcpgateway.services.resource_service.build_identity_headers", return_value={"X-Identity": "1"}) as mock_build_headers,
17411741
patch("mcpgateway.services.resource_service.streamablehttp_client", return_value=_AsyncCM()),
17421742
patch("mcpgateway.services.resource_service.ClientSession", _ClientSessionCM),
@@ -1817,7 +1817,6 @@ async def __aexit__(self, exc_type, exc, tb):
18171817
patch("mcpgateway.services.tool_service.fresh_db_session", return_value=_FreshDBSession(db)),
18181818
patch("mcpgateway.services.tool_service.check_gateway_access", AsyncMock(return_value=True)),
18191819
patch("mcpgateway.services.tool_service.resolve_gateway_auth_headers", AsyncMock(return_value={})),
1820-
patch("mcpgateway.services.tool_service.build_gateway_auth_headers", return_value={}),
18211820
patch("mcpgateway.services.tool_service.build_identity_headers", return_value={"X-Identity": "1"}) as mock_build_headers,
18221821
patch("mcpgateway.services.tool_service.build_identity_meta", return_value={"identity": True}) as mock_build_meta,
18231822
patch("mcpgateway.services.tool_service.create_span", return_value=mock_span),
@@ -2023,7 +2022,7 @@ async def __aexit__(self, exc_type, exc, tb):
20232022

20242023
try:
20252024
with (
2026-
patch("mcpgateway.transports.streamablehttp_transport.build_gateway_auth_headers", return_value={}),
2025+
patch("mcpgateway.transports.streamablehttp_transport.resolve_gateway_auth_headers", AsyncMock(return_value={})),
20272026
patch("mcpgateway.transports.streamablehttp_transport.build_identity_headers", return_value={"X-Identity": "1"}) as mock_build_headers,
20282027
patch("mcpgateway.transports.streamablehttp_transport.streamablehttp_client", return_value=_AsyncCM()),
20292028
patch("mcpgateway.transports.streamablehttp_transport.ClientSession", _ClientSessionCM),
@@ -2065,7 +2064,7 @@ async def __aexit__(self, exc_type, exc, tb):
20652064

20662065
try:
20672066
with (
2068-
patch("mcpgateway.transports.streamablehttp_transport.build_gateway_auth_headers", return_value={}),
2067+
patch("mcpgateway.transports.streamablehttp_transport.resolve_gateway_auth_headers", AsyncMock(return_value={})),
20692068
patch("mcpgateway.transports.streamablehttp_transport.build_identity_headers", return_value={"X-Identity": "1"}) as mock_build_headers,
20702069
patch("mcpgateway.transports.streamablehttp_transport.streamablehttp_client", return_value=_AsyncCM()),
20712070
patch("mcpgateway.transports.streamablehttp_transport.ClientSession", _ClientSessionCM),
@@ -2108,7 +2107,7 @@ async def __aexit__(self, exc_type, exc, tb):
21082107

21092108
try:
21102109
with (
2111-
patch("mcpgateway.transports.streamablehttp_transport.build_gateway_auth_headers", return_value={}),
2110+
patch("mcpgateway.transports.streamablehttp_transport.resolve_gateway_auth_headers", AsyncMock(return_value={})),
21122111
patch("mcpgateway.transports.streamablehttp_transport.build_identity_headers", return_value={"X-Identity": "1"}) as mock_build_headers,
21132112
patch("mcpgateway.transports.streamablehttp_transport.streamablehttp_client", return_value=_AsyncCM()),
21142113
patch("mcpgateway.transports.streamablehttp_transport.ClientSession", _ClientSessionCM),

0 commit comments

Comments
 (0)