From 77dc6f7cc8ffc4b15ef1248f87d3d9e2ad8fd878 Mon Sep 17 00:00:00 2001 From: "Ch.-David Blot" Date: Thu, 28 May 2026 15:00:36 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=9B=20fix:=20fix=20proxy=20setting?= =?UTF-8?q?s=20from=20environement=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix for authentication override was making requeste ingore PROXY_* environement variables as well --- osc_sdk_python/authentication.py | 16 ++++++++++++++++ osc_sdk_python/call.py | 3 +-- osc_sdk_python/requester.py | 11 ++--------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/osc_sdk_python/authentication.py b/osc_sdk_python/authentication.py index 23fd8ac..e75d561 100644 --- a/osc_sdk_python/authentication.py +++ b/osc_sdk_python/authentication.py @@ -1,7 +1,9 @@ +from requests.structures import CaseInsensitiveDict import datetime import hashlib import hmac import base64 +import requests from .version import get_version from .credentials import Profile @@ -174,3 +176,17 @@ def get_basic_auth_header(self): "X-Osc-Date": date_iso, "Authorization": "Basic " + b64_creds, } + + def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + if self.is_basic_auth_configured(): + auth_headers = self.get_basic_auth_header() + else: + auth_headers = self.forge_headers_signed(request.path_url, request.body or "") + + if request.headers is None: + request.headers = CaseInsensitiveDict() + + for head in auth_headers: + request.headers[head] = auth_headers[head] + + return request diff --git a/osc_sdk_python/call.py b/osc_sdk_python/call.py index 123c75a..85ff752 100644 --- a/osc_sdk_python/call.py +++ b/osc_sdk_python/call.py @@ -21,7 +21,6 @@ def __init__(self, logger=None, limiter=None, **kwargs): self.limiter: RateLimiter | None = limiter self.retry_kwargs = {} self.session = Session() - self.session.trust_env = False kwargs = self.update_limiter(**kwargs) kwargs = self.update_retry(**kwargs) @@ -88,7 +87,7 @@ def api(self, action, service="api", **data): self.logger.do_log( "uri: " + uri + "\npayload:\n" + json.dumps(data, indent=2) ) - return requester.send(uri, json.dumps(data)) + return requester.send(json.dumps(data)) except Exception as err: raise err diff --git a/osc_sdk_python/requester.py b/osc_sdk_python/requester.py index 3e89887..882c993 100644 --- a/osc_sdk_python/requester.py +++ b/osc_sdk_python/requester.py @@ -1,6 +1,5 @@ from .retry import Retry - class Requester: def __init__(self, session, auth, endpoint, **kwargs): self.session = session @@ -8,13 +7,7 @@ def __init__(self, session, auth, endpoint, **kwargs): self.endpoint = endpoint self.request_kwargs = kwargs - def send(self, uri, payload): - headers = None - if self.auth.is_basic_auth_configured(): - headers = self.auth.get_basic_auth_header() - else: - headers = self.auth.forge_headers_signed(uri, payload) - + def send(self, payload): if self.auth.x509_client_cert is not None: cert_file = self.auth.x509_client_cert else: @@ -22,7 +15,7 @@ def send(self, uri, payload): retry_kwargs = self.request_kwargs.copy() retry_kwargs.update( - {"data": payload, "headers": headers, "verify": True, "cert": cert_file} + {"data": payload, "auth": self.auth, "verify": True, "cert": cert_file} ) response = Retry(self.session, "post", self.endpoint, **retry_kwargs) From 1286ea29abcff212f7f0d89257f52bc73b56f744 Mon Sep 17 00:00:00 2001 From: "Ch.-David Blot" Date: Thu, 28 May 2026 15:31:53 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=85=20test:=20add=20proxy=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_proxy.py | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/test_proxy.py diff --git a/tests/test_proxy.py b/tests/test_proxy.py new file mode 100644 index 0000000..9559620 --- /dev/null +++ b/tests/test_proxy.py @@ -0,0 +1,78 @@ +import os +import unittest +import unittest.mock + +from osc_sdk_python.call import Call +from osc_sdk_python.credentials import Profile + + +class TestProxySupport(unittest.TestCase): + def test_proxy_env_passed_to_session(self): + with unittest.mock.patch.object( + Profile, "from_standard_configuration" + ) as mock_from_std: + mock_from_std.return_value = Profile(region="eu-west-2", protocol="https") + + with unittest.mock.patch.dict( + os.environ, {"HTTPS_PROXY": "http://proxy.example.com:8080"} + ): + call = Call(access_key="fake-ak", secret_key="fake-sk") + + captured_proxies = [] + + class FakeAdapter: + def send(self, request, **kwargs): + captured_proxies.append(kwargs.get("proxies")) + import requests + + resp = requests.Response() + resp.status_code = 200 + resp._content = b'{"status": "ok"}' + resp.request = request + resp.url = request.url + return resp + + call.session.mount("https://", FakeAdapter()) + + result = call.api("ReadVms") + + self.assertEqual(len(captured_proxies), 1) + self.assertEqual( + captured_proxies[0], + {"https": "http://proxy.example.com:8080"}, + ) + self.assertEqual(result, {"status": "ok"}) + + def test_no_proxy_env_no_proxies_kwarg(self): + with unittest.mock.patch.object( + Profile, "from_standard_configuration" + ) as mock_from_std: + mock_from_std.return_value = Profile(region="eu-west-2", protocol="https") + + with unittest.mock.patch.dict(os.environ, {}, clear=True): + call = Call(access_key="fake-ak", secret_key="fake-sk") + + captured_proxies = [] + + class FakeAdapter: + def send(self, request, **kwargs): + captured_proxies.append(kwargs.get("proxies")) + import requests + + resp = requests.Response() + resp.status_code = 200 + resp._content = b'{"status": "ok"}' + resp.request = request + resp.url = request.url + return resp + + call.session.mount("https://", FakeAdapter()) + + call.api("ReadVms") + + self.assertEqual(len(captured_proxies), 1) + self.assertEqual(captured_proxies[0], {}) + + +if __name__ == "__main__": + unittest.main()