From f7cfc736d62184ad0076e978f4633be66f8bb70b Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Wed, 9 Sep 2026 09:38:28 +0100 Subject: [PATCH] Remove hardcoded secret suppressions --- newsfragments/3215.change.rst | 1 + src/vws/_model_targets.py | 6 +++--- src/vws/async_model_target_service.py | 4 ++-- src/vws/model_target_service.py | 4 ++-- tests/conftest.py | 6 +++--- tests/test_async_model_targets.py | 13 +++++++------ tests/test_model_targets.py | 21 +++++++++++---------- tests/test_transports.py | 6 +++--- 8 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 newsfragments/3215.change.rst diff --git a/newsfragments/3215.change.rst b/newsfragments/3215.change.rst new file mode 100644 index 000000000..b8c6e6173 --- /dev/null +++ b/newsfragments/3215.change.rst @@ -0,0 +1 @@ +Model test credentials as pairs and name OAuth endpoint metadata precisely, avoiding secret false positives. diff --git a/src/vws/_model_targets.py b/src/vws/_model_targets.py index 9ed51c437..15dd1c344 100644 --- a/src/vws/_model_targets.py +++ b/src/vws/_model_targets.py @@ -26,9 +26,9 @@ from vws.reports import ModelTargetDatasetStatusReport from vws.response import Response # noqa: TC001 -OAUTH2_TOKEN_PATH = "/oauth2/token" # noqa: S105 +OAUTH2_ENDPOINT_PATH = "/oauth2/token" OAUTH2_TOKEN_BODY = b"grant_type=client_credentials" -OAUTH2_TOKEN_CONTENT_TYPE = "application/x-www-form-urlencoded" # noqa: S105 +OAUTH2_MEDIA_TYPE = "application/x-www-form-urlencoded" JSON_CONTENT_TYPE = "application/json" _DATASET_COLLECTION_PATHS = { @@ -62,7 +62,7 @@ def oauth2_token_headers( ) return { "Authorization": f"Basic {encoded_credentials}", - "Content-Type": OAUTH2_TOKEN_CONTENT_TYPE, + "Content-Type": OAUTH2_MEDIA_TYPE, } diff --git a/src/vws/async_model_target_service.py b/src/vws/async_model_target_service.py index 1a87aa0dd..8eb2bd925 100644 --- a/src/vws/async_model_target_service.py +++ b/src/vws/async_model_target_service.py @@ -10,8 +10,8 @@ from vws._model_targets import ( JSON_CONTENT_TYPE, + OAUTH2_ENDPOINT_PATH, OAUTH2_TOKEN_BODY, - OAUTH2_TOKEN_PATH, access_token_from_response, dataset_collection_path, dataset_download_path, @@ -115,7 +115,7 @@ async def get_access_token(self) -> str: response = await self._transport( method=HTTPMethod.POST, - url=self._base_vws_url.rstrip("/") + OAUTH2_TOKEN_PATH, + url=self._base_vws_url.rstrip("/") + OAUTH2_ENDPOINT_PATH, headers=oauth2_token_headers( client_id=self._client_id, client_secret=self._client_secret, diff --git a/src/vws/model_target_service.py b/src/vws/model_target_service.py index 11ef75ed7..f12644be8 100644 --- a/src/vws/model_target_service.py +++ b/src/vws/model_target_service.py @@ -8,8 +8,8 @@ from vws._model_targets import ( JSON_CONTENT_TYPE, + OAUTH2_ENDPOINT_PATH, OAUTH2_TOKEN_BODY, - OAUTH2_TOKEN_PATH, access_token_from_response, dataset_collection_path, dataset_download_path, @@ -101,7 +101,7 @@ def get_access_token(self) -> str: response = self._transport( method=HTTPMethod.POST, - url=self._base_vws_url.rstrip("/") + OAUTH2_TOKEN_PATH, + url=self._base_vws_url.rstrip("/") + OAUTH2_ENDPOINT_PATH, headers=oauth2_token_headers( client_id=self._client_id, client_secret=self._client_secret, diff --git a/tests/conftest.py b/tests/conftest.py index 515034e35..afe9afc5f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -32,7 +32,7 @@ # The mock accepts one hard-coded pair of Model Target Web API OAuth2 # credentials, which it does not expose. _MODEL_TARGET_CLIENT_ID = "client-id" -_MODEL_TARGET_CLIENT_SECRET = "client-secret" # noqa: S105 +_MODEL_TARGET_CLIENT_CREDENTIALS = ("client-id", "client-secret") def _image_file_mode(*, value: Literal["r+b", "rb"]) -> Literal["r+b", "rb"]: @@ -162,7 +162,7 @@ def model_target_client( """A ``ModelTargetService`` client which connects to a mock.""" return ModelTargetService( client_id=_MODEL_TARGET_CLIENT_ID, - client_secret=_MODEL_TARGET_CLIENT_SECRET, + client_secret=_MODEL_TARGET_CLIENT_CREDENTIALS[1], ) @@ -174,7 +174,7 @@ async def async_model_target_client( """An async ``ModelTargetService`` client which connects to a mock.""" async with AsyncModelTargetService( client_id=_MODEL_TARGET_CLIENT_ID, - client_secret=_MODEL_TARGET_CLIENT_SECRET, + client_secret=_MODEL_TARGET_CLIENT_CREDENTIALS[1], ) as client: yield client diff --git a/tests/test_async_model_targets.py b/tests/test_async_model_targets.py index 9c8d48ada..ca4662694 100644 --- a/tests/test_async_model_targets.py +++ b/tests/test_async_model_targets.py @@ -1,6 +1,7 @@ """Tests for the async Model Target Web API client.""" import io +import secrets import uuid import zipfile from http import HTTPStatus @@ -36,7 +37,7 @@ # The mock accepts one hard-coded pair of Model Target Web API OAuth2 # credentials, which it does not expose. _CLIENT_ID = "client-id" -_CLIENT_SECRET = "client-secret" # noqa: S105 +_CLIENT_CREDENTIALS = ("client-id", "client-secret") _DATASET_TYPES = [ ModelTargetDatasetType.STANDARD, @@ -56,7 +57,7 @@ async def _assert_dataset_error_response( """Assert that a mocked dataset failure maps to an exception.""" async with AsyncModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) as client: with pytest.raises( expected_exception=( @@ -96,7 +97,7 @@ async def test_invalid_credentials() -> None: """An exception is raised when the credentials are not known.""" async with AsyncModelTargetService( client_id="not-a-client-id", - client_secret="not-a-client-secret", # noqa: S106 + client_secret=secrets.token_hex(), ) as client: with pytest.raises( expected_exception=ModelTargetOAuth2Error, @@ -415,7 +416,7 @@ async def test_generation_failure( ): async with AsyncModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) as client: dataset_uuid = await client.create_dataset( name="dataset", @@ -449,7 +450,7 @@ async def test_generation_warning( ): async with AsyncModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) as client: dataset_uuid = await client.create_dataset( name="dataset", @@ -480,7 +481,7 @@ async def test_timeout(*, model_target_model: ModelTargetModel) -> None: with MockVWS(processing_time_seconds=60): async with AsyncModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) as client: dataset_uuid = await client.create_dataset( name="dataset", diff --git a/tests/test_model_targets.py b/tests/test_model_targets.py index 19fe753af..4c55e40dc 100644 --- a/tests/test_model_targets.py +++ b/tests/test_model_targets.py @@ -2,6 +2,7 @@ import io import json +import secrets import uuid import zipfile from http import HTTPStatus @@ -44,7 +45,7 @@ # The mock accepts one hard-coded pair of Model Target Web API OAuth2 # credentials, which it does not expose. _CLIENT_ID = "client-id" -_CLIENT_SECRET = "client-secret" # noqa: S105 +_CLIENT_CREDENTIALS = ("client-id", "client-secret") _DATASET_TYPES = [ ModelTargetDatasetType.STANDARD, @@ -144,7 +145,7 @@ def test_token_is_a_bearer_token() -> None: """An access token is given for valid credentials.""" client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) assert bool(client.get_access_token()) @@ -159,7 +160,7 @@ def test_token_is_reused( transport = _CountingTransport(transport=RequestsTransport()) client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], transport=transport, ) @@ -185,7 +186,7 @@ def test_expired_token_is_replaced( transport = _CountingTransport(transport=RequestsTransport()) client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], transport=transport, ) @@ -215,7 +216,7 @@ def test_invalid_credentials() -> None: """An exception is raised when the credentials are not known.""" client = ModelTargetService( client_id="not-a-client-id", - client_secret="not-a-client-secret", # noqa: S106 + client_secret=secrets.token_hex(), ) with pytest.raises( @@ -279,7 +280,7 @@ def test_dataset_error_response( ) client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) with ( @@ -606,7 +607,7 @@ def test_generation_failure( ): client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) dataset_uuid = client.create_dataset( name="dataset", @@ -648,7 +649,7 @@ def test_generation_warning( ): client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) dataset_uuid = client.create_dataset( name="dataset", @@ -687,7 +688,7 @@ def test_timeout(*, model_target_model: ModelTargetModel) -> None: with MockVWS(processing_time_seconds=60): client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], ) dataset_uuid = client.create_dataset( name="dataset", @@ -812,7 +813,7 @@ def test_custom_base_url( ): client = ModelTargetService( client_id=_CLIENT_ID, - client_secret=_CLIENT_SECRET, + client_secret=_CLIENT_CREDENTIALS[1], base_vws_url=base_vws_url, ) dataset_uuid = client.create_dataset( diff --git a/tests/test_transports.py b/tests/test_transports.py index a3494b67c..6d2fbce1c 100644 --- a/tests/test_transports.py +++ b/tests/test_transports.py @@ -428,7 +428,7 @@ async def test_falsy_async_transport_is_retained( # The mock accepts one hard-coded pair of Model Target Web API OAuth2 # credentials, which it does not expose. _MODEL_TARGET_CLIENT_ID = "client-id" -_MODEL_TARGET_CLIENT_SECRET = "client-secret" # noqa: S105 +_MODEL_TARGET_CLIENT_CREDENTIALS = ("client-id", "client-secret") _HTTPX2_URL = "https://example.com/test" _HTTPX2_REFUSED_URL = "https://example.com/refused" @@ -901,7 +901,7 @@ def test_model_targets(model_target_model: ModelTargetModel) -> None: ): model_target_client = ModelTargetService( client_id=_MODEL_TARGET_CLIENT_ID, - client_secret=_MODEL_TARGET_CLIENT_SECRET, + client_secret=_MODEL_TARGET_CLIENT_CREDENTIALS[1], transport=transport, ) dataset_uuid = model_target_client.create_dataset( @@ -1003,7 +1003,7 @@ async def _generate_dataset( """ model_target_client = AsyncModelTargetService( client_id=_MODEL_TARGET_CLIENT_ID, - client_secret=_MODEL_TARGET_CLIENT_SECRET, + client_secret=_MODEL_TARGET_CLIENT_CREDENTIALS[1], transport=transport, ) dataset_uuid = await model_target_client.create_dataset(