← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~ilkeremrekoc/launchpad:add-extra-attrs into launchpad:master

 

İlker Emre Koç has proposed merging ~ilkeremrekoc/launchpad:add-extra-attrs into launchpad:master.

Commit message:
Add extra_attrs metadata to vulnerabilities

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~ilkeremrekoc/launchpad/+git/launchpad/+merge/493278

Modified SOSSRecord, SOSSImporter and SOSSExporter to add Extra_attrs
yaml field to each created bugtasks' metadata field.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilkeremrekoc/launchpad:add-extra-attrs into launchpad:master.
diff --git a/lib/lp/bugs/scripts/soss/models.py b/lib/lp/bugs/scripts/soss/models.py
index 5b8a273..09e179b 100644
--- a/lib/lp/bugs/scripts/soss/models.py
+++ b/lib/lp/bugs/scripts/soss/models.py
@@ -123,6 +123,7 @@ class SOSSRecord(SVTRecord):
     description: Optional[str] = None
     cvss: Optional[List[CVSS]] = None
     public_date: Optional[datetime] = None
+    extra_attrs: Optional[Dict[str, Any]] = None
 
     @classmethod
     def from_str(cls, string: str) -> "SOSSRecord":
@@ -189,6 +190,7 @@ class SOSSRecord(SVTRecord):
             description=raw.get("Description"),
             cvss=cvss_list,
             public_date=public_date,
+            extra_attrs=raw.get("Extra_attrs"),
         )
 
     def to_dict(self) -> Dict[str, Any]:
@@ -215,6 +217,8 @@ class SOSSRecord(SVTRecord):
             serialized["PublicDate"] = self.public_date.isoformat(
                 sep="T", timespec="milliseconds"
             )
+        if self.extra_attrs:
+            serialized["Extra_attrs"] = self.extra_attrs
 
         return serialized
 
diff --git a/lib/lp/bugs/scripts/soss/sossexport.py b/lib/lp/bugs/scripts/soss/sossexport.py
index c158dd3..3e3a744 100644
--- a/lib/lp/bugs/scripts/soss/sossexport.py
+++ b/lib/lp/bugs/scripts/soss/sossexport.py
@@ -114,6 +114,11 @@ class SOSSExporter(SVTExporter):
         assigned_to = (
             bug.bugtasks[0].assignee.name if bug.bugtasks[0].assignee else ""
         )
+        extra_attrs = (
+            bug.bugtasks[0].metadata.get("extra_attrs")
+            if bug.bugtasks[0].metadata
+            else None
+        )
 
         # Parse vulnerability
         public_date = self._normalize_date_without_timezone(
@@ -135,6 +140,7 @@ class SOSSExporter(SVTExporter):
             description=vulnerability.description,
             cvss=self._get_cvss(vulnerability.cvss),
             public_date=public_date,
+            extra_attrs=extra_attrs,
         )
 
     def _format_notes(self, notes: str) -> List[Union[Dict, str]]:
diff --git a/lib/lp/bugs/scripts/soss/sossimport.py b/lib/lp/bugs/scripts/soss/sossimport.py
index 2bb7c17..7491cb3 100644
--- a/lib/lp/bugs/scripts/soss/sossimport.py
+++ b/lib/lp/bugs/scripts/soss/sossimport.py
@@ -168,6 +168,9 @@ class SOSSImporter(SVTImporter):
         )
         metadata = {"repositories": package.repositories}
 
