launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #32987
[Merge] ~enriqueesanchz/launchpad:add-vulnerabilities-export-data into launchpad:master
Enrique Sánchez has proposed merging ~enriqueesanchz/launchpad:add-vulnerabilities-export-data into launchpad:master.
Commit message:
Add vulnerabilities exportData endpoint
Implement the API endpoint to create a ExportVulnerabilityJob using
vulnerability set.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~enriqueesanchz/launchpad/+git/launchpad/+merge/492761
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~enriqueesanchz/launchpad:add-vulnerabilities-export-data into launchpad:master.
diff --git a/lib/lp/bugs/model/tests/test_vulnerability.py b/lib/lp/bugs/model/tests/test_vulnerability.py
index 2b69862..bae25c1 100644
--- a/lib/lp/bugs/model/tests/test_vulnerability.py
+++ b/lib/lp/bugs/model/tests/test_vulnerability.py
@@ -33,6 +33,7 @@ from lp.bugs.interfaces.vulnerabilityjob import (
IImportVulnerabilityJobSource,
VulnerabilityJobInProgress,
)
+from lp.bugs.model.exportvulnerabilityjob import ExportVulnerabilityJob
from lp.bugs.model.importvulnerabilityjob import ImportVulnerabilityJob
from lp.bugs.model.vulnerability import (
VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG,
@@ -982,6 +983,93 @@ class TestVulnerabilitySetImportData(TestCaseWithFactory):
)
+class TestVulnerabilitySetExportData(TestCaseWithFactory):
+ layer = DatabaseFunctionalLayer
+
+ def setUp(self):
+ super().setUp()
+ self.requester = self.factory.makePerson()
+ self.handler = VulnerabilityHandlerEnum.SOSS
+
+ def test_exportData(self):
+ """Test that we can create a ExportVulnerabilityJob using exportData
+ method.
+ """
+ self.useContext(feature_flags())
+ set_feature_flag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG, "true")
+
+ self.factory.makeDistribution(name="soss", owner=self.requester)
+
+ with person_logged_in(self.requester):
+ getUtility(IVulnerabilitySet).exportData(
+ self.requester,
+ self.handler,
+ None,
+ )
+
+ job = getUtility(IExportVulnerabilityJobSource).get(self.handler)
+ naked_job = removeSecurityProxy(job)
+ self.assertIsInstance(naked_job, ExportVulnerabilityJob)
+ self.assertEqual(naked_job.handler, self.handler)
+
+ def test_exportData_feature_flag_disabled(self):
+ """Test that if the feature flag is disabled it raises the
+ NotImplementedError exception."""
+
+ # All parameters None, feature flag is the first check
+ self.assertRaisesWithContent(
+ NotImplementedError,
+ "Vulnerability export API is currently disabled",
+ getUtility(IVulnerabilitySet).exportData,
+ self.requester,
+ None,
+ None,
+ )
+
+ def test_exportData_handler_unauthorized(self):
+ """Test that we cannot create a ExportVulnerabilityJob if the user is
+ not authorized to use the handler.
+ """
+ self.useContext(feature_flags())
+ set_feature_flag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG, "true")
+
+ self.factory.makeDistribution(name="soss")
+
+ self.assertRaisesWithContent(
+ UnauthorizedVulnerabilityHandler,
+ f"You don't have enough rights to use {self.handler}",
+ getUtility(IVulnerabilitySet).exportData,
+ self.requester,
+ self.handler,
+ None,
+ )
+
+ def test_exportData_duplicated(self):
+ """Test that we cannot create a duplicated ExportVulnerabilityJob
+ if there is already a peding one for the same handler.
+ """
+ self.useContext(feature_flags())
+ set_feature_flag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG, "true")
+
+ self.factory.makeDistribution(name="soss", owner=self.requester)
+
+ vulnerability_set = getUtility(IVulnerabilitySet)
+ with person_logged_in(self.requester):
+ vulnerability_set.exportData(
+ self.requester,
+ self.handler,
+ None,
+ )
+
+ self.assertRaises(
+ VulnerabilityJobInProgress,
+ vulnerability_set.exportData,
+ self.requester,
+ self.handler,
+ None,
+ )
+
+
class TestVulnerabilitySetWebService(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
@@ -1137,6 +1225,67 @@ class TestVulnerabilitySetWebService(TestCaseWithFactory):
set(response.body.decode().split("\n")),
)
+ def test_exportData_webservice(self):
+ """Test that we can create a ExportVulnerabilityJob using the
+ webservice.
+ """
+ self.useContext(feature_flags())
+ set_feature_flag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG, "true")
+
+ webservice = webservice_for_person(
+ self.requester,
+ default_api_version="devel",
+ )
+ response = webservice.named_post(
+ self.vulnerability_set_url,
+ "exportData",
+ handler=self.handler.title,
+ )
+ self.assertEqual(200, response.status)
+
+ def test_exportData_webservice_feature_flag_disabled(self):
+ """Test that we cannot create a ExportVulnerabilityJob using the
+ webservice when the vulnerability import API is disabled.
+ """
+ webservice = webservice_for_person(
+ self.requester,
+ default_api_version="devel",
+ )
+ response = webservice.named_post(
+ self.vulnerability_set_url,
+ "exportData",
+ handler=self.handler.title,
+ )
+ self.assertEqual(500, response.status)
+ self.assertEqual(
+ "Vulnerability export API is currently disabled",
+ response.body.decode().split("\n")[0],
+ )
+
+ def test_exportData_webservice_handler_unauthorized(self):
+ """Test that we can create a ExportVulnerabilityJob using the
+ webservice.
+ """
+ self.useContext(feature_flags())
+ set_feature_flag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG, "true")
+
+ user_unauthorized = self.factory.makePerson()
+
+ webservice = webservice_for_person(
+ user_unauthorized,
+ default_api_version="devel",
+ )
+ response = webservice.named_post(
+ self.vulnerability_set_url,
+ "exportData",
+ handler=self.handler.title,
+ )
+ self.assertEqual(500, response.status)
+ self.assertEqual(
+ f"You don't have enough rights to use {self.handler}",
+ response.body.decode().split("\n")[0],
+ )
+
def test_getImports_webservice_required_arguments_missing(self):
"""Test that getImports webservice requires missing arguments."""
webservice = webservice_for_person(
diff --git a/lib/lp/bugs/model/vulnerability.py b/lib/lp/bugs/model/vulnerability.py
index 068bee3..11f5dde 100644
--- a/lib/lp/bugs/model/vulnerability.py
+++ b/lib/lp/bugs/model/vulnerability.py
@@ -42,7 +42,10 @@ from lp.bugs.interfaces.vulnerability import (
IVulnerabilitySet,
VulnerabilityChange,
)
-from lp.bugs.interfaces.vulnerabilityjob import IImportVulnerabilityJobSource
+from lp.bugs.interfaces.vulnerabilityjob import (
+ IExportVulnerabilityJobSource,
+ IImportVulnerabilityJobSource,
+)
from lp.bugs.model.bug import Bug
from lp.bugs.model.buglinktarget import BugLinkTargetMixin
from lp.bugs.model.vulnerabilitysubscription import VulnerabilitySubscription
@@ -482,9 +485,30 @@ class VulnerabilitySet:
):
"""See `IVulnerabilitySet`."""
- raise NotImplementedError(
- "Vulnerability export API is currently disabled"
- )
+ if not getFeatureFlag(VULNERABILITY_IMPORT_ENABLED_FEATURE_FLAG):
+ raise NotImplementedError(
+ "Vulnerability export API is currently disabled"
+ )
+
+ # Check requester's permissions to handler
+ from lp.bugs.scripts.soss.sossexport import SOSSExporter
+
+ if handler == VulnerabilityHandlerEnum.SOSS:
+ distribution = getUtility(IDistributionSet).getByName(
+ HANDLER_DISTRIBUTION_MAP[handler]
+ )
+ exporter = SOSSExporter()
+ else:
+ raise NotFoundError(f"{handler} not found")
+
+ if not exporter.checkUserPermissions(requester, distribution):
+ raise UnauthorizedVulnerabilityHandler(
+ f"You don't have enough rights to use {handler}"
+ )
+
+ # Trigger the export job after validations pass
+ job_source = getUtility(IExportVulnerabilityJobSource)
+ job_source.create(handler)
return None