Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion contentstack_management/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
12 changes: 4 additions & 8 deletions tests/api/users/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
11 changes: 7 additions & 4 deletions tests/integration/api/test_01_user.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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)

Expand Down
12 changes: 4 additions & 8 deletions tests/mock/users/test_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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()
Expand Down
7 changes: 2 additions & 5 deletions tests/unit/contentstack/test_totp_login.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import base64
import unittest
import os
import sys
Expand All @@ -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):
Expand All @@ -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}")
Expand Down Expand Up @@ -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
)

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_oauth_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import json
import time
import unittest
import uuid
from unittest.mock import Mock, patch, MagicMock
import requests

Expand All @@ -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 = {}
Expand All @@ -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
Expand Down
Loading