launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #32935
[Merge] ~enriqueesanchz/launchpad:fix-update-cve-exception into launchpad:master
Enrique Sánchez has proposed merging ~enriqueesanchz/launchpad:fix-update-cve-exception into launchpad:master.
Commit message:
Fix empty delta zip raising an Exception
There are some times where the delta zip release from
CVEProject/cvelistV5 is empty because there were no changes. We avoid
raising an LaunchpadScriptFailure due to that.
Default cve references content to url.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~enriqueesanchz/launchpad/+git/launchpad/+merge/491899
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~enriqueesanchz/launchpad:fix-update-cve-exception into launchpad:master.
diff --git a/lib/lp/bugs/scripts/cveimport.py b/lib/lp/bugs/scripts/cveimport.py
index 66a6dcd..99fe66b 100644
--- a/lib/lp/bugs/scripts/cveimport.py
+++ b/lib/lp/bugs/scripts/cveimport.py
@@ -374,6 +374,16 @@ class CVEUpdater(LaunchpadCronScript):
# extract the outer zip file
with zipfile.ZipFile(outer_zip_path) as outer_zf:
if delta:
+ target_dir = os.path.join(temp_dir, "deltaCves")
+
+ # If there are no delta cves, we return an empty dir
+ if not outer_zf.namelist():
+ self.logger.info(
+ "Zip file is empty: there are no delta changes"
+ )
+ os.mkdir(target_dir)
+ return target_dir
+
# for delta, extract deltacves directory
members = [
m
@@ -381,7 +391,6 @@ class CVEUpdater(LaunchpadCronScript):
if m.startswith("deltaCves/")
]
outer_zf.extractall(temp_dir, members=members)
- target_dir = os.path.join(temp_dir, "deltaCves")
else:
# for baseline, handle nested zip structure
outer_zf.extract("cves.zip", temp_dir)
@@ -729,6 +738,9 @@ class CVEUpdater(LaunchpadCronScript):
source = "external" # default source
content = ref.get("name", "")
+ if not content:
+ content = url
+
# look for existing reference
was_there_previously = False
for old_ref in old_references:
diff --git a/lib/lp/bugs/scripts/tests/test_cveimport.py b/lib/lp/bugs/scripts/tests/test_cveimport.py
index f39c7e6..07f4550 100644
--- a/lib/lp/bugs/scripts/tests/test_cveimport.py
+++ b/lib/lp/bugs/scripts/tests/test_cveimport.py
@@ -4,8 +4,10 @@
import gzip
import io
import json
+import os
import shutil
import tempfile
+import zipfile
from datetime import datetime, timezone
from pathlib import Path
@@ -203,6 +205,20 @@ class TestCVEUpdater(TestCase):
self.assertIsNotNone(cve)
self.assertEqual("Delta CVE", cve.description)
+ def test_process_delta_directory_empty(self):
+ """Test processing an empty directory of delta CVE files."""
+ # Create empty test delta directory
+ delta_dir = Path(self.temp_dir) / "deltaCves"
+ delta_dir.mkdir()
+
+ # Process the directory using the script infrastructure
+ updater = self.make_updater([str(delta_dir)])
+ processed, errors = updater.process_delta_directory(str(delta_dir))
+
+ # Verify results
+ self.assertEqual(0, processed)
+ self.assertEqual(0, errors)
+
def test_construct_github_url(self):
"""Test GitHub URL construction for different scenarios."""
updater = CVEUpdater(
@@ -262,3 +278,66 @@ class TestCVEUpdater(TestCase):
# Verify the update
updated_cve = cveset["2024-0004"]
self.assertEqual(new_desc, updated_cve.description)
+
+ def test_extract_github_zip(self):
+ """Test extract_github_zip for complete releases."""
+ updater = self.make_updater()
+ outer_buffer = io.BytesIO()
+
+ with zipfile.ZipFile(outer_buffer, "w") as outer_zip:
+ # create inner cves.zip in memory
+ inner_buffer = io.BytesIO()
+ with zipfile.ZipFile(inner_buffer, "w") as inner_zip:
+ inner_zip.writestr("cves/CVE-2025-8941.json", "CVE data")
+ outer_zip.writestr("cves.zip", inner_buffer.getvalue())
+
+ target_dir = updater.extract_github_zip(outer_buffer.getvalue())
+ self.assertTrue(target_dir.endswith("cves"))
+ self.assertEqual(os.listdir(target_dir), ["CVE-2025-8941.json"])
+
+ def test_extract_empty_github_zip(self):
+ """Test that extract_github_zip for complete releases raises
+ LaunchpadScriptFailure when the zip is empty.
+ """
+ updater = self.make_updater()
+ buffer = io.BytesIO()
+
+ # Empty zipfile buffer
+ with zipfile.ZipFile(buffer, "w"):
+ pass
+
+ self.assertRaisesWithContent(
+ LaunchpadScriptFailure,
+ "Failed to extract ZIP files: \"There is no item named 'cves.zip' "
+ 'in the archive"',
+ updater.extract_github_zip,
+ buffer.getvalue(),
+ )
+
+ def test_extract_delta_github_zip(self):
+ """Test extract_github_zip for delta releases."""
+ updater = self.make_updater()
+ buffer = io.BytesIO()
+
+ with zipfile.ZipFile(buffer, "w") as zf:
+ zf.writestr("deltaCves/CVE-2025-8941.json", "delta CVE data")
+
+ empty_dir = updater.extract_github_zip(buffer.getvalue(), delta=True)
+ self.assertTrue(empty_dir.endswith("deltaCves"))
+ self.assertEqual(os.listdir(empty_dir), ["CVE-2025-8941.json"])
+
+ def test_extract_empty_delta_github_zip(self):
+ """Test that extract_github_zip for delta releases returns an empty dir
+ if the zip is empty. There can be hours when no cves are updated so we
+ will return an empty dir and will not import cves.
+ """
+ updater = self.make_updater()
+ buffer = io.BytesIO()
+
+ # Empty zipfile buffer
+ with zipfile.ZipFile(buffer, "w"):
+ pass
+
+ empty_dir = updater.extract_github_zip(buffer.getvalue(), delta=True)
+ self.assertTrue(empty_dir.endswith("deltaCves"))
+ self.assertEqual(os.listdir(empty_dir), [])