diff --git a/openedx/tests/test_bug_36305_regression.py b/openedx/tests/test_bug_36305_regression.py new file mode 100644 index 000000000000..5e8beb133ead --- /dev/null +++ b/openedx/tests/test_bug_36305_regression.py @@ -0,0 +1,57 @@ +""" +Regression test for bug #36305 — xmlsec / lxml version mismatch on open-release/sumac.master. + +The latest PyPI wheels for xmlsec and lxml link against a newer libxml2 than what ships +on Ubuntu 24.04 GitHub Actions runners, which raises a version-mismatch RuntimeError at +import time. The fix pins both packages in requirements/constraints.txt; this module is a +tripwire that ensures the pins stay in place on this branch. + +See: https://github.com/openedx/edx-platform/issues/36305 +See: https://github.com/openedx/edx-platform/issues/36695 +""" + +import os +import re +import unittest + + +REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +CONSTRAINTS_PATH = os.path.join(REPO_ROOT, "requirements", "constraints.txt") + + +def _read_constraints(): + """Return the contents of requirements/constraints.txt as a single string.""" + with open(CONSTRAINTS_PATH, encoding="utf-8") as handle: + return handle.read() + + +class TestBug36305Regression(unittest.TestCase): + """Ensure lxml and xmlsec stay pinned so CI does not pull a libxml2-incompatible wheel.""" + + def test_unit_bug_36305_regression_xmlsec_is_pinned(self): + """xmlsec must be pinned to a version compatible with the system libxml2.""" + contents = _read_constraints() + self.assertRegex( + contents, + r"^xmlsec==1\.3\.14\s*$", + msg="xmlsec must be pinned to 1.3.14 to avoid libxml2 mismatch (bug #36305).", + ) + + def test_unit_bug_36305_regression_lxml_is_pinned(self): + """lxml must be pinned to an exact version.""" + contents = _read_constraints() + match = re.search(r"^lxml==(\S+)\s*$", contents, flags=re.MULTILINE) + self.assertIsNotNone( + match, + msg="lxml must be pinned to an exact version to avoid libxml2 mismatch (bug #36305).", + ) + + def test_integration_bug_36305_regression_import_xmlsec_succeeds(self): + """Importing xmlsec must not raise a version-mismatch RuntimeError.""" + try: + import xmlsec # noqa: F401 pylint: disable=import-outside-toplevel,unused-import + except RuntimeError as exc: # pragma: no cover - only fires on broken wheel + self.fail( + "xmlsec import failed with RuntimeError (likely libxml2 version mismatch, " + "bug #36305): {err}".format(err=exc) + ) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 9a9207bd8eef..0bdb1a298f99 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -185,3 +185,15 @@ social-auth-app-django<=5.4.1 # # Date: 2024-10-14 # # The edx-enterprise is currently using edx-rest-api-client==5.7.1, which needs to be updated first. # edx-rest-api-client==5.7.1 + +# Date: 2025-05-09 +# lxml and xmlsec need to be constrained because the latest version builds against a newer +# version of libxml2 than what we're running with. This leads to a version mismatch error +# at runtime. You can re-produce it by running any test. If lxml is unpinned in the future +# and you see this error, it may be that the system libxml2 is now shipping the correct +# version and we can un-pin this. +# Backported from master commit ef93d6b8631 to fix pylint CI on open-release/sumac.master. +# Issue: https://github.com/openedx/edx-platform/issues/36305 +# Tracking: https://github.com/openedx/edx-platform/issues/36695 +lxml==5.3.0 +xmlsec==1.3.14