Skip to content

Commit

Permalink
fix: make config generator robust to option changes (intel#3803)
Browse files Browse the repository at this point in the history
fixes: intel#2821
  • Loading branch information
mastersans authored Feb 15, 2024
1 parent fd80100 commit 171c480
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 105 deletions.
42 changes: 35 additions & 7 deletions cve_bin_tool/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
get_backport_supported_distros,
)
from cve_bin_tool.config import ConfigParser
from cve_bin_tool.config_generator import config_generator
from cve_bin_tool.config_generator import ConfigGenerator
from cve_bin_tool.cve_scanner import CVEScanner
from cve_bin_tool.cvedb import CVEDB, OLD_CACHE_DIR
from cve_bin_tool.data_sources import (
Expand Down Expand Up @@ -525,7 +525,33 @@ def main(argv=None):
configs = conf.parse_config()

args = ChainMap(args, configs, defaults)

if args["generate_config"] != "":
store = parser.parse_args(argv[1:])
arg_groups = {}
for grp in parser._action_groups:
grp_dict = {
a.dest: getattr(store, a.dest, None) for a in grp._group_actions
}
arg_groups[grp.title] = argparse.Namespace(**grp_dict)

organized_arguments = {}
for group_title, group_args in arg_groups.items():
group_title = group_title.replace(" ", "_")
organized_arguments[group_title] = {}
for arg_name, arg_value in vars(group_args).items():
arg_name = arg_name.replace("_", "-")
if arg_name == "log-level":
help_str = parser._option_string_actions["--log"].help
elif arg_name == "directory":
help_str = "Directory to scan"
else:
help_str = parser._option_string_actions[f"--{arg_name}"].help
organized_arguments[group_title][arg_name] = {
"arg_value": arg_value,
"help": help_str,
}

LOGGER.debug(organized_arguments)
# logging and error related settings
if args["log_level"]:
LOGGER.setLevel(args["log_level"].upper())
Expand Down Expand Up @@ -627,12 +653,14 @@ def main(argv=None):
f'epss probability {args["epss_probability"]} is invalid so set it to 0'
)

config_generate = set(args["generate_config"].split(","))
config_generate = [config_type.strip() for config_type in config_generate]
for config_type in config_generate:
LOGGER.debug(f"Arguments declared in generating config file {args}")
config_generator.config_generator(args, config_type)
if args["generate_config"] != "":
config_formats = set(args["generate_config"].split(","))
config_formats = [config_format.strip() for config_format in config_formats]
# current format includes .yaml and .toml
for config_format in config_formats:
LOGGER.debug(f"Arguments declared in generating config file {args}")
ConfigGenerator.config_generator(config_format, organized_arguments)

return 0

# Offline processing
Expand Down
156 changes: 66 additions & 90 deletions cve_bin_tool/config_generator.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,76 @@
class config_generator:
def config_generator(args, types):
if types == "toml":
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later
import json

config_header = """
# This is a generated configuration file from the CVE Binary Tool ConfigGenerator.
# Exercise caution when editing. To generate a new config file, use --generate-config option.
# For more info, refer to the official documentation at: https://cve-bin-tool.readthedocs.io/en/latest/.
# If you support the project and wish to contribute, check the Contributor Guide:
# https://cve-bin-tool.readthedocs.io/en/latest/CONTRIBUTING.html#cve-binary-tool-contributor-guide.
# Project GitHub: https://github.com/intel/cve-bin-tool
"""


class ConfigGenerator:
"""
A class for generating configuration files in different formats.
"""

def config_generator(config_format, organized_arguments):
"""
Generate a configuration file in the specified format.
Args:
config_format (str): The format of the configuration file (".toml" or ".yaml").
organized_arguments (dict): A dictionary containing organized arguments.
Returns:
None
"""
if config_format == "toml":
first_char = "["
last_char = "]"
sign = "="
coma = '"'
elif types == "yaml":
elif config_format == "yaml":
first_char = ""
last_char = ":"
sign = ":"
coma = ""
else:
return

