forked from intel/cve-bin-tool
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: documentation on out of tree parsers
Signed-off-by: John Andersen <[email protected]>
- Loading branch information
John Andersen
committed
Jun 18, 2024
1 parent
b9ab8f3
commit 63960fd
Showing
11 changed files
with
583 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ | |
"php", | ||
"perl", | ||
"dart", | ||
"env", | ||
] | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
from __future__ import annotations | ||
|
||
import dataclasses | ||
import pathlib | ||
import re | ||
|
||
from packageurl import PackageURL | ||
|
||
from cve_bin_tool.parsers import Parser | ||
from cve_bin_tool.util import ProductInfo, ScanInfo | ||
|
||
|
||
@dataclasses.dataclass | ||
class EnvNamespaceConfig: | ||
ad_hoc_cve_id: str | ||
vendor: str | ||
product: str | ||
version: str | ||
location: str = "/usr/local/bin/product" | ||
|
||
|
||
@dataclasses.dataclass | ||
class EnvConfig: | ||
namespaces: dict[str, EnvNamespaceConfig] | ||
|
||
|
||
class EnvParser(Parser): | ||
""" | ||
Parser for Python requirements files. | ||
This parser is designed to parse Python requirements files (usually named | ||
requirements.txt) and generate PURLs (Package URLs) for the listed packages. | ||
""" | ||
|
||
PARSER_MATCH_FILENAMES = [ | ||
".env", | ||
] | ||
|
||
@staticmethod | ||
def parse_file_contents(contents): | ||
lines = list( | ||
[ | ||
line | ||
for line in contents.replace("\r\n", "\n").split("\n") | ||
if line.strip() and line.startswith("CVE_BIN_TOOL_") | ||
] | ||
) | ||
namespaces = {} | ||
for i, line in enumerate(lines): | ||
key, value = line.split("=", maxsplit=1) | ||
namespace, key = key[len("CVE_BIN_TOOL_") :].split("_", maxsplit=1) | ||
if value.startswith('"'): | ||
value = value[1:] | ||
if value.endswith('"'): | ||
value = value[:-1] | ||
namespaces.setdefault(namespace, {}) | ||
namespaces[namespace][key.lower()] = value | ||
for namespace, config in namespaces.items(): | ||
namespaces[namespace] = EnvNamespaceConfig(**config) | ||
return EnvConfig(namespaces=namespaces) | ||
|
||
def run_checker(self, filename): | ||
""" | ||
Parse the .env file and yield ScanInfo objects for the listed packages. | ||
Args: | ||
filename (str): The path to the .env file. | ||
Yields: | ||
str: ScanInfo objects for the packages listed in the file. | ||
""" | ||
self.filename = filename | ||
contents = pathlib.Path(self.filename).read_text() | ||
|
||
env_config = self.parse_file_contents(contents) | ||
|
||
data_source = "environment" | ||
affected_data = [ | ||
{ | ||
"cve_id": cve.ad_hoc_cve_id, | ||
"vendor": cve.vendor, | ||
"product": cve.product, | ||
# TODO Version MUST be unique to this bug! | ||
"version": cve.version, | ||
"versionStartIncluding": "", | ||
# "versionStartIncluding": cve.version, | ||
"versionStartExcluding": "", | ||
"versionEndIncluding": "", | ||
# "versionEndIncluding": cve.version, | ||
"versionEndExcluding": "", | ||
} | ||
for _namespace, cve in env_config.namespaces.items() | ||
] | ||
severity_data = [ | ||
{ | ||
"ID": cve.ad_hoc_cve_id, | ||
# TODO severity | ||
"severity": "LOW", | ||
# TODO description | ||
"description": "TODO", | ||
# TODO score | ||
"score": 0, | ||
# TODO CVSS_version | ||
"CVSS_version": 3, | ||
# TODO CVSS_vector | ||
"CVSS_vector": "", | ||
"last_modified": "", | ||
} | ||
for _namespace, cve in env_config.namespaces.items() | ||
] | ||
|
||
with self.cve_db.with_cursor() as cursor: | ||
self.cve_db.populate_cve_metrics(severity_data, cursor) | ||
self.cve_db.populate_severity(severity_data, cursor, data_source) | ||
self.cve_db.populate_affected(affected_data, cursor, data_source) | ||
|
||
for _namespace, cve in env_config.namespaces.items(): | ||
yield ScanInfo( | ||
ProductInfo( | ||
cve.vendor, | ||
cve.product, | ||
cve.version, | ||
cve.location, | ||
PackageURL( | ||
type="ad-hoc", | ||
namespace=cve.vendor, | ||
name=re.sub(r"[^a-zA-Z0-9._-]", "", cve.product).lower(), | ||
version=cve.version, | ||
qualifiers={}, | ||
subpath=None, | ||
), | ||
), | ||
pathlib.Path(filename).resolve(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
Adding a new parser to cve-bin-tool | ||
=================================== | ||
|
||
Overview | ||
-------- | ||
|
||
Parsers enhance ``cve-bin-tool`` by helping it discover vulnerabilities for | ||
different file types and manifest formats. | ||
|
||
Parsers | ||
------- | ||
|
||
The following parsers have been added to the project: | ||
|
||
- **DartParser** | ||
- **GoParser** | ||
- **JavaParser** | ||
- **JavascriptParser** | ||
- **PerlParser** | ||
- **PhpParser** | ||
- **PythonParser** | ||
- **PythonRequirementsParser** | ||
- **RParser** | ||
- **RubyParser** | ||
- **RustParser** | ||
- **SwiftParser** | ||
- **BanditParser** | ||
|
||
Usage | ||
----- | ||
|
||
To utilize these parsers, ensure that your project includes the following imports: | ||
|
||
.. code-block:: python | ||
from cve_bin_tool.parsers.dart import DartParser | ||
from cve_bin_tool.parsers.go import GoParser | ||
from cve_bin_tool.parsers.java import JavaParser | ||
from cve_bin_tool.parsers.javascript import JavascriptParser | ||
from cve_bin_tool.parsers.perl import PerlParser | ||
from cve_bin_tool.parsers.php import PhpParser | ||
from cve_bin_tool.parsers.python import PythonParser, PythonRequirementsParser | ||
from cve_bin_tool.parsers.r import RParser | ||
from cve_bin_tool.parsers.ruby import RubyParser | ||
from cve_bin_tool.parsers.rust import RustParser | ||
from cve_bin_tool.parsers.swift import SwiftParser | ||
from cve_bin_tool.parsers.bandit import BanditParser | ||
Setting Up a New Package and Entry Point | ||
---------------------------------------- | ||
|
||
To implement a new parser plugin, such as a Bandit parser, follow these steps: | ||
|
||
1. Create the Parser Class | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
First, create the parser class. This class should be located in the appropriate directory within your project. For example, you might place it in ``cve_bin_tool_parser_env/env.py``. | ||
|
||
.. literalinclude:: /../cve_bin_tool/parsers/env.py | ||
|
||
2. Set Up ``setup.py`` | ||
^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Next, configure the ``setup.py`` file boilerplate. | ||
|
||
.. literalinclude:: /../example/oot-parser/setup.py | ||
|
||
3. Set Up ``setup.cfg`` | ||
^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Next, configure the ``setup.cfg`` file to include your new parser as an entry point. This allows the parser to be dynamically discovered and used by the project. | ||
|
||
.. literalinclude:: /../example/oot-parser/setup.cfg | ||
|
||
4. Create ``entry_points.txt`` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
You may also need to configure an ``entry_points.txt`` file if your project uses it to manage entry points. | ||
|
||
.. literalinclude:: /../example/oot-parser/entry_points.txt | ||
|
||
5. Install your plugin | ||
^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
You need to activate your virtualenv before installing if you set one up. | ||
|
||
.. code-block:: console | ||
$ python -m pip install -e . | ||
6. Populate the to-be-parsed file | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
In this example we implemented the ``EnvParser`` which is the format of | ||
``/etc/environment``. | ||
|
||
.. literalinclude:: /../test/parser_env_test_0001.env | ||
|
||
7. Run ``cve-bin-tool`` and see your plugin's findings | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
Let's test that our defined CVE comes up by scanning a ``.env`` file. | ||
|
||
.. code-block:: console | ||
$ cve-bin-tool --log debug setup.py | ||
Advanced Example: Ad-Hoc CVEs | ||
----------------------------- | ||
|
||
For more information see: https://github.com/ossf/wg-vulnerability-disclosures/issues/94 | ||
|
||
1. Create the Parser Class | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
First, create the parser class. This class should be located in the appropriate directory within your project. For example, you might place it in ``cve_bin_tool_parser_static_analysis_bandit/bandit.py``. | ||
|
||
.. literalinclude:: /../example/oot-parser/cve_bin_tool_parser_static_analysis_bandit/static_analysis_bandit.py | ||
|
||
2. Run ``cve-bin-tool`` and see your plugin's findings | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
In this example we implemented the ``BanditParser`` which is a static | ||
analysis tool for Python files. We'll test that it loads by scanning | ||
a ``.py`` file. | ||
|
||
.. code-block:: console | ||
$ cve-bin-tool --log debug setup.py | ||
Test Implementation | ||
------------------- | ||
|
||
A new test class `TestParsers` has been introduced to verify that the expected file types are correctly mapped to their respective parsers. The test ensures that the actual valid files match the expected valid files. | ||
|
||
Test Method | ||
^^^^^^^^^^^ | ||
|
||
- `test_parser_match_filenames_results_in_correct_valid_files`: This test compares the `EXPECTED_VALID_FILES` dictionary with the `actual_valid_files` dictionary imported from `cve_bin_tool.parsers.parse`. If there is any discrepancy between the two, the test will fail, indicating that the loaded file types do not match the expected registered file types. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.