launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #33058
[Merge] ~ines-almeida/launchpad:svt-move-test-files into launchpad:master
Ines Almeida has proposed merging ~ines-almeida/launchpad:svt-move-test-files into launchpad:master.
Commit message:
Move UCT test files to make directory consistent
This makes it so that SOSS and UCT records have their own tests in separate directories
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~ines-almeida/launchpad/+git/launchpad/+merge/493466
This is just a file moving with no other change. All tests in bugs/scripts/tests passed
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~ines-almeida/launchpad:svt-move-test-files into launchpad:master.
diff --git a/lib/lp/bugs/model/exportvulnerabilityjob.py b/lib/lp/bugs/model/exportvulnerabilityjob.py
index 254b6e6..6da2147 100644
--- a/lib/lp/bugs/model/exportvulnerabilityjob.py
+++ b/lib/lp/bugs/model/exportvulnerabilityjob.py
@@ -17,7 +17,6 @@ from zope.component import getUtility
from zope.interface import implementer, provider
from zope.security.proxy import removeSecurityProxy
-from lp.app.enums import InformationType
from lp.bugs.enums import VulnerabilityHandlerEnum
from lp.bugs.interfaces.vulnerabilityjob import (
IExportVulnerabilityJob,
@@ -27,14 +26,14 @@ from lp.bugs.interfaces.vulnerabilityjob import (
VulnerabilityJobType,
)
from lp.bugs.model.bug import Bug as BugModel
-from lp.bugs.model.cve import Cve as CveModel
from lp.bugs.model.vulnerability import HANDLER_DISTRIBUTION_MAP, Vulnerability
from lp.bugs.model.vulnerabilityjob import (
VulnerabilityJob,
VulnerabilityJobDerived,
)
-from lp.bugs.scripts.soss.models import SOSSRecord
from lp.bugs.scripts.soss.sossexport import SOSSExporter
+from lp.bugs.scripts.svthandler import SVTExporter, SVTRecord
+from lp.bugs.scripts.uct.uctexport import UCTExporter
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.model.distribution import Distribution
from lp.services.config import config
@@ -48,8 +47,6 @@ EXPIRATION_WEEK_INTERVAL = 4
PROCESSED_CVE_LOG_INTERVAL = 500
logger = logging.getLogger(__name__)
-HANDLER_EXPORTER_MAP = {VulnerabilityHandlerEnum.SOSS: SOSSExporter}
-
@implementer(IExportVulnerabilityJob)
@provider(IExportVulnerabilityJobSource)
@@ -72,10 +69,6 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
return self.metadata.get("request").get("sources")
@property
- def information_type(self):
- return self.metadata.get("request").get("information_type")
-
- @property
def error_description(self):
return self.metadata.get("result").get("error_description")
@@ -84,7 +77,6 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
cls,
handler,
sources: Optional[List[str]] = None,
- information_type=InformationType.PRIVATESECURITY.value,
):
"""Create a new `ExportVulnerabilityJob`.
@@ -114,7 +106,6 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
metadata = {
"request": {
"sources": sources if sources is not None else [],
- "information_type": information_type,
},
"result": {
"error_description": [],
@@ -157,36 +148,35 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
parts += ", metadata: %s" % self.metadata
return "<%s>" % parts
- def _get_exporter_to_record(
+ def _get_exporter(
self,
handler: VulnerabilityHandlerEnum,
- information_type: InformationType = InformationType.PRIVATESECURITY,
- ):
- """Decide which parser and importer to use
+ ) -> SVTExporter:
+ """Decide which exporter to use
:return: a tuple of (parser, importer) where parser is the function
that gets a blob and returns a record and importer is the function that
gets a record and imports it.
"""
- exporter = HANDLER_EXPORTER_MAP.get(handler)
-
- if not exporter:
- exception = VulnerabilityJobException("Handler not found")
+ if handler == VulnerabilityHandlerEnum.SOSS:
+ return SOSSExporter()
+ elif handler == VulnerabilityHandlerEnum.UCT:
+ return UCTExporter()
+ else:
+ exception = VulnerabilityJobException(
+ f"Handler '{handler}' not found"
+ )
self.notifyUserError(exception)
raise exception
- exporter_to_record = exporter(
- information_type=information_type
- ).to_record
-
- return exporter_to_record
-
def _get_distribution(self, handler) -> Distribution:
distribution_name = HANDLER_DISTRIBUTION_MAP.get(handler)
if not distribution_name:
- exception = VulnerabilityJobException("Handler not found")
+ exception = VulnerabilityJobException(
+ f"Handler '{handler}' not found"
+ )
self.notifyUserError(exception)
raise exception
@@ -222,11 +212,7 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
def run(self):
"""See `IRunnableJob`."""
- information_type = InformationType.items[self.information_type]
- export_to_record = self._get_exporter_to_record(
- self.context.handler,
- information_type,
- )
+ exporter = self._get_exporter(self.context.handler)
distribution = self._get_distribution(self.context.handler)
distribution_vulnerability_set = (
distribution.getVulnerabilitiesVisibleToUser(
@@ -242,9 +228,8 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
# Log progress every PROCESSED_CVE_LOG_INTERVAL CVEs
num_parsed_cves = 0
- exported_cves: List[Tuple[SOSSRecord, str]] = []
+ exported_cves: List[Tuple[SVTRecord, str]] = []
for vul in distribution_vulnerability_set:
- cve: CveModel = vul.cve
bug = self._get_bug(vul)
@@ -257,14 +242,14 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
continue
try:
- record = export_to_record(cve, distribution, bug, vul)
+ record = exporter.to_record(bug, vul)
except ValueError as e:
self.notifyUserError(e)
continue
if record is None:
exception = VulnerabilityJobException(
- f"CVE-{cve.sequence} couldn't be converted"
+ f"CVE-{vul.cve.sequence} couldn't be converted"
)
self.notifyUserError(exception)
continue
@@ -283,7 +268,7 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
f"Processed {num_parsed_cves} CVEs in total."
)
- if exported_cves == []:
+ if len(exported_cves) == 0:
exception = VulnerabilityJobException("No CVEs to export")
self.notifyUserError(exception)
raise exception
@@ -303,7 +288,7 @@ class ExportVulnerabilityJob(VulnerabilityJobDerived):
file_path = os.path.join(temp_dir, cve_name)
with open(file_path, "w") as f:
- f.write(record.to_yaml())
+ f.write(record.to_str())
# Create a zip archive of the temp folder
buf = io.BytesIO()
diff --git a/lib/lp/bugs/scripts/soss/models.py b/lib/lp/bugs/scripts/soss/models.py
index ca9d202..22445fc 100644
--- a/lib/lp/bugs/scripts/soss/models.py
+++ b/lib/lp/bugs/scripts/soss/models.py
@@ -218,5 +218,5 @@ class SOSSRecord(SVTRecord):
return serialized
- def to_yaml(self) -> str:
+ def to_str(self) -> str:
return yaml.dump(self.to_dict(), sort_keys=False)
diff --git a/lib/lp/bugs/scripts/soss/sossexport.py b/lib/lp/bugs/scripts/soss/sossexport.py
index c158dd3..94a7f98 100644
--- a/lib/lp/bugs/scripts/soss/sossexport.py
+++ b/lib/lp/bugs/scripts/soss/sossexport.py
@@ -7,10 +7,8 @@ from collections import defaultdict
from datetime import datetime
from typing import Dict, List, Optional, Union
-from lp.app.enums import InformationType
from lp.bugs.model.bug import Bug as BugModel
from lp.bugs.model.bugtask import BugTask
-from lp.bugs.model.cve import Cve as CveModel
from lp.bugs.model.vulnerability import Vulnerability
from lp.bugs.scripts.soss.models import SOSSRecord
from lp.bugs.scripts.soss.sossimport import (
@@ -20,7 +18,6 @@ from lp.bugs.scripts.soss.sossimport import (
)
from lp.bugs.scripts.svthandler import SVTExporter
from lp.registry.interfaces.role import IPersonRoles
-from lp.registry.model.distribution import Distribution
from lp.registry.security import SecurityAdminDistribution
__all__ = [
@@ -43,12 +40,6 @@ class SOSSExporter(SVTExporter):
files.
"""
- def __init__(
- self,
- information_type: InformationType = InformationType.PROPRIETARY,
- ) -> None:
- self.information_type = information_type
-
def _get_packages(
self, bugtasks: List[BugTask]
) -> Dict[SOSSRecord.PackageTypeEnum, SOSSRecord.Package]:
@@ -95,15 +86,13 @@ class SOSSExporter(SVTExporter):
def to_record(
self,
- lp_cve: CveModel,
- distribution: Distribution,
bug: BugModel,
vulnerability: Vulnerability,
) -> SOSSRecord:
"""Return a SOSSRecord exporting Launchpad data for the specified
cve_sequence.
"""
- self._validate_to_record_args(lp_cve, distribution, bug, vulnerability)
+ self._validate_to_record_args(bug, vulnerability)
# Parse bug
desc_parts = bug.description.rsplit("\n\nReferences:\n", maxsplit=1)
@@ -131,7 +120,7 @@ class SOSSExporter(SVTExporter):
priority_reason=vulnerability.importance_explanation,
assigned_to=assigned_to,
packages=packages,
- candidate=f"CVE-{lp_cve.sequence}",
+ candidate=f"CVE-{vulnerability.cve.sequence}",
description=vulnerability.description,
cvss=self._get_cvss(vulnerability.cvss),
public_date=public_date,
@@ -157,16 +146,12 @@ class SOSSExporter(SVTExporter):
def _validate_to_record_args(
self,
- lp_cve: CveModel,
- distribution: Distribution,
bug: BugModel,
vulnerability: Vulnerability,
):
required_args = {
- "Cve": lp_cve,
"Bug": bug,
"Vulnerability": vulnerability,
- "Distribution": distribution,
}
for name, value in required_args.items():
diff --git a/lib/lp/bugs/scripts/soss/tests/test_sossexport.py b/lib/lp/bugs/scripts/soss/tests/test_sossexport.py
index 07802dc..1752d8e 100644
--- a/lib/lp/bugs/scripts/soss/tests/test_sossexport.py
+++ b/lib/lp/bugs/scripts/soss/tests/test_sossexport.py
@@ -79,12 +79,7 @@ class TestSOSSExporter(TestCaseWithFactory):
soss_record = SOSSRecord.from_yaml(f)
bug, vulnerability = soss_importer.import_cve_from_file(file)
-
- cve_sequence = file.name.lstrip("CVE-")
- lp_cve = self.cve_set[cve_sequence]
- exported = self.soss_exporter.to_record(
- lp_cve, self.soss, bug, vulnerability
- )
+ exported = self.soss_exporter.to_record(bug, vulnerability)
self.assertEqual(soss_record, exported)
@@ -98,12 +93,7 @@ class TestSOSSExporter(TestCaseWithFactory):
for file in self.sampledata.iterdir():
bug, vulnerability = soss_importer.import_cve_from_file(file)
-
- cve_sequence = file.name.lstrip("CVE-")
- lp_cve = self.cve_set[cve_sequence]
- exported = self.soss_exporter.to_record(
- lp_cve, self.soss, bug, vulnerability
- )
+ exported = self.soss_exporter.to_record(bug, vulnerability)
with open(file) as f:
- self.assertEqual(f.read(), exported.to_yaml())
+ self.assertEqual(f.read(), exported.to_str())
diff --git a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
index a4d0285..1353c99 100644
--- a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
+++ b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
@@ -342,19 +342,19 @@ class TestSOSSRecord(TestCase):
self.soss_record_dict,
)
- def test_to_yaml(self):
+ def test_to_str(self):
load_from = Path(__file__).parent / "sampledata" / "CVE-2025-1979"
with open(load_from) as f:
sample_data = f.read()
- self.assertEqual(self.soss_record.to_yaml(), sample_data),
+ self.assertEqual(self.soss_record.to_str(), sample_data),
def _verify_import_export_yaml(self, file):
with open(file) as f:
soss_record_read = f.read()
soss_record = SOSSRecord.from_yaml(soss_record_read)
- self.assertEqual(soss_record_read, soss_record.to_yaml())
+ self.assertEqual(soss_record_read, soss_record.to_str())
def test_verify_import_export_yaml(self):
files = self.get_sample_files()
diff --git a/lib/lp/bugs/scripts/svthandler.py b/lib/lp/bugs/scripts/svthandler.py
index 9e9d096..51efb2d 100644
--- a/lib/lp/bugs/scripts/svthandler.py
+++ b/lib/lp/bugs/scripts/svthandler.py
@@ -7,21 +7,28 @@ __all__ = [
"SVTExporter",
]
+from dataclasses import dataclass
+
from lp.bugs.interfaces.bug import IBug
-from lp.bugs.interfaces.cve import ICve
from lp.bugs.interfaces.vulnerability import IVulnerability
-from lp.registry.interfaces.distribution import IDistribution
+@dataclass
class SVTRecord:
"""A dataclass that contains the exact same info as a cve file."""
+ @classmethod
def from_str(string: str) -> "SVTRecord":
"""Parse a string and return a SVTRecord."""
raise NotImplementedError()
+ def to_str(self) -> str:
+ """Convert the SVTRecord to a string."""
+ raise NotImplementedError()
+
class SVTImporter:
+
def from_record(
record: SVTRecord, cve_sequence: str
) -> (IBug, IVulnerability):
@@ -34,12 +41,15 @@ class SVTImporter:
class SVTExporter:
+
def to_record(
- lp_cve: ICve,
- distribution: IDistribution,
bug: IBug,
vulnerability: IVulnerability,
) -> SVTRecord:
"""Export the bug and vulnerability related to a cve in a distribution
and return a SVTRecord."""
raise NotImplementedError()
+
+ def checkUserPermissions(self, user, distribution):
+ """Checks if the user has permissions to use this handler."""
+ raise NotImplementedError()
diff --git a/lib/lp/bugs/scripts/uct/models.py b/lib/lp/bugs/scripts/uct/models.py
index e707b49..42331d0 100644
--- a/lib/lp/bugs/scripts/uct/models.py
+++ b/lib/lp/bugs/scripts/uct/models.py
@@ -5,6 +5,7 @@ import logging
import re
import tempfile
from collections import OrderedDict, defaultdict
+from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from pathlib import Path
@@ -60,6 +61,7 @@ class CVSS(NamedTuple):
vector_string: str
+@dataclass
class UCTRecord(SVTRecord):
"""
UCTRecord represents a single CVE record (file) in the ubuntu-cve-tracker.
@@ -104,45 +106,24 @@ class UCTRecord(SVTRecord):
tags: Set[str]
patches: List["UCTRecord.Patch"]
- def __init__(
- self,
- parent_dir: str,
- assigned_to: str,
- bugs: List[str],
- cvss: List[CVSS],
- candidate: str,
- crd: Optional[datetime],
- public_date: Optional[datetime],
- public_date_at_USN: Optional[datetime],
- description: str,
- discovered_by: str,
- mitigation: Optional[str],
- notes: str,
- priority: Priority,
- references: List[str],
- ubuntu_description: str,
- packages: List[Package],
- global_tags: Set[str],
- priority_explanation: str = "",
- ):
- self.parent_dir = parent_dir
- self.assigned_to = assigned_to
- self.bugs = bugs
- self.cvss = cvss
- self.candidate = candidate
- self.crd = crd
- self.public_date = public_date
- self.public_date_at_USN = public_date_at_USN
- self.description = description
- self.discovered_by = discovered_by
- self.mitigation = mitigation
- self.notes = notes
- self.priority = priority
- self.priority_explanation = priority_explanation
- self.references = references
- self.ubuntu_description = ubuntu_description
- self.packages = packages
- self.global_tags = global_tags
+ parent_dir: str
+ assigned_to: str
+ bugs: List[str]
+ cvss: List[CVSS]
+ candidate: str
+ crd: Optional[datetime]
+ public_date: Optional[datetime]
+ public_date_at_USN: Optional[datetime]
+ description: str
+ discovered_by: str
+ mitigation: Optional[str]
+ notes: str
+ priority: "UCTRecord.Priority"
+ references: List[str]
+ ubuntu_description: str
+ packages: List["UCTRecord.Package"]
+ global_tags: Set[str]
+ priority_explanation: str = ""
def __eq__(self, other):
if not isinstance(other, UCTRecord):
diff --git a/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2007-0255 b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2007-0255
new file mode 100644
index 0000000..db2403d
--- /dev/null
+++ b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2007-0255
@@ -0,0 +1,61 @@
+PublicDate: 2007-01-16 23:28:00 UTC
+Candidate: CVE-2007-0255
+References:
+ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0255
+ http://xine.sourceforge.net/security
+Description:
+ XINE 0.99.4 allows user-assisted remote attackers to cause a denial of
+ service (application crash) and possibly execute arbitrary code via a
+ certain M3U file that contains a long #EXTINF line and contains format
+ string specifiers in an invalid udp:// URI, possibly a variant of
+ CVE-2007-0017.
+Ubuntu-Description:
+Notes:
+ sbeattie> issue is unlisted on xine upstream website
+Priority: medium
+Bugs:
+Discovered-by:
+Assigned-to:
+CVSS:
+
+Patches_xine-ui:
+upstream_xine-ui: needs-triage
+dapper_xine-ui: ignored (reached end-of-life)
+edgy_xine-ui: needed (reached end-of-life)
+feisty_xine-ui: needed (reached end-of-life)
+gutsy_xine-ui: needed (reached end-of-life)
+hardy_xine-ui: ignored (reached end-of-life)
+intrepid_xine-ui: needed (reached end-of-life)
+jaunty_xine-ui: ignored (reached end-of-life)
+karmic_xine-ui: ignored (reached end-of-life)
+lucid_xine-ui: ignored (reached end-of-life)
+maverick_xine-ui: ignored (reached end-of-life)
+natty_xine-ui: ignored (reached end-of-life)
+oneiric_xine-ui: ignored (reached end-of-life)
+precise_xine-ui: ignored (reached end-of-life)
+precise/esm_xine-ui: DNE (precise was needed)
+quantal_xine-ui: ignored (reached end-of-life)
+raring_xine-ui: ignored (reached end-of-life)
+saucy_xine-ui: ignored (reached end-of-life)
+trusty_xine-ui: ignored (reached end-of-life)
+trusty/esm_xine-ui: DNE (trusty was needed)
+utopic_xine-ui: ignored (reached end-of-life)
+vivid_xine-ui: ignored (reached end-of-life)
+vivid/stable-phone-overlay_xine-ui: DNE
+vivid/ubuntu-core_xine-ui: DNE
+wily_xine-ui: ignored (reached end-of-life)
+xenial_xine-ui: ignored (end of standard support, was needed)
+yakkety_xine-ui: ignored (reached end-of-life)
+zesty_xine-ui: ignored (reached end-of-life)
+artful_xine-ui: ignored (reached end-of-life)
+bionic_xine-ui: needed
+cosmic_xine-ui: ignored (reached end-of-life)
+disco_xine-ui: ignored (reached end-of-life)
+eoan_xine-ui: ignored (reached end-of-life)
+focal_xine-ui: needed
+groovy_xine-ui: ignored (reached end-of-life)
+hirsute_xine-ui: ignored (reached end-of-life)
+impish_xine-ui: ignored (reached end-of-life)
+jammy_xine-ui: needed
+kinetic_xine-ui: needed
+devel_xine-ui: needed
\ No newline at end of file
diff --git a/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-23222 b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-23222
new file mode 100644
index 0000000..8c8a836
--- /dev/null
+++ b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-23222
@@ -0,0 +1,47 @@
+PublicDateAtUSN: 2022-01-14 08:15:00 UTC
+Candidate: CVE-2022-23222
+PublicDate: 2022-01-14 08:15:00 UTC
+References:
+ https://ubuntu.com/security/notices/USN-5368-1
+Description:
+ kernel/bpf/verifier.c in the Linux kernel through 5.15.14 allows local
+ users to gain privileges because of the availability of pointer arithmetic
+ via certain *_OR_NULL pointer types.
+Ubuntu-Description:
+ It was discovered that the BPF verifier in the Linux kernel did not
+ properly restrict pointer types in certain situations. A local attacker
+ could use this to cause a denial of service (system crash) or possibly
+ execute arbitrary code.
+Notes:
+ sbeattie> Ubuntu 21.10 / 5.13+ kernels disable unprivileged BPF by default.
+ kernels 5.8 and older are not affected, priority high is for
+ 5.10 and 5.11 based kernels only
+Mitigation:
+ seth-arnold> set kernel.unprivileged_bpf_disabled to 1
+Bugs:
+ https://github.com/mm2/Little-CMS/issues/29
+ https://github.com/mm2/Little-CMS/issues/30
+ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=745471
+Priority: critical
+Discovered-by: tr3e wang
+Assigned-to:
+Tags: cisa-kev
+CVSS:
+ nvd: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H [7.8 HIGH]
+
+Patches_linux:
+ break-fix: 457f44363a8894135c85b7a9afd2bd8196db24ab c25b2ae136039ffa820c26138ed4a5e5f3ab3841|local-CVE-2022-23222-fix
+ upstream: https://github.com/389ds/389-ds-base/commit/58dbf084a63e6dbbd999bf6a70475fad8255f26a (1.4.4)
+ upstream: https://github.com/389ds/389-ds-base/commit/2e5b526012612d1d6ccace46398bee679a730271
+upstream_linux: released (5.17~rc1)
+impish_linux: released (5.13.0-37.42)
+devel_linux: not-affected (5.15.0-25.25)
+Priority_linux_impish: medium
+Priority_linux_devel: medium
+Tags_linux: not-ue
+
+Patches_linux-hwe:
+upstream_linux-hwe: released (5.17~rc1)
+impish_linux-hwe: DNE
+devel_linux-hwe: DNE
+Priority_linux-hwe: high
diff --git a/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-3219 b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-3219
new file mode 100644
index 0000000..14aaa73
--- /dev/null
+++ b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2022-3219
@@ -0,0 +1,43 @@
+Candidate: CVE-2022-3219
+PublicDate: 2022-09-28
+References:
+ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-3219
+ https://access.redhat.com/security/cve/CVE-2022-3219
+ https://marc.info/?l=oss-security&m=165696590211434&w=4
+Description:
+ gnupg: denial of service issue (resource consumption) using compressed
+ packets
+Ubuntu-Description:
+Notes:
+ mdeslaur> per the upstream gnupg bug, the change will not be applied
+ mdeslaur> as of 2022-09-28, proposed patch has not been accepted by
+ mdeslaur> upstream developers
+Mitigation:
+Bugs:
+ https://dev.gnupg.org/T5993
+Priority: low
+Discovered-by:
+Assigned-to:
+CVSS:
+
+Patches_gnupg:
+upstream_gnupg: needs-triage
+esm-infra/xenial_gnupg: deferred (2022-09-28)
+trusty_gnupg: ignored (out of standard support)
+xenial_gnupg: ignored (out of standard support)
+bionic_gnupg: DNE
+focal_gnupg: DNE
+jammy_gnupg: DNE
+trusty/esm_gnupg: deferred (2022-09-28)
+
+Patches_gnupg2:
+ other: https://dev.gnupg.org/D556
+upstream_gnupg2: needs-triage
+esm-infra/xenial_gnupg2: deferred (2022-09-28)
+trusty_gnupg2: ignored (out of standard support)
+xenial_gnupg2: ignored (end of standard support)
+bionic_gnupg2: deferred (2022-09-28)
+focal_gnupg2: deferred (2022-09-28)
+jammy_gnupg2: deferred (2022-09-28)
+kinetic_gnupg2: deferred (2022-09-28)
+devel_gnupg2: deferred (2022-09-28)
\ No newline at end of file
diff --git a/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2023-32637 b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2023-32637
new file mode 100644
index 0000000..8b88352
--- /dev/null
+++ b/lib/lp/bugs/scripts/uct/tests/sampledata/CVE-2023-32637
@@ -0,0 +1,28 @@
+Candidate: CVE-2023-32637
+PublicDate: 2023-07-25 06:15:00 UTC
+References:
+ https://jvn.jp/en/jp/JVN35897618/
+ https://jbrowse.org/jb2/
+ http://gmod.org/wiki/GBrowse
+ https://www.cve.org/CVERecord?id=CVE-2023-32637
+Description:
+ GBrowse accepts files with any formats uploaded and places them in the area
+ accessible through unauthenticated web requests. Therefore, anyone who can
+ upload files through the product may execute arbitrary code on the server.
+Ubuntu-Description:
+Notes:
+ ccdm94> this has likely been fixed in all 2.x versions.
+Bugs:
+Priority: high
+ This has a high priority because it is a vulnerability that allows a remote
+ attacker to execute code in a machine, and it looks to be easily exploitable
+ given that it involves regular functionalities provided by the application.
+Discovered-by:
+Assigned-to:
+CVSS:
+ nvd: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H [9.8 CRITICAL]
+
+Patches_gbrowse:
+upstream_gbrowse: released (2.56+dfsg-1)
+trusty_gbrowse: ignored (end of standard support)
+xenial_gbrowse: ignored (end of standard support)
diff --git a/lib/lp/bugs/scripts/tests/test_uct.py b/lib/lp/bugs/scripts/uct/tests/test_uct.py
similarity index 100%
rename from lib/lp/bugs/scripts/tests/test_uct.py
rename to lib/lp/bugs/scripts/uct/tests/test_uct.py
diff --git a/lib/lp/bugs/scripts/tests/test_uctimport.py b/lib/lp/bugs/scripts/uct/tests/test_uctimport.py
similarity index 100%
rename from lib/lp/bugs/scripts/tests/test_uctimport.py
rename to lib/lp/bugs/scripts/uct/tests/test_uctimport.py