← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~enriqueesanchz/launchpad:add-cve-tags into launchpad:master

 

Enrique Sánchez has proposed merging ~enriqueesanchz/launchpad:add-cve-tags into launchpad:master.

Commit message:
Add SVT `global_tags` support to uctimport/uctexport

Add `global_tags` field to `uct/models.py`
Add SVT `global_tags` tests
Updated `cve_lib` from `ubuntu-cve-tracker` to support `Tags:`

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~enriqueesanchz/launchpad/+git/launchpad/+merge/485186
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~enriqueesanchz/launchpad:add-cve-tags into launchpad:master.
diff --git a/lib/contrib/cve_lib.py b/lib/contrib/cve_lib.py
index 863bdee..bd8b30d 100644
--- a/lib/contrib/cve_lib.py
+++ b/lib/contrib/cve_lib.py
@@ -15,6 +15,8 @@ from collections import OrderedDict
 
 import yaml
 
+GLOBAL_TAGS_KEY = "*"
+
 
 def set_cve_dir(path):
     """Return a path with CVEs in it. Specifically:
@@ -76,8 +78,8 @@ subprojects = {
         "name": "Ubuntu 22.04 LTS for NVIDIA BlueField",
         "codename": "Jammy Jellyfish",
         "ppas": [
-                 {"ppa": "canonical-kernel-bluefield/release", "pocket": "release"}
-                ],
+            {"ppa": "canonical-kernel-bluefield/release", "pocket": "release"}
+        ],
         "parent": "ubuntu/jammy",
         "description": "Available for NVIDIA BlueField platforms",
     },
@@ -99,9 +101,12 @@ subprojects = {
         "name": "Ubuntu 12.04 ESM",
         "codename": "Precise Pangolin",
         "alias": "precise/esm",
-        "ppas": [{ "ppa": "ubuntu-esm/esm", "pocket": "security"}],
+        "ppas": [{"ppa": "ubuntu-esm/esm", "pocket": "security"}],
         "parent": "ubuntu/precise",
-        "description": "Available with UA Infra or UA Desktop: https://ubuntu.com/advantage";,
+        "description": (
+            "Available with UA Infra or UA Desktop: "
+            "https://ubuntu.com/advantage";
+        ),
         "stamp": 1493521200,
     },
     "esm/trusty": {
@@ -112,11 +117,13 @@ subprojects = {
         "codename": "Trusty Tahr",
         "alias": "trusty/esm",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-infra-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/trusty",
-        "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";,
+        "description": (
+            "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";
+        ),
         "stamp": 1556593200,
     },
     "esm-infra/xenial": {
@@ -127,11 +134,13 @@ subprojects = {
         "name": "Ubuntu 16.04 LTS",
         "codename": "Xenial Xerus",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-infra-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/xenial",
-        "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";,
+        "description": (
+            "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";
+        ),
         "stamp": 1618963200,
     },
     "esm-infra/bionic": {
@@ -142,26 +151,37 @@ subprojects = {
         "name": "Ubuntu 18.04 LTS",
         "codename": "Bionic Beaver",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-infra-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-infra-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-infra-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/bionic",
-        "description": "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";,
+        "description": (
+            "Available with Ubuntu Pro (Infra-only): https://ubuntu.com/pro";
+        ),
         "stamp": 1685539024,
     },
     "esm-infra-legacy/trusty": {
         "eol": False,
-        "oval": False, #TODO: Change to True when we are ready for generating data
+        "oval": False,
         "packages": ["esm-infra-legacy-trusty-supported.txt"],
         "name": "Ubuntu 14.04 LTS",
         "codename": "Trusty Tahr",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-infra-legacy-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-infra-legacy-updates",  "pocket": "updates"}
-                ],
+            {
+                "ppa": "ubuntu-esm/esm-infra-legacy-security",
+                "pocket": "security",
+            },
+            {
+                "ppa": "ubuntu-esm/esm-infra-legacy-updates",
+                "pocket": "updates",
+            },
+        ],
         "parent": "esm/trusty",
-        "description": "Available with Ubuntu Pro with Legacy support add-on: https://ubuntu.com/pro";,
-        "stamp": None, #TODO: to be calculate when finally public
+        "description": (
+            "Available with Ubuntu Pro with Legacy support add-on: "
+            "https://ubuntu.com/pro";
+        ),
+        "stamp": None,
     },
     "esm-apps/xenial": {
         "eol": False,
@@ -171,9 +191,9 @@ subprojects = {
         "name": "Ubuntu 16.04 LTS",
         "codename": "Xenial Xerus",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-apps-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"},
+        ],
         "parent": "esm-infra/xenial",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
         "stamp": 1618963200,
@@ -186,9 +206,9 @@ subprojects = {
         "name": "Ubuntu 18.04 LTS",
         "codename": "Bionic Beaver",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-apps-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"},
+        ],
         "parent": "esm-infra/bionic",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
         "stamp": 1524870000,
@@ -201,9 +221,9 @@ subprojects = {
         "name": "Ubuntu 20.04 LTS",
         "codename": "Focal Fossa",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-apps-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/focal",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
         "stamp": 1587567600,
@@ -216,9 +236,9 @@ subprojects = {
         "name": "Ubuntu 22.04 LTS",
         "codename": "Jammy Jellyfish",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-apps-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/jammy",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
         "stamp": 1650693600,
@@ -231,9 +251,9 @@ subprojects = {
         "name": "Ubuntu 24.04 LTS",
         "codename": "Noble Numbat",
         "ppas": [
-                 {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
-                 {"ppa": "ubuntu-esm/esm-apps-updates",  "pocket": "updates"}
-                ],
+            {"ppa": "ubuntu-esm/esm-apps-security", "pocket": "security"},
+            {"ppa": "ubuntu-esm/esm-apps-updates", "pocket": "updates"},
+        ],
         "parent": "ubuntu/noble",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
         "stamp": 1714060800,
@@ -244,7 +264,7 @@ subprojects = {
         "packages": ["fips-xenial-supported.txt"],
         "name": "Ubuntu 16.04 FIPS Certified",
         "codename": "Xenial Xerus",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}],
+        "ppas": [{"ppa": "ubuntu-advantage/fips", "pocket": "security"}],
         "parent": "ubuntu/xenial",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -254,7 +274,7 @@ subprojects = {
         "packages": ["fips-bionic-supported.txt"],
         "name": "Ubuntu 18.04 FIPS Certified",
         "codename": "Bionic Beaver",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}],
+        "ppas": [{"ppa": "ubuntu-advantage/fips", "pocket": "security"}],
         "parent": "ubuntu/bionic",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -264,7 +284,7 @@ subprojects = {
         "packages": ["fips-focal-supported.txt"],
         "name": "Ubuntu 20.04 FIPS Certified",
         "codename": "Focal Fossa",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips", "pocket": "security"}],
+        "ppas": [{"ppa": "ubuntu-advantage/fips", "pocket": "security"}],
         "parent": "ubuntu/focal",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -274,7 +294,9 @@ subprojects = {
         "packages": ["fips-updates-xenial-supported.txt"],
         "name": "Ubuntu 16.04 FIPS Compliant",
         "codename": "Xenial Xerus",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}],
+        "ppas": [
+            {"ppa": "ubuntu-advantage/fips-updates", "pocket": "updates"}
+        ],
         "parent": "ubuntu/xenial",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -284,7 +306,9 @@ subprojects = {
         "packages": ["fips-updates-bionic-supported.txt"],
         "name": "Ubuntu 18.04 FIPS Compliant",
         "codename": "Bionic Beaver",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}],
+        "ppas": [
+            {"ppa": "ubuntu-advantage/fips-updates", "pocket": "updates"}
+        ],
         "parent": "ubuntu/bionic",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -294,7 +318,9 @@ subprojects = {
         "packages": ["fips-updates-focal-supported.txt"],
         "name": "Ubuntu 20.04 FIPS Compliant",
         "codename": "Focal Fossa",
-        "ppas": [{"ppa" : "ubuntu-advantage/fips-updates", "pocket": "updates"}],
+        "ppas": [
+            {"ppa": "ubuntu-advantage/fips-updates", "pocket": "updates"}
+        ],
         "parent": "ubuntu/focal",
         "description": "Available with Ubuntu Pro: https://ubuntu.com/pro";,
     },
@@ -305,9 +331,16 @@ subprojects = {
         "name": "Ubuntu 16.04 ROS ESM",
         "codename": "Xenial Xerus",
         "alias": "ros-esm/xenial",
-        "ppas": [{"ppa": "ubuntu-robotics-packagers/ros-security", "pocket": "security"}],
+        "ppas": [
+            {
+                "ppa": "ubuntu-robotics-packagers/ros-security",
+                "pocket": "security",
+            }
+        ],
         "parent": "ubuntu/xenial",
-        "description": "Available with Ubuntu Advantage: https://ubuntu.com/advantage";,
+        "description": (
+            "Available with Ubuntu Advantage: https://ubuntu.com/advantage";
+        ),
     },
     "ros-esm/melodic": {
         "eol": False,
@@ -316,9 +349,16 @@ subprojects = {
         "name": "Ubuntu 18.04 ROS ESM",
         "codename": "Bionic Beaver",
         "alias": "ros-esm/bionic",
-        "ppas": [{"ppa": "ubuntu-robotics-packagers/ros-security", "pocket": "security"}],
+        "ppas": [
+            {
+                "ppa": "ubuntu-robotics-packagers/ros-security",
+                "pocket": "security",
+            }
+        ],
         "parent": "ubuntu/bionic",
-        "description": "Available with Ubuntu Advantage: https://ubuntu.com/advantage";,
+        "description": (
+            "Available with Ubuntu Advantage: https://ubuntu.com/advantage";
+        ),
     },
     "ubuntu/warty": {
         "eol": True,
@@ -733,22 +773,22 @@ subprojects = {
         "description": "Long Term Release",
         "stamp": 1714060800,
     },
-   "ubuntu/oracular": {
-       "eol": False,
-       "oval": True,
-       "components": ["main", "restricted", "universe", "multiverse"],
-       "name": "Ubuntu 24.10",
-       "version": 24.10,
-       "codename": "Oracular Oriole",
-       "alias": "oracular",
-       "devel": True,  # there can be only one ⚔
-       "description": "Interim Release",
-   },
+    "ubuntu/oracular": {
+        "eol": False,
+        "oval": True,
+        "components": ["main", "restricted", "universe", "multiverse"],
+        "name": "Ubuntu 24.10",
+        "version": 24.10,
+        "codename": "Oracular Oriole",
+        "alias": "oracular",
+        "devel": True,  # there can be only one ⚔
+        "description": "Interim Release",
+    },
     "snap": {
         "eol": False,
         "oval": False,
         "packages": ["snap-supported.txt"],
-    }
+    },
 }
 
 
@@ -898,7 +938,7 @@ def load_external_subprojects():
         # rel name is the path component between subprojects/ and
         # /supported.txt
         rel = supported_txt[
-            len(subprojects_dir) + 1:-len("supported.txt") - 1
+            len(subprojects_dir) + 1 : -len("supported.txt") - 1
         ]
         external_releases.append(rel)
         subprojects.setdefault(rel, {"packages": [], "eol": False})
@@ -935,7 +975,15 @@ for release in subprojects:
         releases.append(rel)
 
 
-VALID_TAGS = {
+valid_cve_tags = {
+    "cisa-kev": (
+        "This vulnerability is listed in the CISA Known Exploited "
+        "Vulnerabilities Catalog. For more details see "
+        "https://www.cisa.gov/known-exploited-vulnerabilities-catalog";
+    ),
+}
+
+valid_package_tags = {
     "universe-binary": (
         "Binaries built from this source package are in universe and so are "
         "supported by the community. For more details see "
@@ -979,6 +1027,10 @@ VALID_TAGS = {
         "Independent Executables in Ubuntu. For more details see "
         "https://wiki.ubuntu.com/Security/Features#pie";
     ),
+    "review-break-fix": (
+        "This vulnerability automatically received break-fix commits entries "
+        "when it was added and needs to be reviewed."
+    ),
 }
 
 # Possible CVE priorities
@@ -989,6 +1041,7 @@ NOTE_RE = re.compile(r"^\s+([A-Za-z0-9-]+)([>|]) *(.*)$")
 EXIT_FAIL = 1
 EXIT_OKAY = 0
 
+
 # New CVE file format for release package field is:
 # <product>[/<where or who>]_SOFTWARE[/<modifier>]: <status> [(<when>)]
 # <product> is the Canonical product or supporting technology (eg, ‘esm-apps’
@@ -1388,23 +1441,28 @@ def load_cve(cve, strict=False, srcmap=None):
                 continue
             data["patches"].setdefault(pkg, list())
             srcmap["patches"].setdefault(pkg, list())
-        elif "Tags_" in field:
+        elif "Tags" in field:
             """These are processed into the "tags" hash"""
             try:
                 _, pkg = field.split("_", 1)
             except ValueError:
-                msg += "%s: %d: bad field with 'Tags_': '%s'\n" % (
-                    cve,
-                    linenum,
-                    field,
-                )
-                code = EXIT_FAIL
-                continue
+                # no package specified - this is the global tags field - use a
+                # key of '*' to store it in the package hash
+                pkg = GLOBAL_TAGS_KEY
             data["tags"].setdefault(pkg, set())
             srcmap["tags"].setdefault(pkg, (cve, linenum))
             for word in value.strip().split(" "):
-                if word not in VALID_TAGS:
-                    msg += "%s: %d: invalid tag '%s': '%s'\n" % (
+                if pkg == GLOBAL_TAGS_KEY and word not in valid_cve_tags:
+                    msg += "%s: %d: invalid CVE tag '%s': '%s'\n" % (
+                        cve,
+                        linenum,
+                        word,
+                        field,
+                    )
+                    code = EXIT_FAIL
+                    continue
+                elif pkg != GLOBAL_TAGS_KEY and word not in valid_package_tags:
+                    msg += "%s: %d: invalid package tag '%s': '%s'\n" % (
                         cve,
                         linenum,
                         word,
diff --git a/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-23222 b/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-23222
index 95a74f0..8c8a836 100644
--- a/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-23222
+++ b/lib/lp/bugs/scripts/tests/sampledata/CVE-2022-23222
@@ -25,6 +25,7 @@ Bugs:
 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]
 
diff --git a/lib/lp/bugs/scripts/tests/test_uct.py b/lib/lp/bugs/scripts/tests/test_uct.py
index 8ac253a..d2242d5 100644
--- a/lib/lp/bugs/scripts/tests/test_uct.py
+++ b/lib/lp/bugs/scripts/tests/test_uct.py
@@ -160,6 +160,7 @@ class TestUCTRecord(TestCase):
                         patches=[],
                     ),
                 ],
+                global_tags={"cisa-kev"},
             ).__dict__,
             uct_record.__dict__,
         )
@@ -248,6 +249,7 @@ class TestUCTRecord(TestCase):
                         patches=[],
                     ),
                 ],
+                global_tags=set(),
             ).__dict__,
             uct_record.__dict__,
         )
@@ -404,6 +406,7 @@ class TestCVE(TestCaseWithFactory):
                     patches=[],
                 ),
             ],
+            global_tags={"cisa-kev"},
         )
 
         self.cve = CVE(
@@ -539,6 +542,7 @@ class TestCVE(TestCaseWithFactory):
                     notes=None,
                 ),
             ],
+            global_tags={"cisa-kev"},
         )
 
     def test_make_from_uct_record(self):
@@ -781,6 +785,7 @@ class TestUCTImporterExporter(TestCaseWithFactory):
                     notes=None,
                 ),
             ],
+            global_tags={"cisa-kev"},
         )
         self.importer = UCTImporter()
         self.exporter = UCTExporter()
@@ -801,6 +806,8 @@ class TestUCTImporterExporter(TestCaseWithFactory):
         self.assertEqual(len(cve.bug_urls), len(watches))
         self.assertEqual(sorted(cve.bug_urls), sorted(w.url for w in watches))
 
+        self.assertEqual(sorted(bug.tags), sorted(list(cve.global_tags)))
+
         self.checkBugAttachments(bug, cve)
 
     def checkBugTasks(self, bug: Bug, cve: CVE):
@@ -951,6 +958,7 @@ class TestUCTImporterExporter(TestCaseWithFactory):
         self.assertEqual(expected.mitigation, actual.mitigation)
         self.assertListEqual(expected.cvss, actual.cvss)
         self.assertListEqual(expected.patch_urls, actual.patch_urls)
+        self.assertEqual(expected.global_tags, actual.global_tags)
 
     def test_create_bug(self):
         bug = self.importer.create_bug(self.cve, self.lp_cve)
@@ -1047,6 +1055,7 @@ class TestUCTImporterExporter(TestCaseWithFactory):
                 ),
             ],
             patch_urls=[],
+            global_tags={"cisa-kev"},
         )
         lp_cve = self.factory.makeCVE(sequence="2022-1234")
         bug = self.importer.create_bug(cve, lp_cve)
@@ -1260,6 +1269,14 @@ class TestUCTImporterExporter(TestCaseWithFactory):
         self.importer.update_bug(bug, cve, self.lp_cve)
         self.checkBug(bug, cve)
 
+    def test_update_bug_global_tags_changed(self):
+        bug = self.importer.create_bug(self.cve, self.lp_cve)
+        cve = self.cve
+
+        cve.global_tags.add("another-tag")
+        self.importer.update_bug(bug, cve, self.lp_cve)
+        self.checkBug(bug, cve)
+
     def test_update_bug_ubuntu_description_changed(self):
         bug = self.importer.create_bug(self.cve, self.lp_cve)
         cve = self.cve
diff --git a/lib/lp/bugs/scripts/uct/models.py b/lib/lp/bugs/scripts/uct/models.py
index 66130f6..607a018 100644
--- a/lib/lp/bugs/scripts/uct/models.py
+++ b/lib/lp/bugs/scripts/uct/models.py
@@ -65,6 +65,8 @@ class UCTRecord:
     It contains exactly the same information as a UCT CVE record.
     """
 
