Преглед изворни кода

[cve] Upgrade setuptools to 80.9.0 for Python 3.9+ to fix CVE-2025-47273 (#4294)

Upgrade setuptools to version 80.9.0 for Python 3.9 and above to mitigate
CVE-2025-47273, while maintaining version 70.0.0 for Python 3.8 compatibility.

Changes:
- Move setuptools from base requirements to Python version-specific requirements
- Python 3.8 (default): Keep setuptools==70.0.0 (no change)
- Python 3.9: Upgrade to setuptools==80.9.0 (security fix)
- Python 3.11: Upgrade to setuptools==80.9.0 (security fix)
- Update unit tests to reflect version-specific setuptools configuration

Rationale:
PyPI requires setuptools 80.9.0 to have Python >=3.9, so we use a
version-specific approach in generate_requirements.py. This ensures
backward compatibility for Python 3.8 users while providing security
fixes for Python 3.9+ users.

Implementation:
Modified desktop/core/generate_requirements.py to include setuptools
in architecture-specific requirements (x86_64 and aarch64) rather than
in the base requirements list. This allows different Python versions
to use appropriate setuptools versions based on their constraints.

Testing:
- Updated generate_requirements_test.py to use correct setuptools versions
- Verified requirements generation for all supported Python versions
- Confirmed no breaking changes to existing functionality

Impact:
- Python 3.8 users: No change and users need to upgrade their setup for CVE mitigation
- Python 3.9+ users: Get security-patched setuptools 80.9.0
- No impact on build process or application functionality

Fixes: CVE-2025-47273
Harsh Gupta пре 1 месец
родитељ
комит
3829eff9a1

+ 0 - 1
desktop/core/base_requirements.txt

@@ -1,4 +1,3 @@
-setuptools==70.0.0
 apache-ranger==0.0.3
 requests-gssapi==1.2.3
 asn1crypto==0.24.0

+ 6 - 1
desktop/core/generate_requirements.py

@@ -110,7 +110,6 @@ class RequirementsGenerator:
       "requests-kerberos==0.14.0",
       "rsa==4.7.2",
       "ruff==0.11.10",
-      "setuptools==70.0.0",
       "six==1.16.0",
       "slack-sdk==3.31.0",
       "SQLAlchemy==1.3.8",
@@ -130,6 +129,7 @@ class RequirementsGenerator:
         "numpy==1.24.4",
         "pandas==2.0.3",
         "sasl==0.3.1",
+        "setuptools==70.0.0",
       ],
       "3.9": [
         "decorator==5.1.1",
@@ -139,6 +139,7 @@ class RequirementsGenerator:
         "pandas==2.0.3",
         "pyopenssl==22.1.0",
         "sasl==0.3.1",
+        "setuptools==80.9.0",
       ],
       "3.11": [
         "async-timeout==5.0.1",
@@ -148,6 +149,7 @@ class RequirementsGenerator:
         "numpy==1.24.4",
         "pandas==2.0.3",
         "pure-sasl==0.6.2",
+        "setuptools==80.9.0",
       ],
     }
 
@@ -158,6 +160,7 @@ class RequirementsGenerator:
         "Markdown==3.1",
         "numpy==1.24.4",
         "pandas==2.0.3",
+        "setuptools==70.0.0",
       ],
       "3.9": [
         "decorator==5.1.1",
@@ -167,6 +170,7 @@ class RequirementsGenerator:
         "pandas==2.0.3",
         "pyopenssl==22.1.0",
         "sasl==0.3.1",
+        "setuptools==80.9.0",
       ],
       "3.11": [
         "async-timeout==5.0.1",
@@ -176,6 +180,7 @@ class RequirementsGenerator:
         "numpy==1.24.4",
         "pandas==2.0.3",
         "pure-sasl==0.6.2",
+        "setuptools==80.9.0",
       ],
     }
     self.arch_requirements_map = {

+ 8 - 6
desktop/core/generate_requirements_test.py

@@ -113,9 +113,11 @@ class TestRequirementsGenerator:
       generator = RequirementsGenerator()
       generator.arch = "x86_64"
       generator.python_version_string = "3.9"
-      generator.requirements = ["setuptools==70.0.0", "Django==4.1.13"]
+      generator.requirements = ["Django==4.1.13"]
       generator.local_requirements = []
-      generator.arch_requirements_map = {"x86_64": {"default": ["cryptography==42.0.8"], "3.9": ["Markdown==3.8", "numpy==1.24.4"]}}
+      generator.arch_requirements_map = {
+        "x86_64": {"default": ["cryptography==42.0.8"], "3.9": ["Markdown==3.8", "numpy==1.24.4", "setuptools==80.9.0"]}
+      }
 
       # Mock copy_local_requirements for test isolation
       generator.copy_local_requirements = mock.MagicMock(return_value=[])
@@ -126,7 +128,7 @@ class TestRequirementsGenerator:
       mock_open.assert_called_once_with(f"{self.temp_dir}/requirements-x86_64-3.9.txt", "w")
 
       # Verify correct requirements were written
-      expected_requirements = "\n".join(["setuptools==70.0.0", "Django==4.1.13", "Markdown==3.8", "numpy==1.24.4"])
+      expected_requirements = "\n".join(["Django==4.1.13", "Markdown==3.8", "numpy==1.24.4", "setuptools==80.9.0"])
       mock_open().write.assert_called_once_with(expected_requirements)
 
   @mock.patch("generate_requirements.this_dir")
@@ -176,9 +178,9 @@ class TestRequirementsGenerator:
       generator = RequirementsGenerator()
       generator.arch = "x86_64"
       generator.python_version_string = "3.9"
-      generator.requirements = ["setuptools==70.0.0"]
+      generator.requirements = []
       generator.local_requirements = ["boto-2.49.0", "django-axes-5.13.0"]
-      generator.arch_requirements_map = {"x86_64": {"default": [], "3.9": ["Markdown==3.8"]}}
+      generator.arch_requirements_map = {"x86_64": {"default": [], "3.9": ["Markdown==3.8", "setuptools==80.9.0"]}}
 
       # Mock copy_local_requirements to return file paths
       local_reqs = [f"file://{self.temp_dir}/3.9/boto-2.49.0", f"file://{self.temp_dir}/3.9/django-axes-5.13.0"]
@@ -189,7 +191,7 @@ class TestRequirementsGenerator:
       mock_open.assert_called_once_with(f"{self.temp_dir}/requirements-x86_64-3.9.txt", "w")
 
       expected_requirements = "\n".join(
-        ["setuptools==70.0.0", "Markdown==3.8", f"file://{self.temp_dir}/3.9/boto-2.49.0", f"file://{self.temp_dir}/3.9/django-axes-5.13.0"]
+        ["Markdown==3.8", "setuptools==80.9.0", f"file://{self.temp_dir}/3.9/boto-2.49.0", f"file://{self.temp_dir}/3.9/django-axes-5.13.0"]
       )
 
       mock_open().write.assert_called_once_with(expected_requirements)