diff --git a/changelog.d/20251029_161954_severine.bonnechere_use_http_adapter_for_concurrency.md b/changelog.d/20251029_161954_severine.bonnechere_use_http_adapter_for_concurrency.md new file mode 100644 index 0000000000..31ab931950 --- /dev/null +++ b/changelog.d/20251029_161954_severine.bonnechere_use_http_adapter_for_concurrency.md @@ -0,0 +1,3 @@ +### Added + +- A HTTPAdapter with wider parameters has been setup to better address scanning multiple files at the same time. diff --git a/ggshield/core/client.py b/ggshield/core/client.py index 01d9558635..efb84da49b 100644 --- a/ggshield/core/client.py +++ b/ggshield/core/client.py @@ -7,6 +7,7 @@ from pygitguardian import GGClient, GGClientCallbacks from pygitguardian.models import APITokensResponse, Detail, TokenScope from requests import Session +from requests.adapters import HTTPAdapter from . import ui from .config import Config @@ -101,6 +102,12 @@ def create_session(allow_self_signed: bool = False) -> Session: ) urllib3.disable_warnings() session.verify = False + # Mount HTTPAdapter with larger pool sizes for better concurrency + adapter = HTTPAdapter( + pool_maxsize=100, # default 10 + ) + session.mount("http://", adapter) + session.mount("https://", adapter) return session diff --git a/tests/unit/core/test_client.py b/tests/unit/core/test_client.py index 32054d4033..f3e6aa6737 100644 --- a/tests/unit/core/test_client.py +++ b/tests/unit/core/test_client.py @@ -9,7 +9,11 @@ from pygitguardian import GGClient from pygitguardian.models import APITokensResponse, Detail, TokenScope -from ggshield.core.client import check_client_api_key, create_client_from_config +from ggshield.core.client import ( + check_client_api_key, + create_client_from_config, + create_session, +) from ggshield.core.config import Config from ggshield.core.errors import ( APIKeyCheckError, @@ -239,3 +243,37 @@ def test_retrieve_client_unknown_custom_dashboard_url(isolated_fs: FakeFilesyste config = Config() config.cmdline_instance_name = "https://example.com" create_client_from_config(config) + + +def test_create_session_pool_configuration(): + """ + GIVEN create_session is called + WHEN the session is created + THEN the HTTPAdapter has the correct pool configuration + """ + session = create_session() + + adapter = session.get_adapter("https://example.com") + + # Verify pool configuration by checking the init parameters + assert getattr(adapter, "_pool_maxsize", None) == 100 + + +@pytest.mark.parametrize("allow_self_signed", [True, False]) +def test_create_session_with_self_signed_option(allow_self_signed: bool): + """ + GIVEN create_session is called with allow_self_signed parameter + WHEN the session is created + THEN HTTPAdapter is mounted regardless of allow_self_signed value + AND verify is set correctly + """ + session = create_session(allow_self_signed=allow_self_signed) + + # Verify adapters are mounted + assert "https://" in session.adapters + + # Verify SSL verification setting + if allow_self_signed: + assert session.verify is False + else: + assert session.verify is True