From 91b83b5c8f4d29bb035d13699f7fb3771f2cd63c Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 26 Oct 2026 11:59:14 +0530 Subject: [PATCH 1/3] Fix: use approved placeholder Replace hardcoded passwords and secrets in tests with env/cred-helper values or per-run generated values, and drop the deepcode ignore suppression comments. Clears the Snyk Code NoHardcodedPasswords and HardcodedNonCryptoSecret findings. Co-Authored-By: Claude Sonnet 5.5 --- tests/api/users/test_api.py | 12 ++++-------- tests/integration/api/test_01_user.py | 11 +++++++---- tests/mock/users/test_mock.py | 12 ++++-------- tests/unit/contentstack/test_totp_login.py | 7 ++----- tests/unit/test_oauth_handler.py | 4 ++-- 5 files changed, 19 insertions(+), 27 deletions(-) diff --git a/tests/api/users/test_api.py b/tests/api/users/test_api.py index a25d78f..4b580fa 100644 --- a/tests/api/users/test_api.py +++ b/tests/api/users/test_api.py @@ -44,10 +44,8 @@ def test_active_user(self): "user": { "first_name": "your_first_name", "last_name": "your_last_name", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password": "your_password", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password_confirmation": "confirm_your_password" + "password": password, + "password_confirmation": password } } response = self.client.user().activate(activation_token, act_data) @@ -80,10 +78,8 @@ def test_reset_password(self): act_data = { "user": { "reset_password_token": "abcdefghijklmnop1234567890", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password": "Simple@123", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password_confirmation": "Simple@123" + "password": password, + "password_confirmation": password } } response = self.client.user().reset_password(act_data) diff --git a/tests/integration/api/test_01_user.py b/tests/integration/api/test_01_user.py index 05291f1..c82876f 100644 --- a/tests/integration/api/test_01_user.py +++ b/tests/integration/api/test_01_user.py @@ -1,11 +1,16 @@ """User API tests — profile fetch and update.""" +import os + import pytest from framework import helpers as h pytestmark = pytest.mark.order(1) +# Exercised only with bogus tokens; value comes from the environment, no fallback. +TEST_PASSWORD = os.environ.get("TEST_USER_PASSWORD") + class TestUser: def test_fetch(self, ctx): @@ -26,14 +31,12 @@ class TestUserAuthOps: """Account auth endpoints exercised safely (bogus tokens / non-real email).""" def test_activate_bogus_token(self, ctx): - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - resp = ctx.client.user().activate("bogus_activation_token", {"user": {"password": "Test@12345"}}) + resp = ctx.client.user().activate("bogus_activation_token", {"user": {"password": TEST_PASSWORD}}) h.assert_status(resp, 400, 404, 422) def test_reset_password_bogus_token(self, ctx): resp = ctx.client.user().reset_password( - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - {"user": {"reset_password_token": "bogus", "password": "Test@12345", "password_confirmation": "Test@12345"}} + {"user": {"reset_password_token": "bogus", "password": TEST_PASSWORD, "password_confirmation": TEST_PASSWORD}} ) h.assert_status(resp, 400, 404, 422) diff --git a/tests/mock/users/test_mock.py b/tests/mock/users/test_mock.py index 2507d71..0b833a9 100644 --- a/tests/mock/users/test_mock.py +++ b/tests/mock/users/test_mock.py @@ -38,10 +38,8 @@ def test_mock_active_user(self): "user": { "first_name": "your_first_name", "last_name": "your_last_name", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password": "your_password", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password_confirmation": "confirm_your_password" + "password": password, + "password_confirmation": password } } @@ -81,10 +79,8 @@ def test_reset_password(self): act_data = { "user": { "reset_password_token": "abcdefghijklmnop1234567890", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password": "Simple@123", - # deepcode ignore NoHardcodedPasswords: test fixture value, not a real secret - "password_confirmation": "Simple@123" + "password": password, + "password_confirmation": password } } response = self.client.user().reset_password(act_data).json() diff --git a/tests/unit/contentstack/test_totp_login.py b/tests/unit/contentstack/test_totp_login.py index 3f6a049..4a84dbe 100644 --- a/tests/unit/contentstack/test_totp_login.py +++ b/tests/unit/contentstack/test_totp_login.py @@ -1,3 +1,4 @@ +import base64 import unittest import os import sys @@ -18,8 +19,7 @@ def setUp(self): self.client = Client() self.test_email = "test@example.com" self.test_password = "test_password" - # deepcode ignore HardcodedNonCryptoSecret: test fixture value, not a real secret - self.test_secret = "JBSWY3DPEHPK3PXP" # Standard test secret for TOTP + self.test_secret = base64.b32encode(os.urandom(10)).decode() # Valid base32 TOTP secret generated per test run self.test_tfa_token = "123456" def tearDown(self): @@ -38,9 +38,7 @@ def test_login_method_signature_with_totp(self): # Test that the method accepts TOTP parameters without error try: client.login(self.test_email, self.test_password, tfa_token=self.test_tfa_token) - # deepcode ignore HardcodedNonCryptoSecret: test fixture value, not a real secret client.login(self.test_email, self.test_password, mfa_secret=self.test_secret) - # deepcode ignore HardcodedNonCryptoSecret: test fixture value, not a real secret client.login(self.test_email, self.test_password, tfa_token=self.test_tfa_token, mfa_secret=self.test_secret) except Exception as e: self.fail(f"Login method should accept TOTP parameters without error: {e}") @@ -74,7 +72,6 @@ def test_login_with_mfa_secret_generates_totp(self): result = self.client.login( self.test_email, self.test_password, - # deepcode ignore HardcodedNonCryptoSecret: test fixture value, not a real secret mfa_secret=self.test_secret ) diff --git a/tests/unit/test_oauth_handler.py b/tests/unit/test_oauth_handler.py index 1ff20e9..c14507a 100644 --- a/tests/unit/test_oauth_handler.py +++ b/tests/unit/test_oauth_handler.py @@ -5,6 +5,7 @@ import json import time import unittest +import uuid from unittest.mock import Mock, patch, MagicMock import requests @@ -19,7 +20,7 @@ def setUp(self): self.app_id = "test-app-id" self.client_id = "test-client-id" self.redirect_uri = "http://localhost:3000/callback" - self.client_secret = "test-client-secret" + self.client_secret = uuid.uuid4().hex # Generated per test run, not a real secret self.scope = ["read", "write"] self.api_client = Mock() self.api_client.headers = {} @@ -31,7 +32,6 @@ def setUp(self): app_id=self.app_id, client_id=self.client_id, redirect_uri=self.redirect_uri, - # deepcode ignore HardcodedNonCryptoSecret: test fixture value, not a real secret client_secret=self.client_secret, scope=self.scope, api_client=self.api_client From ea2499a3ea47e745be30cd5e925d6d6d8277b36c Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 26 Oct 2026 12:25:19 +0530 Subject: [PATCH 2/3] Fix: bump urllib3 floor to 2.8.0 urllib3 2.7.0 is affected by improper certificate validation, resource allocation without limits and an infinite loop; 2.8.0 fixes all three. Raise the minimum so the vulnerable version is no longer installable. Co-Authored-By: Claude Sonnet 5.5 --- requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e9b1a36..fc2ba15 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ python-dotenv>=1.2.2 # <82: pkg_resources (used by coverage-badge and similar tools) was removed in setuptools 82+ setuptools>=83.0.0 requests>=2.33.0,<3.0.0 -urllib3>=2.7.0,<3.0.0 +urllib3>=2.8.0,<3.0.0 requests-toolbelt>=1.0.0,<2.0.0 pyotp==2.9.0 packaging>=24.0 diff --git a/setup.py b/setup.py index 53a99b3..fdfaccf 100644 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ def get_author_email(package): install_requires=[ "requests >= 2.5.4", "requests-toolbelt >= 0.3.1", - "urllib3 >= 2.7.0,<3.0.0", + "urllib3 >= 2.8.0,<3.0.0", ], extras_require={ "dev": ["pytest>=7.0", "twine>=4.0.2", "packaging>=24.0", "dotenv>=0.0.5", "pylint>=2.0.0"], From 7107cde9b318466943cfbecfd3b505bc0993b2e9 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Mon, 26 Oct 2026 12:29:34 +0530 Subject: [PATCH 3/3] chore: bump version to 1.11.3 Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 8 ++++++++ contentstack_management/__init__.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9539610..b9d6462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # CHANGELOG ## Content Management SDK For Python +--- +## v1.11.3 + +#### Date: 26 October 2026 + +- Bumped `urllib3` minimum version from `>=2.7.0` to `>=2.8.0` in `requirements.txt` and `setup.py` to resolve Snyk findings: improper certificate validation, allocation of resources without limits or throttling, and an infinite loop (DX-27815, DX-27816, DX-27817). +- Tests: replaced hardcoded passwords and secrets with environment-backed or runtime-generated values and removed `# deepcode ignore` suppression comments, resolving Snyk Code findings (DX-22180 to DX-22195). No change to the published package. + --- ## v1.11.2 diff --git a/contentstack_management/__init__.py b/contentstack_management/__init__.py index e038906..9cb9f32 100644 --- a/contentstack_management/__init__.py +++ b/contentstack_management/__init__.py @@ -102,7 +102,7 @@ def get_contentstack_endpoint(region='us', service='', omit_https=False): __author__ = 'dev-ex' __status__ = 'debug' __region__ = 'na' -__version__ = '1.11.2' +__version__ = '1.11.3' __host__ = 'api.contentstack.io' __protocol__ = 'https://' __api_version__ = 'v3'