+    GLOBAL_TAGS_KEY = "*"
+
     class Priority(Enum):
         CRITICAL = "critical"
         HIGH = "high"
@@ -118,6 +120,7 @@ class UCTRecord:
         references: List[str],
         ubuntu_description: str,
         packages: List[Package],
+        global_tags: Set[str],
         priority_explanation: str = "",
     ):
         self.parent_dir = parent_dir
@@ -137,6 +140,7 @@ class UCTRecord:
         self.references = references
         self.ubuntu_description = ubuntu_description
         self.packages = packages
+        self.global_tags = global_tags
 
     def __eq__(self, other):
         if not isinstance(other, UCTRecord):
@@ -158,6 +162,8 @@ class UCTRecord:
 
         packages = []
         tags: Dict[str, Set[str]] = cls._pop_cve_property(cve_data, "tags")
+        global_tags = tags.pop(cls.GLOBAL_TAGS_KEY, set())
+
         patches: Dict[str, List[Tuple[str, str]]] = cls._pop_cve_property(
             cve_data, "patches"
         )
@@ -267,6 +273,7 @@ class UCTRecord:
                 cve_data, "Ubuntu-Description"
             ),
             packages=packages,
+            global_tags=global_tags,
         )
 
         # make sure all fields are consumed
@@ -317,6 +324,8 @@ class UCTRecord:
         )
         self._write_field("Discovered-by", self.discovered_by, output)
         self._write_field("Assigned-to", self.assigned_to, output)
