Skip to content

Commit

Permalink
feat(parser): add conan parser (#4569)
Browse files Browse the repository at this point in the history
---------

Signed-off-by: Aryan Bakliwal <aryanbakliwal12345@gmail.com>
Co-authored-by: Terri Oda <terri.oda@intel.com>
  • Loading branch information
AryanBakliwal and terriko authored Dec 18, 2024
1 parent fc85cc8 commit 37f514c
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ codecov
collectd
commons
compress
conan
conda
config
connman
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ NOTKNOWN
pyyaml
skontar
Svunknown
urllib
urllib
1 change: 1 addition & 0 deletions cve_bin_tool/parsers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"perl",
"dart",
"env",
"ccpp",
]


Expand Down
65 changes: 65 additions & 0 deletions cve_bin_tool/parsers/ccpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later
"""Python script containing all functionalities related to parsing of C/C++ conan.lock files."""

import json
import re

from cve_bin_tool.parsers import Parser


class CCppParser(Parser):
"""
Parser for C/C++ conan.lock files based on
https://docs.conan.io/2/tutorial/versioning/lockfiles.html
"""

PARSER_MATCH_FILENAMES = [
"conan.lock",
]

def __init__(self, cve_db, logger):
super().__init__(cve_db, logger)
self.purl_pkg_type = "conan"

def generate_purl(self, product, vendor="", version="", qualifier={}, subpath=None):
"""Generates PURL after normalizing all components."""
product = re.sub(r"[^a-zA-Z0-9._-]", "", product).lower()

if not product:
return None

purl = super().generate_purl(
product,
vendor,
version,
qualifier,
subpath,
)

return purl

def run_checker(self, filename):
"""Parse the file and yield valid PURLs."""
self.filename = filename
with open(self.filename) as fh:
data = json.load(fh)
requires = data["requires"]
build_requires = data["build_requires"]
if requires:
for require in requires:
product = require.split("#")[0].split("/")[0]
version = require.split("#")[0].split("/")[1]
purl = self.generate_purl(product)
vendor = self.get_vendor(purl, product, version)
if vendor is not None:
yield from vendor
if build_requires:
for build_require in build_requires:
product = build_require.split("#")[0].split("/")[0]
version = build_require.split("#")[0].split("/")[1]
purl = self.generate_purl(product)
vendor = self.get_vendor(purl, product, version)
if vendor is not None:
yield from vendor
self.logger.debug(f"Done scanning file: {self.filename}")
9 changes: 8 additions & 1 deletion doc/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
- [Perl](#perl)
- [PHP](#php)
- [Dart](#dart)
- [C/C++](#cc)
- [Feedback \& Contributions](#feedback--contributions)
- [Security Issues](#security-issues)

Expand Down Expand Up @@ -1520,10 +1521,16 @@ Here's an example of what a [`composer.lock`](https://github.com/intel/cve-bin-t

### Dart

The scanner examines the pubspec.lock file, made by Dart's pub tool for managing project dependencies and versions. The package names and versions are used to search the database for vulnerabilities.
The scanner examines the `pubspec.lock` file, made by Dart's pub tool for managing project dependencies and versions. The package names and versions are used to search the database for vulnerabilities.

Here's an example of what a [`pubspec.lock`](https://github.com/intel/cve-bin-tool/blob/main/test/language_data/pubspec.lock) file might look like.

### C/C++

The scanner examines the `conan.lock` file, generated by the Conan dependency and package manager for C and C++. The package names and versions are used to search the database for vulnerabilities.

Here's an example of what a [`conan.lock`](https://github.com/intel/cve-bin-tool/blob/main/test/language_data/conan.lock) file might look like.

## Feedback & Contributions

Bugs and feature requests can be made via [GitHub issues](https://github.com/intel/cve-bin-tool/issues).
Expand Down
12 changes: 12 additions & 0 deletions test/language_data/conan.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "0.5",
"requires": [
"zlib/1.2.11#fca992a7d96a1b92bd956caa8a97d18f%1705999194.642",
"openssl/3.0.1w#a8f0792d7c5121b954578a7149d23e03%1717541485.78"
],
"build_requires": [
"cmake/3.22.6#f305019023c2db74d1001c5afa5cf362"
],
"python_requires": [],
"config_requires": []
}
14 changes: 14 additions & 0 deletions test/test_language_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ class TestLanguageScanner:

DART_PRODUCTS = ["dio", "archive"]

CONAN_PRODUCTS = ["zlib", "openssl", "cmake"]

@classmethod
def setup_class(cls):
cls.cvedb = CVEDB()
Expand Down Expand Up @@ -341,6 +343,18 @@ def test_language_package_none_found(self, filename: str) -> None:
)
],
),
pytest.param(
str(TEST_FILE_PATH / "conan.lock"),
parsers.ccpp.CCppParser,
CONAN_PRODUCTS,
"conan",
marks=[
pytest.mark.skipif(
not LONG_TESTS(),
reason="Test reduction in short tests",
)
],
),
],
)
def test_language_package(
Expand Down

0 comments on commit 37f514c

Please sign in to comment.