From f145c7db940f72cb9ad76b99793267f619e63217 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Thu, 7 May 2026 15:23:00 -0400 Subject: [PATCH 1/4] PYTHON-5756 - Fix BSON Binary type length bug (#2790) --- bson/_cbsonmodule.c | 2 +- test/test_bson.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bson/_cbsonmodule.c b/bson/_cbsonmodule.c index 330a52a73..366129936 100644 --- a/bson/_cbsonmodule.c +++ b/bson/_cbsonmodule.c @@ -2281,7 +2281,7 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer, } memcpy(&length, buffer + *position, 4); length = BSON_UINT32_FROM_LE(length); - if (max < length) { + if (max - 5 < length) { // Account for 5-byte header. max >= 5 guaranteed above goto invalid; } diff --git a/test/test_bson.py b/test/test_bson.py index ffc02965f..ae1807e5f 100644 --- a/test/test_bson.py +++ b/test/test_bson.py @@ -1269,6 +1269,22 @@ class TestBSON(unittest.TestCase): encode(doc) self.assertEqual(cm.exception.document, doc) + def test_binary_length_accounts_for_header(self): + size = 20 + binary_length = 12 # 5 more than the actual 7 bytes + + payload = b"" + payload += struct.pack(" Date: Thu, 7 May 2026 15:23:07 -0400 Subject: [PATCH 2/4] PYTHON-5708 - Unskip large encryption tests on mongocryptd (#2793) --- test/asynchronous/test_encryption.py | 4 ---- test/test_encryption.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/test/asynchronous/test_encryption.py b/test/asynchronous/test_encryption.py index 1503f54c7..455b1940c 100644 --- a/test/asynchronous/test_encryption.py +++ b/test/asynchronous/test_encryption.py @@ -876,8 +876,6 @@ class TestViews(AsyncEncryptionIntegrationTest): class TestCorpus(AsyncEncryptionIntegrationTest): - # PYTHON-5708: Encryption tests sending large payloads fail on some mongocryptd versions. - @async_client_context.require_version_max(6, 99) @unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set") async def asyncSetUp(self): await super().asyncSetUp() @@ -1054,8 +1052,6 @@ class TestBsonSizeBatches(AsyncEncryptionIntegrationTest): client_encrypted: AsyncMongoClient listener: OvertCommandListener - # PYTHON-5708: Encryption tests sending large payloads fail on some mongocryptd versions. - @async_client_context.require_version_max(6, 99) async def asyncSetUp(self): await super().asyncSetUp() db = async_client_context.client.db diff --git a/test/test_encryption.py b/test/test_encryption.py index 099336227..7df9e7ac3 100644 --- a/test/test_encryption.py +++ b/test/test_encryption.py @@ -872,8 +872,6 @@ class TestViews(EncryptionIntegrationTest): class TestCorpus(EncryptionIntegrationTest): - # PYTHON-5708: Encryption tests sending large payloads fail on some mongocryptd versions. - @client_context.require_version_max(6, 99) @unittest.skipUnless(any(AWS_CREDS.values()), "AWS environment credentials are not set") def setUp(self): super().setUp() @@ -1050,8 +1048,6 @@ class TestBsonSizeBatches(EncryptionIntegrationTest): client_encrypted: MongoClient listener: OvertCommandListener - # PYTHON-5708: Encryption tests sending large payloads fail on some mongocryptd versions. - @client_context.require_version_max(6, 99) def setUp(self): super().setUp() db = client_context.client.db From a50550535dc9fe8800b66591bc827e71a4bf6dd8 Mon Sep 17 00:00:00 2001 From: Qi Deng Date: Wed, 13 May 2026 06:33:42 -0700 Subject: [PATCH 3/4] URL-encode client_id in Azure IMDS token request (#2787) Co-authored-by: Qi Deng --- pymongo/_azure_helpers.py | 3 ++- test/test_azure_helpers.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pymongo/_azure_helpers.py b/pymongo/_azure_helpers.py index 8a7af0b40..b7a518185 100644 --- a/pymongo/_azure_helpers.py +++ b/pymongo/_azure_helpers.py @@ -17,6 +17,7 @@ from __future__ import annotations import json from typing import Any, Optional +from urllib.parse import quote def _get_azure_response( @@ -29,7 +30,7 @@ def _get_azure_response( url += "?api-version=2018-02-01" url += f"&resource={resource}" if client_id: - url += f"&client_id={client_id}" + url += f"&client_id={quote(client_id)}" headers = {"Metadata": "true", "Accept": "application/json"} request = Request(url, headers=headers) # noqa: S310 try: diff --git a/test/test_azure_helpers.py b/test/test_azure_helpers.py index 6fe645187..25d1a779c 100644 --- a/test/test_azure_helpers.py +++ b/test/test_azure_helpers.py @@ -150,6 +150,20 @@ class TestGetAzureResponse(unittest.TestCase): _, kwargs = mock_open.call_args self.assertEqual(kwargs["timeout"], 42) + def test_client_id_is_url_encoded(self): + """Ensure special characters in client_id are percent-encoded.""" + body = json.dumps({"access_token": "tok", "expires_in": "3600"}) + with _mock_urlopen(200, body) as mock_open: + self._call(client_id="id with spaces&special=chars") + + url = mock_open.call_args[0][0].full_url + # '&' and '=' must be percent-encoded so they don't inject extra query params + self.assertIn("client_id=id%20with%20spaces%26special%3Dchars", url) + # The encoded client_id should not introduce a raw '&' + # Count params: api-version, resource, client_id — exactly 3 + query_string = url.split("?", 1)[1] + self.assertEqual(query_string.count("&"), 2) + if __name__ == "__main__": unittest.main() From 552b7bf47bbe6cf4a9532262e7234bea98f25402 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Wed, 13 May 2026 12:20:15 -0400 Subject: [PATCH 4/4] =?UTF-8?q?PYTHON-5631=20-=20test=5Fdirect=5Fclient=5F?= =?UTF-8?q?maintains=5Fpool=5Fto=5Farbiter=20waits=20inst=E2=80=A6=20(#279?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/asynchronous/test_client.py | 4 ++-- test/test_client.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/asynchronous/test_client.py b/test/asynchronous/test_client.py index ca150ca6d..dea1161af 100644 --- a/test/asynchronous/test_client.py +++ b/test/asynchronous/test_client.py @@ -2711,11 +2711,11 @@ class TestClientPool(AsyncMockClientTest): await async_wait_until(lambda: len(c.nodes) == 1, "connect") self.assertEqual(await c.address, ("c", 3)) - # Assert that we create 1 pooled connection. + # Wait for the pooled connection to be registered await listener.async_wait_for_event(monitoring.ConnectionReadyEvent, 1) self.assertEqual(listener.event_count(monitoring.ConnectionCreatedEvent), 1) arbiter = c._topology.get_server_by_address(("c", 3)) - self.assertEqual(len(arbiter.pool.conns), 1) + await async_wait_until(lambda: len(arbiter.pool.conns) == 1, "create 1 pooled connection") # Arbiter pool is marked ready. self.assertEqual(listener.event_count(monitoring.PoolReadyEvent), 1) diff --git a/test/test_client.py b/test/test_client.py index 75d585fda..d2d93c6ba 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -2666,11 +2666,11 @@ class TestClientPool(MockClientTest): wait_until(lambda: len(c.nodes) == 1, "connect") self.assertEqual(c.address, ("c", 3)) - # Assert that we create 1 pooled connection. + # Wait for the pooled connection to be registered listener.wait_for_event(monitoring.ConnectionReadyEvent, 1) self.assertEqual(listener.event_count(monitoring.ConnectionCreatedEvent), 1) arbiter = c._topology.get_server_by_address(("c", 3)) - self.assertEqual(len(arbiter.pool.conns), 1) + wait_until(lambda: len(arbiter.pool.conns) == 1, "create 1 pooled connection") # Arbiter pool is marked ready. self.assertEqual(listener.event_count(monitoring.PoolReadyEvent), 1)