launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #32608
[Merge] ~enriqueesanchz/launchpad:soss-export-parsing into launchpad:master
Enrique Sánchez has proposed merging ~enriqueesanchz/launchpad:soss-export-parsing into launchpad:master.
Commit message:
Add soss-cve-tracker export parsing layer
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~enriqueesanchz/launchpad/+git/launchpad/+merge/487080
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~enriqueesanchz/launchpad:soss-export-parsing into launchpad:master.
diff --git a/lib/lp/bugs/scripts/soss/models.py b/lib/lp/bugs/scripts/soss/models.py
index 4d63a2c..dd942e3 100644
--- a/lib/lp/bugs/scripts/soss/models.py
+++ b/lib/lp/bugs/scripts/soss/models.py
@@ -50,6 +50,9 @@ class SOSSRecord:
if not VALID_CHANNEL_REGEX.match(self.value):
raise ValueError(f"Invalid channel format: {self.value}")
+ def __str__(self):
+ return self.value
+
@dataclass
class CVSS:
source: str
@@ -67,6 +70,14 @@ class SOSSRecord:
f"Invalid base severity: {self.base_severity}"
)
+ def to_dict(self):
+ return {
+ "source": self.source,
+ "vector": self.vector,
+ "baseScore": self.base_score,
+ "baseSeverity": self.base_severity,
+ }
+
@dataclass
class Package:
name: str
@@ -75,6 +86,15 @@ class SOSSRecord:
status: "SOSSRecord.PackageStatusEnum"
note: str
+ def to_dict(self):
+ return {
+ "Name": self.name,
+ "Channel": str(self.channel),
+ "Repositories": self.repositories,
+ "Status": self.status.value,
+ "Note": self.note,
+ }
+
references: List[str]
notes: List[str]
priority: PriorityEnum
@@ -144,3 +164,32 @@ class SOSSRecord:
cvss=cvss_list,
public_date=public_date,
)
+
+ def to_dict(self) -> dict:
+ serialized = {
+ "References": self.references,
+ "Notes": self.notes,
+ "Priority": self.priority.value,
+ "Priority-Reason": self.priority_reason,
+ "Assigned-To": self.assigned_to,
+ "Packages": {
+ key.value: [p.to_dict() for p in pkg_list]
+ for key, pkg_list in self.packages.items()
+ },
+ }
+
+ if self.candidate:
+ serialized["Candidate"] = self.candidate
+ if self.description:
+ serialized["Description"] = self.description
+ if self.cvss:
+ serialized["CVSS"] = [cvss.to_dict() for cvss in self.cvss]
+ if self.public_date:
+ serialized["PublicDate"] = self.public_date.isoformat(
+ sep="T", timespec="milliseconds"
+ )
+
+ return serialized
+
+ def to_yaml(self) -> str:
+ return yaml.dump(self.to_dict(), sort_keys=False)
diff --git a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2005-1544 b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2005-1544
new file mode 100644
index 0000000..8788e47
--- /dev/null
+++ b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2005-1544
@@ -0,0 +1,33 @@
+References: []
+Notes: []
+Priority: Needs-triage
+Priority-Reason: ''
+Assigned-To: ''
+Packages:
+ conda:
+ - Name: libtiff
+ Channel: focal:4.5.0-h6adf6a1/stable
+ Repositories:
+ - soss-conda-candidate-local
+ Status: ignored
+ Note: ''
+ - Name: opencv
+ Channel: focal:4.5.3-py39hf3d152e/stable
+ Repositories:
+ - soss-conda-stable-local
+ - soss-conda-candidate-local
+ Status: ignored
+ Note: ''
+ unpackaged:
+ - Name: opencv
+ Channel: jammy:4.8.0/stable
+ Repositories:
+ - soss-src-stable-local
+ Status: ignored
+ Note: ''
+ - Name: opencv
+ Channel: jammy:4.7.0/stable
+ Repositories:
+ - soss-src-stable-local
+ Status: ignored
+ Note: ''
diff --git a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000 b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000
new file mode 100644
index 0000000..e92427b
--- /dev/null
+++ b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2011-5000
@@ -0,0 +1,14 @@
+References: []
+Notes: []
+Priority: Needs-triage
+Priority-Reason: ''
+Assigned-To: ''
+Packages:
+ conda:
+ - Name: openssh
+ Channel: focal:8.6p1-h1fa914a/stable
+ Repositories:
+ - soss-conda-src-local
+ - soss-conda-stable-local
+ Status: ignored
+ Note: ''
diff --git a/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2021-21300 b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2021-21300
new file mode 100644
index 0000000..0a68496
--- /dev/null
+++ b/lib/lp/bugs/scripts/soss/tests/sampledata/CVE-2021-21300
@@ -0,0 +1,13 @@
+References: []
+Notes: []
+Priority: Needs-triage
+Priority-Reason: ''
+Assigned-To: ''
+Packages:
+ conda:
+ - Name: git
+ Channel: focal:2.32.0-pl5321hc30692c/stable
+ Repositories:
+ - soss-conda-candidate-local
+ Status: ignored
+ Note: was ignored
diff --git a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
index a26cad7..eb1fec5 100644
--- a/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
+++ b/lib/lp/bugs/scripts/soss/tests/test_sossrecord.py
@@ -1,5 +1,6 @@
# Copyright 2025 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+import os
from datetime import datetime
from pathlib import Path
@@ -10,6 +11,10 @@ from lp.testing import TestCase
class TestSOSSRecord(TestCase):
maxDiff = None
+ def get_sample_files(self):
+ directory = Path(__file__).parent / "sampledata"
+ return [directory / f for f in os.listdir(directory)]
+
def setUp(self, *args, **kwargs):
super().setUp(*args, **kwargs)
@@ -273,3 +278,29 @@ class TestSOSSRecord(TestCase):
soss_record = SOSSRecord.from_yaml(f)
self.assertEqual(self.soss_record, soss_record)
+
+ def test_to_dict(self):
+ self.assertDictEqual(
+ self.soss_record.to_dict(),
+ self.soss_record_dict,
+ )
+
+ def test_to_yaml(self):
+ load_from = Path(__file__).parent / "sampledata" / "CVE-2025-1979-full"
+ with open(load_from) as f:
+ sample_data = f.read()
+
+ self.assertEqual(self.soss_record.to_yaml(), sample_data),
+
+ def parse_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())
+
+ def test_parse_import_export_yaml(self):
+ files = self.get_sample_files()
+
+ for f in files:
+ self.parse_import_export_yaml(f)