Skip to content

Commit b90df84

Browse files
terrikoinosmeet
authored andcommitted
fix: fail gracefully for npm .package-lock.json files (intel#3654)
* fixes intel#3559 npm has a .package-lock.json file with a similar name but slightly different format than the package-lock.json file we can parse with our javascript language parser. This changes the javascript parser so it fails more gracefully if the format of a package-lock.json file does not appear to be what we can parse. As in, it prints a warning that it was unable to parse the file and does not halt the scan. We should probably build a parser to handle these files correctly in the future, but for now this will skip them. Also, I added some docstrings to the files I changed so interrogate would be happy. Signed-off-by: Terri Oda <[email protected]>
1 parent 26a84d1 commit b90df84

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

cve_bin_tool/parsers/javascript.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88

99
class JavascriptParser(Parser):
10+
"""Parser for javascript's package-lock.json files"""
11+
1012
def __init__(self, cve_db, logger):
1113
super().__init__(cve_db, logger)
1214

@@ -23,6 +25,17 @@ def run_checker(self, filename):
2325
vendor = None
2426
if vendor is not None:
2527
yield from vendor
28+
29+
# If there is no "dependencies" array then this file is likely not in a format we
30+
# can parse. Log warning and abort.
31+
# npm generates a similarly named .package-lock.js file (note the starting `.`)
32+
# that will trigger this
33+
if "dependencies" not in data.keys():
34+
self.logger.warning(
35+
f"Cannot parse {self.filename}: no dependencies array found."
36+
)
37+
return
38+
2639
# Now process dependencies
2740
for i in data["dependencies"]:
2841
# To handle @actions/<product>: lines, extract product name from line

test/language_data/.package-lock.json

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/test_language_scanner.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414

1515
class TestLanguageScanner:
16+
"""Tests for various language scanners"""
17+
1618
TEST_FILE_PATH = Path(__file__).parent.resolve() / "language_data"
1719

1820
JAVASCRIPT_PRODUCTS = [
@@ -168,6 +170,7 @@ def setup_class(cls):
168170
(((str(TEST_FILE_PATH / "pom.xml")), ["jmeter", "hamcrest"]),),
169171
)
170172
def test_java_package(self, filename: str, product_list: set[str]) -> None:
173+
"""Test against a valid pom.xml file for Java packages"""
171174
scanner = VersionScanner()
172175
scanner.file_stack.append(filename)
173176
# check list of product_names
@@ -181,6 +184,7 @@ def test_java_package(self, filename: str, product_list: set[str]) -> None:
181184
"filename", ((str(TEST_FILE_PATH / "fail-package-lock.json")),)
182185
)
183186
def test_javascript_package_none_found(self, filename: str) -> None:
187+
"""Test an invalid package-lock.json file"""
184188
scanner = VersionScanner()
185189
scanner.file_stack.append(filename)
186190
product = None
@@ -189,6 +193,20 @@ def test_javascript_package_none_found(self, filename: str) -> None:
189193
pass
190194
assert product is not None
191195

196+
def test_invalid_npm_package(self) -> None:
197+
"""
198+
A test for an npm .package-lock.json file.
199+
Currently we can't parse those, so it should generate a warning,
200+
return no output but not fail
201+
"""
202+
203+
scanner = VersionScanner()
204+
scanner_output = scanner.scan_file(
205+
str(self.TEST_FILE_PATH / ".package-lock.json")
206+
)
207+
for entry in scanner_output:
208+
assert entry is None
209+
192210
@pytest.mark.parametrize(
193211
"filename",
194212
[
@@ -197,6 +215,7 @@ def test_javascript_package_none_found(self, filename: str) -> None:
197215
],
198216
)
199217
def test_language_package_none_found(self, filename: str) -> None:
218+
"""Test for cases where no products match a vendor in the database"""
200219
scanner = VersionScanner()
201220
scanner.file_stack.append(filename)
202221
product = None
@@ -220,6 +239,7 @@ def test_language_package_none_found(self, filename: str) -> None:
220239
],
221240
)
222241
def test_language_package(self, filename: str, products: set[str]) -> None:
242+
"""Test valid language product list files"""
223243
scanner = VersionScanner()
224244
scanner.file_stack.append(filename)
225245
found_product = []
@@ -236,6 +256,7 @@ def test_language_package(self, filename: str, products: set[str]) -> None:
236256

237257
@pytest.mark.parametrize("filename", ((str(TEST_FILE_PATH / "PKG-INFO")),))
238258
def test_python_package(self, filename: str) -> None:
259+
"""Test against python's PKG-INFO metadata file"""
239260
scanner = VersionScanner()
240261
scanner.file_stack.append(filename)
241262
for product in scanner.scan_file(filename):

0 commit comments

Comments
 (0)