Skip to content

Commit 0f24b06

Browse files
authored
fix: rpm extractor for windows (#1696)
1 parent 09ebae5 commit 0f24b06

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

cve_bin_tool/extractor.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,16 @@ async def extract_file_rpm(self, filename, extraction_path):
106106
if stderr or not stdout:
107107
return 1
108108
filenames = await aio_glob(os.path.join(extraction_path, "*.cpio"))
109+
if not filenames:
110+
filenames = await aio_glob(
111+
os.path.join(extraction_path, "*.cpio.zstd")
112+
)
113+
filename = filenames[0]
114+
exit_code = await self.extract_file_zst(filename, extraction_path)
115+
if exit_code:
116+
return 1
117+
filenames = await aio_glob(os.path.join(extraction_path, "*.cpio"))
109118
filename = filenames[0]
110-
111119
stdout, stderr, _ = await aio_run_command(["7z", "x", filename])
112120
if stderr or not stdout:
113121
return 1
@@ -118,11 +126,19 @@ async def extract_file_zst(self, filename: str, extraction_path: str) -> int:
118126

119127
dctx = zstandard.ZstdDecompressor()
120128
with ErrorHandler(mode=ErrorMode.Ignore) as e:
121-
with open(filename, "rb") as f:
122-
with dctx.stream_reader(f) as reader:
123-
with tarfile.open(mode="r|", fileobj=reader) as tar:
124-
tar.extractall(extraction_path)
125-
tar.close()
129+
if filename.endswith(".cpio.zstd"):
130+
with open(filename, "rb") as compressed:
131+
base = os.path.basename(filename)
132+
file = os.path.splitext(base)[0]
133+
output_path = os.path.join(extraction_path, file)
134+
with open(output_path, "wb") as destination:
135+
dctx.copy_stream(compressed, destination)
136+
else:
137+
with open(filename, "rb") as f:
138+
with dctx.stream_reader(f) as reader:
139+
with tarfile.open(mode="r|", fileobj=reader) as tar:
140+
tar.extractall(extraction_path)
141+
tar.close()
126142
return e.exit_code
127143

128144
async def extract_file_pkg(self, filename: str, extraction_path: str) -> int:

test/test_extractor.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
# import logging
2323
# logging.basicConfig(level=logging.DEBUG)
2424

25+
DOVECOT_FILE_PATH = path.join(
26+
path.abspath(path.dirname(__file__)),
27+
"condensed-downloads",
28+
"dovecot-2.3.14-1.fc34.i686.rpm",
29+
)
2530
CAB_TEST_FILE_PATH = path.join(
2631
path.abspath(path.dirname(__file__)), "assets", "cab-test-python3.8.cab"
2732
)
@@ -140,6 +145,27 @@ async def test_extract_file_rpm_no_rpm2cipo(self, extension_list: List[str]):
140145
mock_aio_run_command.assert_not_called()
141146

142147

148+
class TestExtractFileRpmWithZstd(TestExtractorBase):
149+
"""Tests for the rpm file extractor (zstd/windows)"""
150+
151+
@classmethod
152+
def setup_class(cls):
153+
super().setup_class()
154+
shutil.copyfile(DOVECOT_FILE_PATH, path.join(cls.tempdir, "test.rpm"))
155+
156+
@pytest.fixture
157+
def extension_list(self) -> List[str]:
158+
return self.extractor.file_extractors[self.extractor.extract_file_rpm]
159+
160+
@pytest.mark.asyncio
161+
async def test_extract_file_rpm(self, extension_list: List[str]):
162+
"""Test the rpm file extraction in windows with zstd"""
163+
async for extracted_path in self.extract_files(
164+
[f"test{extension}" for extension in extension_list]
165+
):
166+
assert path.isfile(path.join(extracted_path, "usr", "sbin", "dovecot"))
167+
168+
143169
class TestExtractFileDeb(TestExtractorBase):
144170
"""Tests for deb file extractor"""
145171

0 commit comments

Comments
 (0)