+        if soss_record.extra_attrs:
+            metadata["extra_attrs"] = soss_record.extra_attrs
+
         # Create the bug, only first bugtask
         bug, _ = removeSecurityProxy(
             self.bug_set.createBug(
@@ -357,6 +360,11 @@ class SOSSImporter(SVTImporter):
                     else None
                 )
 
+                if soss_record.extra_attrs:
+                    if metadata is None:
+                        metadata = {}
+                    metadata["extra_attrs"] = soss_record.extra_attrs
+
                 if target not in bugtask_by_target:
                     bugtask = removeSecurityProxy(
                         self.bugtask_set.createTask(
diff --git a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000 b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000
index 76ce151..97e27a9 100644
--- a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000
+++ b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000
@@ -13,3 +13,5 @@ Packages:
     Status: ignored
     Note: ''
 Candidate: CVE-2011-5000
+Extra_attrs:
+  Custom_attr_1_nvd_score_arrivial_time: '2012-09-09T25:21:39Z'
diff --git a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2025-1979 b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2025-1979
index 904ea32..1648012 100644
--- a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2025-1979
+++ b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2025-1979
@@ -79,3 +79,6 @@ CVSS:
   baseScore: 9.0
   baseSeverity: CRITICAL
 PublicDate: '2025-03-06T05:15:16.213'
+Extra_attrs:
+  Custom_attr_1_nvd_score_arrivial_time: '2025-08-03T23:21:39Z'
+  Custom_attr_2_assigned_to_someone_time: '2025-08-10T11:22:33Z'
diff --git a/lib/lp/bugs/scripts/soss/tests/test_sossimport.py b/lib/lp/bugs/scripts/soss/tests/test_sossimport.py
index 675da82..d939dde 100644
--- a/lib/lp/bugs/scripts/soss/tests/test_sossimport.py
+++ b/lib/lp/bugs/scripts/soss/tests/test_sossimport.py
@@ -69,6 +69,10 @@ class TestSOSSImporter(TestCaseWithFactory):
         pyyaml = self.source_package_name_set.getOrCreateByName("pyyaml")
         ray = self.source_package_name_set.getOrCreateByName("ray")
         vllm = self.source_package_name_set.getOrCreateByName("vllm")
+        extra_attry = {
+            "Custom_attr_1_nvd_score_arrivial_time": "2025-08-03T23:21:39Z",
+            "Custom_attr_2_assigned_to_someone_time": "2025-08-10T11:22:33Z",
+        }
 
         self.bugtask_reference = [
             (
@@ -79,7 +83,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.INVALID,
                 "",
-                {"repositories": ["nvidia-pb3-python-stable-local"]},
+                {
+                    "repositories": ["nvidia-pb3-python-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
             (
                 self.soss.getExternalPackage(
@@ -89,7 +96,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.INVALID,
                 "2.22.0+soss.1",
-                {"repositories": ["nvidia-pb3-python-stable-local"]},
+                {
+                    "repositories": ["nvidia-pb3-python-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
             (
                 self.soss.getExternalPackage(
@@ -99,7 +109,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.FIXRELEASED,
                 "2.22.0+soss.1",
-                {"repositories": ["nvidia-pb3-python-stable-local"]},
+                {
+                    "repositories": ["nvidia-pb3-python-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
             (
                 self.soss.getExternalPackage(
@@ -109,7 +122,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.DEFERRED,
                 "2.22.0+soss.1",
-                {"repositories": ["nvidia-pb3-python-stable-local"]},
+                {
+                    "repositories": ["nvidia-pb3-python-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
             (
                 self.soss.getExternalPackage(
@@ -119,7 +135,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.UNKNOWN,
                 "",
-                {"repositories": ["soss-src-stable-local"]},
+                {
+                    "repositories": ["soss-src-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
             (
                 self.soss.getExternalPackage(
@@ -129,7 +148,10 @@ class TestSOSSImporter(TestCaseWithFactory):
                 ),
                 BugTaskStatus.NEW,
                 "",
-                {"repositories": ["soss-src-stable-local"]},
+                {
+                    "repositories": ["soss-src-stable-local"],
+                    "extra_attrs": extra_attry,
+                },
             ),
         ]
 
@@ -197,7 +219,7 @@ class TestSOSSImporter(TestCaseWithFactory):
 
         self._check_bugtasks(
             bug.bugtasks,
-            self.bugtask_reference,
+            bugtask_reference,
             BugTaskImportance.LOW,
             self.janitor,
         )
@@ -378,7 +400,10 @@ class TestSOSSImporter(TestCaseWithFactory):
             ),
             BugTaskStatus.DEFERRED,
             "test note",
-            {"repositories": ["test-repo"]},
+            {
+                "repositories": ["test-repo"],
+                "extra_attrs": self.bugtask_reference[2][3].get("extra_attrs"),
+            },  # extra_attrs remains the same as it is bound to the bug
         )
 
         soss_importer._create_or_update_bugtasks(bug, self.soss_record)
diff --git a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
index c8405d6..fd2afc5 100644
--- a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
+++ b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
@@ -141,6 +141,10 @@ class TestSOSSRecord(TestCase):
                 ),
             ],
             public_date=datetime.fromisoformat("2025-03-06T05:15:16.213"),
+            extra_attrs={
+                "Custom_attr_1_nvd_score_arrivial_date": "2025-08-03",
+                "Custom_attr_2_assigned_time": "2025-08-10T11:22:33Z",
+            },
         )
 
         self.soss_record_dict = {
@@ -265,6 +269,10 @@ class TestSOSSRecord(TestCase):
                 },
             ],
             "PublicDate": "2025-03-06T05:15:16.213",
+            "Extra_attrs": {
+                "Custom_attr_1_nvd_score_arrivial_date": "2025-08-03",
+                "Custom_attr_2_assigned_time": "2025-08-10T11:22:33Z",
+            },
         }
 
     def test_from_dict(self):
@@ -323,6 +331,17 @@ class TestSOSSRecord(TestCase):
         soss_record = SOSSRecord.from_dict(self.soss_record_dict)
         self.assertEqual(self.soss_record, soss_record)
 
+    def test_from_dict_no_extra_attrs(self):
+        """Ensure that without Extra_attrs in input, soss_record.extra_attrs
+        is None.
+        """
+        self.soss_record_dict.pop("Extra_attrs")
+
+        soss_record = SOSSRecord.from_dict(self.soss_record_dict)
+
+        self.soss_record.extra_attrs = None
+        self.assertEqual(self.soss_record, soss_record)
+
     def test_from_yaml(self):
         load_from = Path(__file__).parent / "sampledata" / "CVE-2025-1979"
 

Follow ups