+        if self.global_tags:
+            self._write_field("Tags", " ".join(self.global_tags), output)
         self._write_field(
             "CVSS",
             [
@@ -511,6 +520,7 @@ class CVE:
         notes: str,
         mitigation: str,
         cvss: List[CVSS],
+        global_tags: Set[str],
         patch_urls: Optional[List[PatchURL]] = None,
         importance_explanation: str = "",
     ):
@@ -533,6 +543,7 @@ class CVE:
         self.notes = notes
         self.mitigation = mitigation
         self.cvss = cvss
+        self.global_tags = global_tags
         self.patch_urls: List[CVE.PatchURL] = patch_urls or []
 
     @classmethod
@@ -679,6 +690,7 @@ class CVE:
             notes=uct_record.notes,
             mitigation=uct_record.mitigation,
             cvss=uct_record.cvss,
+            global_tags=uct_record.global_tags,
             patch_urls=patch_urls,
         )
 
@@ -799,6 +811,7 @@ class CVE:
             priority_explanation=self.importance_explanation,
             references=self.references,
             ubuntu_description=self.ubuntu_description,
+            global_tags=self.global_tags,
             packages=list(packages_by_name.values()),
         )
 
diff --git a/lib/lp/bugs/scripts/uct/uctexport.py b/lib/lp/bugs/scripts/uct/uctexport.py
index 37ad4c0..937860f 100644
--- a/lib/lp/bugs/scripts/uct/uctexport.py
+++ b/lib/lp/bugs/scripts/uct/uctexport.py
@@ -249,6 +249,7 @@ class UCTExporter:
                 for authority in lp_cve.cvss
                 for vector_string in lp_cve.cvss[authority]
             ],
+            global_tags=set(bug.tags),
             patch_urls=patch_urls,
         )
 
diff --git a/lib/lp/bugs/scripts/uct/uctimport.py b/lib/lp/bugs/scripts/uct/uctimport.py
index 76f3294..e9f1dde 100644
--- a/lib/lp/bugs/scripts/uct/uctimport.py
+++ b/lib/lp/bugs/scripts/uct/uctimport.py
@@ -171,6 +171,7 @@ class UCTImporter:
                 target=distro_package.target,
                 importance=distro_package.importance,
                 cve=lp_cve,
+                tags=cve.global_tags,
             )
         )
 
@@ -234,6 +235,8 @@ class UCTImporter:
         self._update_external_bug_urls(bug, cve.bug_urls)
         self._update_patches(bug, cve.patch_urls)
 
+        bug.tags = cve.global_tags
+
         # Update or add new Vulnerabilities
         vulnerabilities_by_distro = {
             v.distribution: v for v in bug.vulnerabilities

References