diff --git a/docs/source/modules/tcms.rst b/docs/source/modules/tcms.rst index ea3b3f4760..1e783a836e 100644 --- a/docs/source/modules/tcms.rst +++ b/docs/source/modules/tcms.rst @@ -34,3 +34,4 @@ Submodules tcms.handlers tcms.signals tcms.wsgi + tcms.xmlrpc_wrapper diff --git a/docs/source/modules/tcms.xmlrpc_wrapper.rst b/docs/source/modules/tcms.xmlrpc_wrapper.rst new file mode 100644 index 0000000000..a04ddbc78f --- /dev/null +++ b/docs/source/modules/tcms.xmlrpc_wrapper.rst @@ -0,0 +1,7 @@ +tcms.xmlrpc\_wrapper module +=========================== + +.. automodule:: tcms.xmlrpc_wrapper + :members: + :undoc-members: + :show-inheritance: diff --git a/requirements/base.txt b/requirements/base.txt index 355f0bc82d..ae0cffee05 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,6 +3,7 @@ allpairspy==2.5.1 bleach==6.1.0 bleach-allowlist==1.0.3 +defusedxml==0.7.1 Django==4.2.8 django-attachments==1.11 django-colorfield==0.11.0 diff --git a/tcms/bugs/tests/test_api.py b/tcms/bugs/tests/test_api.py index ed9dc39ee9..fe5fa601d5 100644 --- a/tcms/bugs/tests/test_api.py +++ b/tcms/bugs/tests/test_api.py @@ -1,10 +1,11 @@ # pylint: disable=attribute-defined-outside-init # pylint: disable=wrong-import-position import unittest -from xmlrpc.client import Fault as XmlRPCFault from django.conf import settings +from tcms.xmlrpc_wrapper import XmlRPCFault + if "tcms.bugs.apps.AppConfig" not in settings.INSTALLED_APPS: raise unittest.SkipTest("tcms.bugs is disabled") diff --git a/tcms/issuetracker/bugzilla_integration.py b/tcms/issuetracker/bugzilla_integration.py index 449af326a8..557ac24989 100644 --- a/tcms/issuetracker/bugzilla_integration.py +++ b/tcms/issuetracker/bugzilla_integration.py @@ -2,13 +2,13 @@ import os import tempfile from urllib.parse import urlencode -from xmlrpc.client import Fault import bugzilla from django.conf import settings from tcms.core.contrib.linkreference.models import LinkReference from tcms.issuetracker import base +from tcms.xmlrpc_wrapper import XmlRPCFault class Bugzilla(base.IssueTrackerType): @@ -94,7 +94,7 @@ def _report_issue(self, execution, user): is_defect=True, ) return (new_bug, new_bug.weburl) - except Fault: + except XmlRPCFault: pass url = self.bug_system.base_url diff --git a/tcms/issuetracker/tests/test_gitlab_ce.py b/tcms/issuetracker/tests/test_gitlab_ce.py deleted file mode 120000 index ffd607b85b..0000000000 --- a/tcms/issuetracker/tests/test_gitlab_ce.py +++ /dev/null @@ -1 +0,0 @@ -test_gitlab_ee.py \ No newline at end of file diff --git a/tcms/issuetracker/tests/test_gitlab_ce.py b/tcms/issuetracker/tests/test_gitlab_ce.py new file mode 100644 index 0000000000..5a5ce694de --- /dev/null +++ b/tcms/issuetracker/tests/test_gitlab_ce.py @@ -0,0 +1,192 @@ +# pylint: disable=attribute-defined-outside-init + +import os +import time +import unittest + +from tcms.core.contrib.linkreference.models import LinkReference +from tcms.issuetracker.types import Gitlab +from tcms.rpc.tests.utils import APITestCase +from tcms.testcases.models import BugSystem +from tcms.tests.factories import ComponentFactory, TestExecutionFactory + + +@unittest.skipUnless( + os.getenv("TEST_BUGTRACKER_INTEGRATION"), + "Bug tracker integration testing not enabled", +) +class TestGitlabIntegration(APITestCase): + existing_bug_id = 1 + existing_bug_url = "http://bugtracker.kiwitcms.org/root/kiwitcms/issues/1" + existing_bug_url_in_group = ( + "http://bugtracker.kiwitcms.org/group/sub_group/kiwitcms_in_group/issues/1" + ) + + def _fixture_setup(self): + super()._fixture_setup() + + self.execution_1 = TestExecutionFactory() + self.execution_1.case.text = "Given-When-Then" + self.execution_1.case.save() # will generate history object + + self.component = ComponentFactory( + name="Gitlab integration", product=self.execution_1.run.plan.product + ) + self.execution_1.case.add_component(self.component) + + bug_system = BugSystem.objects.create( # nosec:B106:hardcoded_password_funcarg + name="GitLab-EE for root/kiwitcms", + tracker_type="tcms.issuetracker.types.Gitlab", + base_url="http://bugtracker.kiwitcms.org/root/kiwitcms/", + api_url="http://bugtracker.kiwitcms.org", + api_password="ypCa3Dzb23o5nvsixwPA", + ) + self.integration = Gitlab(bug_system, None) + + def test_bug_id_from_url(self): + result = self.integration.bug_id_from_url(self.existing_bug_url) + self.assertEqual(self.existing_bug_id, result) + + # this is an alternative URL, with a dash + result = self.integration.bug_id_from_url( + "http://bugtracker.kiwitcms.org/root/kiwitcms/-/issues/1" + ) + self.assertEqual(self.existing_bug_id, result) + + def test_bug_id_from_url_in_group(self): + bug_system = BugSystem.objects.create( # nosec:B106:hardcoded_password_funcarg + name="GitLab-EE for group/sub_group/kiwitcms_in_group", + tracker_type="tcms.issuetracker.types.Gitlab", + base_url="http://bugtracker.kiwitcms.org/group/sub_group/kiwitcms_in_group/", + api_url="http://bugtracker.kiwitcms.org", + api_password="ypCa3Dzb23o5nvsixwPA", + ) + integration = Gitlab(bug_system, None) + + result = integration.bug_id_from_url(self.existing_bug_url_in_group) + self.assertEqual(self.existing_bug_id, result) + + # this is an alternative URL, with a dash + result = integration.bug_id_from_url( + "http://bugtracker.kiwitcms.org/group/sub_group/kiwitcms_in_group/-/issues/1" + ) + self.assertEqual(self.existing_bug_id, result) + + def test_details_for_public_url(self): + result = self.integration.details(self.existing_bug_url) + + self.assertEqual("Hello GitLab", result["title"]) + self.assertEqual("Created via CLI", result["description"]) + + def test_details_for_public_url_in_group(self): + bug_system = BugSystem.objects.create( # nosec:B106:hardcoded_password_funcarg + name="GitLab-EE for group/sub_group/kiwitcms_in_group", + tracker_type="tcms.issuetracker.types.Gitlab", + base_url="http://bugtracker.kiwitcms.org/group/sub_group/kiwitcms_in_group/", + api_url="http://bugtracker.kiwitcms.org", + api_password="ypCa3Dzb23o5nvsixwPA", + ) + integration = Gitlab(bug_system, None) + + result = integration.details(self.existing_bug_url_in_group) + + self.assertEqual("Hello GitLab Group", result["title"]) + self.assertEqual("Created via CLI", result["description"]) + + def test_details_for_private_url(self): + bug_system = BugSystem.objects.create( # nosec:B106:hardcoded_password_funcarg + name="Private GitLab for root/katinar", + tracker_type="tcms.issuetracker.types.Gitlab", + base_url="http://bugtracker.kiwitcms.org/root/katinar/", + api_url="http://bugtracker.kiwitcms.org", + api_password="ypCa3Dzb23o5nvsixwPA", + ) + integration = Gitlab(bug_system, None) + + result = integration.details( + "http://bugtracker.kiwitcms.org/root/katinar/-/issues/1" + ) + + self.assertEqual("Hello Private Issue", result["title"]) + self.assertEqual("Created in secret via CLI", result["description"]) + + def test_auto_update_bugtracker(self): + repo_id = self.integration.repo_id + gl_project = self.integration.rpc.projects.get(repo_id) + gl_issue = gl_project.issues.get(self.existing_bug_id) + + # make sure there are no comments to confuse the test + initial_comment_count = 0 + for comment in gl_issue.notes.list(): + initial_comment_count += 1 + self.assertNotIn("Confirmed via test execution", comment.body) + + # simulate user adding a new bug URL to a TE and clicking + # 'Automatically update bug tracker' + result = self.rpc_client.TestExecution.add_link( + { + "execution_id": self.execution_1.pk, + "is_defect": True, + "url": self.existing_bug_url, + }, + True, + ) + + # making sure RPC above returned the same URL + self.assertEqual(self.existing_bug_url, result["url"]) + + # wait until comments have been refreshed b/c this seem to happen async + retries = 0 + while len(gl_issue.notes.list()) <= initial_comment_count: + time.sleep(1) + retries += 1 + self.assertLess(retries, 20) + + # sort by id b/c the gitlab library returns newest comments first but + # that may be depending on configuration ! + last_comment = sorted(gl_issue.notes.list(), key=lambda x: x.id)[-1] + + # assert that a comment has been added as the last one + # and also verify its text + for expected_string in [ + "Confirmed via test execution", + f"TR-{self.execution_1.run_id}: {self.execution_1.run.summary}", + self.execution_1.run.get_full_url(), + f"TE-{self.execution_1.pk}: {self.execution_1.case.summary}", + ]: + self.assertIn(expected_string, last_comment.body) + + def test_report_issue_from_test_execution_1click_works(self): + # simulate user clicking the 'Report bug' button in TE widget, TR page + result = self.rpc_client.Bug.report( + self.execution_1.pk, self.integration.bug_system.pk + ) + self.assertEqual(result["rc"], 0) + self.assertIn(self.integration.bug_system.base_url, result["response"]) + self.assertIn("/-/issues/", result["response"]) + + # assert that the result looks like valid URL parameters + new_issue_id = self.integration.bug_id_from_url(result["response"]) + repo_id = self.integration.repo_id + gl_project = self.integration.rpc.projects.get(repo_id) + issue = gl_project.issues.get(new_issue_id) + + self.assertEqual(f"Failed test: {self.execution_1.case.summary}", issue.title) + for expected_string in [ + f"Filed from execution {self.execution_1.get_full_url()}", + "Reporter", + self.execution_1.build.version.product.name, + self.component.name, + "Steps to reproduce", + self.execution_1.case.text, + ]: + self.assertIn(expected_string, issue.description) + + # verify that LR has been added to TE + self.assertTrue( + LinkReference.objects.filter( + execution=self.execution_1, + url=result["response"], + is_defect=True, + ).exists() + ) diff --git a/tcms/kiwi_attachments/tests/test_validators.py b/tcms/kiwi_attachments/tests/test_validators.py index 37dcc871bb..face9e4303 100644 --- a/tcms/kiwi_attachments/tests/test_validators.py +++ b/tcms/kiwi_attachments/tests/test_validators.py @@ -2,12 +2,12 @@ # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used import base64 -from xmlrpc.client import Fault from django.utils.translation import gettext_lazy as _ from parameterized import parameterized from tcms.rpc.tests.utils import APITestCase +from tcms.xmlrpc_wrapper import XmlRPCFault class TestValidators(APITestCase): @@ -23,7 +23,7 @@ def test_uploading_svg_with_inline_script_should_fail(self, file_name): tag_name = "script" message = str(_(f"File contains forbidden tag: <{tag_name}>")) - with self.assertRaisesRegex(Fault, message): + with self.assertRaisesRegex(XmlRPCFault, message): self.rpc_client.User.add_attachment("inline_javascript.svg", b64) @parameterized.expand( @@ -37,12 +37,12 @@ def test_uploading_svg_with_forbidden_attributes_should_fail(self, file_name): attr_name = "onload" message = str(_(f"File contains forbidden attribute: `{attr_name}`")) - with self.assertRaisesRegex(Fault, message): + with self.assertRaisesRegex(XmlRPCFault, message): self.rpc_client.User.add_attachment("image.svg", b64) def test_uploading_filename_ending_in_dot_exe_should_fail(self): message = str(_("Uploading executable files is forbidden")) - with self.assertRaisesRegex(Fault, message): + with self.assertRaisesRegex(XmlRPCFault, message): self.rpc_client.User.add_attachment("hello.exe", "a2l3aXRjbXM=") def test_uploading_real_exe_file_should_fail(self): @@ -50,5 +50,5 @@ def test_uploading_real_exe_file_should_fail(self): b64 = base64.b64encode(exe_file.read()).decode() message = str(_("Uploading executable files is forbidden")) - with self.assertRaisesRegex(Fault, message): + with self.assertRaisesRegex(XmlRPCFault, message): self.rpc_client.User.add_attachment("csrss.exe_from_reactos", b64) diff --git a/tcms/rpc/tests/test_attachment.py b/tcms/rpc/tests/test_attachment.py index 40ae3aea76..fddf2d0f80 100644 --- a/tcms/rpc/tests/test_attachment.py +++ b/tcms/rpc/tests/test_attachment.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.tests import user_should_have_perm from tcms.tests.factories import TestPlanFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestRemoveAttachment(APITestCase): diff --git a/tcms/rpc/tests/test_auth.py b/tcms/rpc/tests/test_auth.py index a8c220ad67..e157be6cf5 100644 --- a/tcms/rpc/tests/test_auth.py +++ b/tcms/rpc/tests/test_auth.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APITestCase +from tcms.xmlrpc_wrapper import XmlRPCFault class TestAuthLogin(APITestCase): diff --git a/tcms/rpc/tests/test_build.py b/tcms/rpc/tests/test_build.py index 78efe809dc..fe4861ac5f 100644 --- a/tcms/rpc/tests/test_build.py +++ b/tcms/rpc/tests/test_build.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- # pylint: disable=invalid-name, attribute-defined-outside-init, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault from django.test import override_settings from tcms.rpc.tests.utils import APITestCase from tcms.tests.factories import BuildFactory, VersionFactory +from tcms.xmlrpc_wrapper import XmlRPCFault @override_settings(LANGUAGE_CODE="en") diff --git a/tcms/rpc/tests/test_category.py b/tcms/rpc/tests/test_category.py index 4faa0194f8..d22b6aebaa 100644 --- a/tcms/rpc/tests/test_category.py +++ b/tcms/rpc/tests/test_category.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.testcases.models import Category from tcms.tests.factories import CategoryFactory, ProductFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestCategory(APITestCase): diff --git a/tcms/rpc/tests/test_classification.py b/tcms/rpc/tests/test_classification.py index 00755e49c6..929e00c075 100644 --- a/tcms/rpc/tests/test_classification.py +++ b/tcms/rpc/tests/test_classification.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.management.models import Classification from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.tests.factories import ClassificationFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestClassificationFilter(APITestCase): diff --git a/tcms/rpc/tests/test_component.py b/tcms/rpc/tests/test_component.py index c54214aec1..5aa9ac5522 100644 --- a/tcms/rpc/tests/test_component.py +++ b/tcms/rpc/tests/test_component.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APITestCase from tcms.tests.factories import ComponentFactory, ProductFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilterComponents(APITestCase): diff --git a/tcms/rpc/tests/test_environment.py b/tcms/rpc/tests/test_environment.py index 1c2a9c7acd..0c62aeaa8d 100644 --- a/tcms/rpc/tests/test_environment.py +++ b/tcms/rpc/tests/test_environment.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- -from xmlrpc.client import Fault as XmlRPCFault from django.test import override_settings from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.testruns.models import Environment +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilterPermission(APIPermissionsTestCase): diff --git a/tcms/rpc/tests/test_plantype.py b/tcms/rpc/tests/test_plantype.py index e154e2b1ed..ed526f8b69 100644 --- a/tcms/rpc/tests/test_plantype.py +++ b/tcms/rpc/tests/test_plantype.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase from tcms.testplans.models import PlanType from tcms.tests.factories import PlanTypeFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestPlanTypeFilter(APIPermissionsTestCase): diff --git a/tcms/rpc/tests/test_priority.py b/tcms/rpc/tests/test_priority.py index 3cc6faa73b..24cf427512 100644 --- a/tcms/rpc/tests/test_priority.py +++ b/tcms/rpc/tests/test_priority.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase +from tcms.xmlrpc_wrapper import XmlRPCFault class TestPriorityFilter(APITestCase): diff --git a/tcms/rpc/tests/test_product.py b/tcms/rpc/tests/test_product.py index 55c9676e48..f7cc871b9d 100644 --- a/tcms/rpc/tests/test_product.py +++ b/tcms/rpc/tests/test_product.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.management.models import Product from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.tests.factories import ClassificationFactory, ProductFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilter(APITestCase): diff --git a/tcms/rpc/tests/test_testcase.py b/tcms/rpc/tests/test_testcase.py index bcd7bacc75..30594e6658 100644 --- a/tcms/rpc/tests/test_testcase.py +++ b/tcms/rpc/tests/test_testcase.py @@ -3,7 +3,6 @@ import unittest from datetime import timedelta -from xmlrpc.client import Fault as XmlRPCFault from attachments.models import Attachment from django.contrib.auth.models import Permission @@ -27,6 +26,7 @@ UserFactory, VersionFactory, ) +from tcms.xmlrpc_wrapper import XmlRPCFault class TestValidateEmail(unittest.TestCase): diff --git a/tcms/rpc/tests/test_testcasestatus.py b/tcms/rpc/tests/test_testcasestatus.py index c83d06033a..c2b4735633 100644 --- a/tcms/rpc/tests/test_testcasestatus.py +++ b/tcms/rpc/tests/test_testcasestatus.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase +from tcms.xmlrpc_wrapper import XmlRPCFault class TestCaseStatusFilter(APITestCase): diff --git a/tcms/rpc/tests/test_testexecution.py b/tcms/rpc/tests/test_testexecution.py index 9085299bdf..baf4a63a1e 100644 --- a/tcms/rpc/tests/test_testexecution.py +++ b/tcms/rpc/tests/test_testexecution.py @@ -2,7 +2,6 @@ # pylint: disable=invalid-name, attribute-defined-outside-init, objects-update-used import time -from xmlrpc.client import Fault as XmlRPCFault from django.forms.models import model_to_dict from django.test import override_settings @@ -18,6 +17,7 @@ TestExecutionFactory, UserFactory, ) +from tcms.xmlrpc_wrapper import XmlRPCFault class TestExecutionGetComments(APITestCase): diff --git a/tcms/rpc/tests/test_testexecutionstatus.py b/tcms/rpc/tests/test_testexecutionstatus.py index 4c7d8248d5..23a37d1d4e 100644 --- a/tcms/rpc/tests/test_testexecutionstatus.py +++ b/tcms/rpc/tests/test_testexecutionstatus.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilter(APITestCase): diff --git a/tcms/rpc/tests/test_testplan.py b/tcms/rpc/tests/test_testplan.py index 82113e7214..bb4ac2c884 100644 --- a/tcms/rpc/tests/test_testplan.py +++ b/tcms/rpc/tests/test_testplan.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault - from attachments.models import Attachment from django.contrib.auth.models import Permission from django.test import override_settings @@ -21,6 +19,7 @@ UserFactory, VersionFactory, ) +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilter(APITestCase): diff --git a/tcms/rpc/tests/test_testrun.py b/tcms/rpc/tests/test_testrun.py index aa451b9d92..48ad270820 100644 --- a/tcms/rpc/tests/test_testrun.py +++ b/tcms/rpc/tests/test_testrun.py @@ -2,7 +2,6 @@ # pylint: disable=attribute-defined-outside-init, objects-update-used from datetime import datetime -from xmlrpc.client import Fault as XmlRPCFault from attachments.models import Attachment from django.contrib.auth.models import Permission @@ -24,6 +23,7 @@ UserFactory, VersionFactory, ) +from tcms.xmlrpc_wrapper import XmlRPCFault class TestAddCase(APITestCase): diff --git a/tcms/rpc/tests/test_user.py b/tcms/rpc/tests/test_user.py index 802be63b03..70dd7e8ba6 100644 --- a/tcms/rpc/tests/test_user.py +++ b/tcms/rpc/tests/test_user.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, objects-update-used -from xmlrpc.client import Fault as XmlRPCFault from django.test import TestCase @@ -9,6 +8,7 @@ from tcms.rpc.tests.utils import APITestCase from tcms.tests import user_should_have_perm from tcms.tests.factories import GroupFactory, UserFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestUserSerializer(TestCase): diff --git a/tcms/rpc/tests/test_version.py b/tcms/rpc/tests/test_version.py index c6259f3913..1d901aed76 100644 --- a/tcms/rpc/tests/test_version.py +++ b/tcms/rpc/tests/test_version.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # pylint: disable=attribute-defined-outside-init, invalid-name, avoid-list-comprehension -from xmlrpc.client import Fault as XmlRPCFault from django.test import override_settings from tcms.management.models import Version from tcms.rpc.tests.utils import APIPermissionsTestCase, APITestCase from tcms.tests.factories import ProductFactory, VersionFactory +from tcms.xmlrpc_wrapper import XmlRPCFault class TestFilterVersions(APITestCase): diff --git a/tcms/xmlrpc_wrapper.py b/tcms/xmlrpc_wrapper.py new file mode 100644 index 0000000000..e346d68f4d --- /dev/null +++ b/tcms/xmlrpc_wrapper.py @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Alexander Todorov + +# B411:blacklist +# CWE: CWE-20 (https://cwe.mitre.org/data/definitions/20.html) +# https://bandit.readthedocs.io/en/1.7.6/blacklists/blacklist_imports.html#b411-import-xmlrpclib +import defusedxml.xmlrpc + +defusedxml.xmlrpc.monkey_patch() + +__all__ = ("XmlRPCFault",) + +XmlRPCFault = defusedxml.xmlrpc.xmlrpc_client.Fault