strings = f"""
# This is an automatically generated configuration file for the CVE Binary Tool. It allows you to customize and manage the tool to suit your needs.
# Please exercise caution when editing this file and follow the instructions provided.
# To generate a new configuration file, use the --generate-config option. For more information, please refer to the official CVE Binary Tool documentation at https://cve-bin-tool.readthedocs.io/en/latest/.
# This file enables you to specify options such as the installation directory of the tool, the data sources to be used, and other relevant settings. To make changes, simply modify the values to the right of the equal sign.
# For more information on the available options and how to configure them, please refer to the official documentation at https://cve-bin-tool.readthedocs.io/en/latest/.
# If you support the project and wish to contribute, you can find the official CVE Binary Tool Contributor Guide at https://cve-bin-tool.readthedocs.io/en/latest/CONTRIBUTING.html#cve-binary-tool-contributor-guide.
# And link for project github https://github.com/intel/cve-bin-tool
{first_char}cve_data_download{last_char}
#set your nvd api key
nvd_api_key {sign} {coma}{args["nvd_api_key"]}{coma}
# choose method for getting CVE lists from NVD (default: api2) other option available json
nvd {sign} {coma}{args["nvd"]}{coma}
# update schedule for data sources and exploits database (default: daily)
update {sign} {coma}{args["update"]}{coma}
{first_char}input{last_char}
# Directory to scan
directory {sign} {coma}{args["directory"]}{coma}
# To supplement triage data of previous scan or run standalone as csv2cve
# Currently we only support csv and json file.
input_file {sign} {coma}{args["input_file"]}{coma}
# provide config file
config {sign} {coma}{args["config"]}{coma}
# specify type of software bill of materials (sbom) (default: spdx) other option are cyclonedx, swid
sbom {sign} {coma}{args["sbom"]}{coma}
# provide sbom filename
sbom_file {sign} {coma}{args["sbom_file"]}{coma}
{first_char}checker{last_char}
# list of checkers you want to skip
skips {sign} {coma}{args["skips"]}{coma}
# list of checkers you want to run
runs {sign} {coma}{args["runs"]}{coma}
{first_char}output{last_char}
# specify output verbosity from [debug, info, warning, error, critical]
# verbosity will decreases as you go left to right (default: info)
log_level {sign} {coma}{args["log_level"]}{coma}
# if true then we don't display any output and
# only exit-code with number of cves get returned
# overwrites setting specified in log_level
# Note: it's lowercase true or false
quiet {sign} {coma}{args["quiet"]}{coma}
# specify one of an output format: [csv, json, html, console] (default: console)
format {sign} {coma}{args["format"]}{coma}
# provide output filename (optional)
# if not specified we will generate one according to output format specified
output_file {sign} {coma}{args["output_file"]}{coma}
# specify minimum CVE severity level to report from [low, medium, high, critical] (default: low)
severity {sign} {coma}{args["severity"]}{coma}
# specify minimum CVSS score to report from integer range 0 to 10 (default: 0)
cvss {sign} {args["cvss"]}
# Produces a report even if there are no CVE for the respective output format
report {sign} {coma}{args["report"]}{coma}
# Provide vulnerability exchange (vex) filename
vex {sign} {coma}{args["vex"]}{coma}
{first_char}other{last_char}
# set true if you want to skip checking for newer version
disable_version_check {sign} {coma}{args["disable_version_check"]}{coma}
# set true if you want to autoextract archive files. (default: true)
extract {sign} {coma}{args["extract"]}{coma}
# operate in offline mode
offline {sign} {coma}{args["offline"]}{coma}
{first_char}merge_report{last_char}
# save output as intermediate report in json format
append {sign} {coma}{args["append"]}{coma}
# add a unique tag to differentiate between multiple intermediate reports
tag {sign} {coma}{args["tag"]}{coma}
# comma separated intermediate reports path for merging
merge {sign} {coma}{args["merge"]}{coma}
# comma separated tag string for filtering intermediate reports
filter {sign} {coma}{args["filter"]}{coma}
{first_char}database{last_char}
# export database filename
export {sign} {coma}{args["export"]}{coma}
# import database filename
import {sign} {coma}{args["import"]}{coma}
{first_char}exploit{last_char}
# check for exploits from found cves
exploits {sign} {coma}{args["exploits"]}{coma}
{first_char}deprecated{last_char}
# autoextract compressed files
extract {sign} {coma}{args["extract"]}{coma}
"""
f = open(f"config.{types}", "w")
f.write(strings)
f.close()
with open(f"config.{config_format}", "w") as f:
f.write(f"{config_header}\n")
for group_title, group_args in organized_arguments.items():
if group_title == "positional_arguments":
continue
group_title = group_title.lower()
if group_title == "output":
if group_args["sbom-output"]["arg_value"] == "":
group_args["sbom-type"]["arg_value"] = None
group_args["sbom-format"]["arg_value"] = None
group_args["sbom-output"]["arg_value"] = None
if group_args["vex"]["arg_value"] == "":
group_args["vex"]["arg_value"] = None
f.write(f"{first_char}{group_title}{last_char}\n")
for arg_name, arg_value_help in group_args.items():
arg_value = arg_value_help["arg_value"]
arg_help = arg_value_help["help"]
arg_name = arg_name.replace("-", "_")
if arg_name in ["config", "generate_config"]:
arg_value = None
if "\n" in arg_help:
arg_help = arg_help.replace("\n", " ")
if arg_value in [True, False] or isinstance(arg_value, list):
arg_val = (
json.dumps(arg_value).lower()
if arg_value in [True, False]
else arg_value
)
f.write(f" {arg_name} {sign} {arg_val}\n" f" #{arg_help}\n\n")
elif arg_value is not None:
f.write(
f" {arg_name} {sign} {coma}{arg_value}{coma}\n"
f" #{arg_help}\n\n"
)
13 changes: 5 additions & 8 deletions test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,16 +721,14 @@ def test_console_output_depending_reportlab_existence(self, caplog):
]
output_yamls = [
[
"This is an automatically generated configuration file",
"nvd : api2",
"format : csv",
"severity : high",
"input_file : test/test_json.py",
"update : daily",
"log_level : info",
"nvd_api_key : ",
"offline : False",
"merge : None",
"offline : false",
],
]
tomls = [
Expand All @@ -749,16 +747,15 @@ def test_console_output_depending_reportlab_existence(self, caplog):
]
output_tomls = [
[
"This is an automatically generated configuration file",
'nvd = "json-mirror"',
'nvd = "json"',
'sbom = "swid"',
'log_level = "warning"',
'offline = "True"',
"offline = true",
'input_file = ""',
'sbom_file = ""',
'runs = ""',
'extract = "True"',
'append = "False"',
"extract = true",
"append = false",
'import = ""',
],
]
Expand Down

0 comments on commit 171c480

Please sign in to comment.