From a75398f3c23c0bc1318aec5f8cc1b4feed93a50d Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Tue, 3 Nov 2026 14:43:40 -0600 Subject: [PATCH 1/2] Identify Python SDK requests consistently Assisted-by: Codex:GPT-6 --- CHANGELOG.md | 7 ++++ README.rst | 2 +- socketdev/core/api.py | 4 +-- socketdev/user_agent.py | 4 +++ tests/unit/test_user_agent.py | 66 +++++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 socketdev/user_agent.py create mode 100644 tests/unit/test_user_agent.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 63642f5..4064898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +### Changed + +- Use `socket-sdk-python/` as the default User-Agent. Explicit caller + overrides continue to identify the calling application. + ## 3.6.2 ### Fixed: reject retired API credentials before use diff --git a/README.rst b/README.rst index 40be80b..7da3cb4 100644 --- a/README.rst +++ b/README.rst @@ -27,7 +27,7 @@ Initializing the module - **token (str)** - The Socket API Key for your Organization - **timeout (int)** - The number of seconds to wait before failing the connection - **allow_unverified (bool)** - Whether to skip SSL certificate verification (default: False). Set to True for testing with self-signed certificates. -- **user_agent (str, optional)** - Custom User-Agent string to use in API requests. If not provided, defaults to "SocketSDKPython/{version}" +- **user_agent (str, optional)** - Custom User-Agent string to use in API requests. If not provided, defaults to "socket-sdk-python/{version}". Applications such as the Socket CLI can override this with their own product name and version. Supported Functions ------------------- diff --git a/socketdev/core/api.py b/socketdev/core/api.py index adceae8..7c58c92 100644 --- a/socketdev/core/api.py +++ b/socketdev/core/api.py @@ -16,7 +16,7 @@ APIInsufficientPermissions, APIOrganizationNotAllowed, ) -from socketdev.version import __version__ +from socketdev.user_agent import USER_AGENT from requests.exceptions import Timeout, ConnectionError import time @@ -54,7 +54,7 @@ def do_request( raise APIKeyMissing if headers is None: - user_agent_string = self.user_agent if self.user_agent is not None else f"SocketSDKPython/{__version__}" + user_agent_string = self.user_agent if self.user_agent is not None else USER_AGENT headers = { "Authorization": f"Basic {self.encoded_key}", "User-Agent": user_agent_string, diff --git a/socketdev/user_agent.py b/socketdev/user_agent.py new file mode 100644 index 0000000..3328ecc --- /dev/null +++ b/socketdev/user_agent.py @@ -0,0 +1,4 @@ +from socketdev.version import __version__ + +USER_AGENT_NAME = "socket-sdk-python" +USER_AGENT = f"{USER_AGENT_NAME}/{__version__}" diff --git a/tests/unit/test_user_agent.py b/tests/unit/test_user_agent.py new file mode 100644 index 0000000..7dd3632 --- /dev/null +++ b/tests/unit/test_user_agent.py @@ -0,0 +1,66 @@ +import pytest +import requests + +from socketdev import socketdev +from socketdev.version import __version__ + + +@pytest.mark.parametrize("method", ["GET", "POST"]) +@pytest.mark.parametrize( + "user_agent", + [ + None, + "SocketPythonCLI/2.11.7", + "socket-python-cli/2.11.7", + "socket-basics/3.4.1", + "custom-client/1.0.0", + "", + ], +) +def test_prepared_requests_use_sdk_identity_or_explicit_caller( + monkeypatch, method, user_agent +): + captured = [] + + def send(session, request, **kwargs): + captured.append(request) + response = requests.Response() + response.status_code = 200 + response._content = b"{}" + return response + + monkeypatch.setattr(requests.sessions.Session, "send", send) + sdk = socketdev(token="synthetic-test-token", user_agent=user_agent) + files = [("manifest", ("package.json", b"{}"))] if method == "POST" else None + + sdk.api.do_request("organizations", method=method, files=files) + + assert len(captured) == 1 + expected = user_agent if user_agent is not None else f"socket-sdk-python/{__version__}" + assert captured[0].headers["User-Agent"] == expected + assert captured[0].headers["Authorization"].startswith("Basic ") + if files: + assert captured[0].headers["Content-Type"].startswith("multipart/form-data;") + + +def test_endpoint_wrappers_share_the_sdk_identity(monkeypatch): + captured = [] + + def send(session, request, **kwargs): + captured.append(request) + response = requests.Response() + response.status_code = 200 + response._content = b"{}" + return response + + monkeypatch.setattr(requests.sessions.Session, "send", send) + sdk = socketdev(token="synthetic-test-token") + + sdk.org.get() + sdk.basics.get_config("test-org") + + assert len(captured) == 2 + assert all( + request.headers["User-Agent"] == f"socket-sdk-python/{__version__}" + for request in captured + ) From f33d39c28016518baa83f37bec2ab460200406af Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:39:51 -0600 Subject: [PATCH 2/2] chore(release): prepare SDK 3.6.3 Set the package version and identify the User-Agent changelog entry as the 3.6.3 release. Assisted-by: Codex:GPT-6 --- CHANGELOG.md | 2 +- socketdev/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5628ba5..9e1fe3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 3.6.3 ### Changed diff --git a/socketdev/version.py b/socketdev/version.py index 4f82193..6a45bf5 100644 --- a/socketdev/version.py +++ b/socketdev/version.py @@ -1 +1 @@ -__version__ = "3.6.2" +__version__ = "3.6.3"