This commit is contained in:
Iliyan Angelov
2025-12-01 06:50:10 +02:00
parent 91f51bc6fe
commit 62c1fe5951
4682 changed files with 544807 additions and 31208 deletions

View File

@@ -0,0 +1,252 @@
#
# Copyright 2015 Hewlett-Packard Enterprise
#
# SPDX-License-Identifier: Apache-2.0
# #############################################################################
# Bandit Baseline is a tool that runs Bandit against a Git commit, and compares
# the current commit findings to the parent commit findings.
# To do this it checks out the parent commit, runs Bandit (with any provided
# filters or profiles), checks out the current commit, runs Bandit, and then
# reports on any new findings.
# #############################################################################
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import contextlib
import logging
import os
import shutil
import subprocess # nosec: B404
import sys
import tempfile
try:
import git
except ImportError:
git = None
bandit_args = sys.argv[1:]
baseline_tmp_file = "_bandit_baseline_run.json_"
current_commit = None
default_output_format = "terminal"
LOG = logging.getLogger(__name__)
repo = None
report_basename = "bandit_baseline_result"
valid_baseline_formats = ["txt", "html", "json"]
"""baseline.py"""
def main():
"""Execute Bandit."""
# our cleanup function needs this and can't be passed arguments
global current_commit
global repo
parent_commit = None
output_format = None
repo = None
report_fname = None
init_logger()
output_format, repo, report_fname = initialize()
if not repo:
sys.exit(2)
# #################### Find current and parent commits ####################
try:
commit = repo.commit()
current_commit = commit.hexsha
LOG.info("Got current commit: [%s]", commit.name_rev)
commit = commit.parents[0]
parent_commit = commit.hexsha
LOG.info("Got parent commit: [%s]", commit.name_rev)
except git.GitCommandError:
LOG.error("Unable to get current or parent commit")
sys.exit(2)
except IndexError:
LOG.error("Parent commit not available")
sys.exit(2)
# #################### Run Bandit against both commits ####################
output_type = (
["-f", "txt"]
if output_format == default_output_format
else ["-o", report_fname]
)
with baseline_setup() as t:
bandit_tmpfile = f"{t}/{baseline_tmp_file}"
steps = [
{
"message": "Getting Bandit baseline results",
"commit": parent_commit,
"args": bandit_args + ["-f", "json", "-o", bandit_tmpfile],
},
{
"message": "Comparing Bandit results to baseline",
"commit": current_commit,
"args": bandit_args + ["-b", bandit_tmpfile] + output_type,
},
]
return_code = None
for step in steps:
repo.head.reset(commit=step["commit"], working_tree=True)
LOG.info(step["message"])
bandit_command = ["bandit"] + step["args"]
try:
output = subprocess.check_output(bandit_command) # nosec: B603
except subprocess.CalledProcessError as e:
output = e.output
return_code = e.returncode
else:
return_code = 0
output = output.decode("utf-8") # subprocess returns bytes
if return_code not in [0, 1]:
LOG.error(
"Error running command: %s\nOutput: %s\n",
bandit_args,
output,
)
# #################### Output and exit ####################################
# print output or display message about written report
if output_format == default_output_format:
print(output)
else:
LOG.info("Successfully wrote %s", report_fname)
# exit with the code the last Bandit run returned
sys.exit(return_code)
# #################### Clean up before exit ###################################
@contextlib.contextmanager
def baseline_setup():
"""Baseline setup by creating temp folder and resetting repo."""
d = tempfile.mkdtemp()
yield d
shutil.rmtree(d, True)
if repo:
repo.head.reset(commit=current_commit, working_tree=True)
# #################### Setup logging ##########################################
def init_logger():
"""Init logger."""
LOG.handlers = []
log_level = logging.INFO
log_format_string = "[%(levelname)7s ] %(message)s"
logging.captureWarnings(True)
LOG.setLevel(log_level)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(log_format_string))
LOG.addHandler(handler)
# #################### Perform initialization and validate assumptions ########
def initialize():
"""Initialize arguments and output formats."""
valid = True
# #################### Parse Args #########################################
parser = argparse.ArgumentParser(
description="Bandit Baseline - Generates Bandit results compared to "
"a baseline",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="Additional Bandit arguments such as severity filtering (-ll) "
"can be added and will be passed to Bandit.",
)
if sys.version_info >= (3, 14):
parser.suggest_on_error = True
parser.color = False
parser.add_argument(
"targets",
metavar="targets",
type=str,
nargs="+",
help="source file(s) or directory(s) to be tested",
)
parser.add_argument(
"-f",
dest="output_format",
action="store",
default="terminal",
help="specify output format",
choices=valid_baseline_formats,
)
args, _ = parser.parse_known_args()
# #################### Setup Output #######################################
# set the output format, or use a default if not provided
output_format = (
args.output_format if args.output_format else default_output_format
)
if output_format == default_output_format:
LOG.info("No output format specified, using %s", default_output_format)
# set the report name based on the output format
report_fname = f"{report_basename}.{output_format}"
# #################### Check Requirements #################################
if git is None:
LOG.error("Git not available, reinstall with baseline extra")
valid = False
return (None, None, None)
try:
repo = git.Repo(os.getcwd())
except git.exc.InvalidGitRepositoryError:
LOG.error("Bandit baseline must be called from a git project root")
valid = False
except git.exc.GitCommandNotFound:
LOG.error("Git command not found")
valid = False
else:
if repo.is_dirty():
LOG.error(
"Current working directory is dirty and must be " "resolved"
)
valid = False
# if output format is specified, we need to be able to write the report
if output_format != default_output_format and os.path.exists(report_fname):
LOG.error("File %s already exists, aborting", report_fname)
valid = False
# Bandit needs to be able to create this temp file
if os.path.exists(baseline_tmp_file):
LOG.error(
"Temporary file %s needs to be removed prior to running",
baseline_tmp_file,
)
valid = False
# we must validate -o is not provided, as it will mess up Bandit baseline
if "-o" in bandit_args:
LOG.error("Bandit baseline must not be called with the -o option")
valid = False
return (output_format, repo, report_fname) if valid else (None, None, None)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,207 @@
# Copyright 2015 Red Hat Inc.
#
# SPDX-License-Identifier: Apache-2.0
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import importlib
import logging
import os
import sys
import yaml
from bandit.core import extension_loader
PROG_NAME = "bandit_conf_generator"
LOG = logging.getLogger(__name__)
template = """
### Bandit config file generated from:
# '{cli}'
### This config may optionally select a subset of tests to run or skip by
### filling out the 'tests' and 'skips' lists given below. If no tests are
### specified for inclusion then it is assumed all tests are desired. The skips
### set will remove specific tests from the include set. This can be controlled
### using the -t/-s CLI options. Note that the same test ID should not appear
### in both 'tests' and 'skips', this would be nonsensical and is detected by
### Bandit at runtime.
# Available tests:
{test_list}
# (optional) list included test IDs here, eg '[B101, B406]':
{test}
# (optional) list skipped test IDs here, eg '[B101, B406]':
{skip}
### (optional) plugin settings - some test plugins require configuration data
### that may be given here, per-plugin. All bandit test plugins have a built in
### set of sensible defaults and these will be used if no configuration is
### provided. It is not necessary to provide settings for every (or any) plugin
### if the defaults are acceptable.
{settings}
"""
def init_logger():
"""Init logger."""
LOG.handlers = []
log_level = logging.INFO
log_format_string = "[%(levelname)5s]: %(message)s"
logging.captureWarnings(True)
LOG.setLevel(log_level)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(log_format_string))
LOG.addHandler(handler)
def parse_args():
"""Parse arguments."""
help_description = """Bandit Config Generator
This tool is used to generate an optional profile. The profile may be used
to include or skip tests and override values for plugins.
When used to store an output profile, this tool will output a template that
includes all plugins and their default settings. Any settings which aren't
being overridden can be safely removed from the profile and default values
will be used. Bandit will prefer settings from the profile over the built
in values."""
parser = argparse.ArgumentParser(
description=help_description,
formatter_class=argparse.RawTextHelpFormatter,
)
if sys.version_info >= (3, 14):
parser.suggest_on_error = True
parser.color = False
parser.add_argument(
"--show-defaults",
dest="show_defaults",
action="store_true",
help="show the default settings values for each "
"plugin but do not output a profile",
)
parser.add_argument(
"-o",
"--out",
dest="output_file",
action="store",
help="output file to save profile",
)
parser.add_argument(
"-t",
"--tests",
dest="tests",
action="store",
default=None,
type=str,
help="list of test names to run",
)
parser.add_argument(
"-s",
"--skip",
dest="skips",
action="store",
default=None,
type=str,
help="list of test names to skip",
)
args = parser.parse_args()
if not args.output_file and not args.show_defaults:
parser.print_help()
parser.exit(1)
return args
def get_config_settings():
"""Get configuration settings."""
config = {}
for plugin in extension_loader.MANAGER.plugins:
fn_name = plugin.name
function = plugin.plugin
# if a function takes config...
if hasattr(function, "_takes_config"):
fn_module = importlib.import_module(function.__module__)
# call the config generator if it exists
if hasattr(fn_module, "gen_config"):
config[fn_name] = fn_module.gen_config(function._takes_config)
return yaml.safe_dump(config, default_flow_style=False)
def main():
"""Config generator to write configuration file."""
init_logger()
args = parse_args()
yaml_settings = get_config_settings()
if args.show_defaults:
print(yaml_settings)
if args.output_file:
if os.path.exists(os.path.abspath(args.output_file)):
LOG.error("File %s already exists, exiting", args.output_file)
sys.exit(2)
try:
with open(args.output_file, "w") as f:
skips = args.skips.split(",") if args.skips else []
tests = args.tests.split(",") if args.tests else []
for skip in skips:
if not extension_loader.MANAGER.check_id(skip):
raise RuntimeError(f"unknown ID in skips: {skip}")
for test in tests:
if not extension_loader.MANAGER.check_id(test):
raise RuntimeError(f"unknown ID in tests: {test}")
tpl = "# {0} : {1}"
test_list = [
tpl.format(t.plugin._test_id, t.name)
for t in extension_loader.MANAGER.plugins
]
others = [
tpl.format(k, v["name"])
for k, v in (
extension_loader.MANAGER.blacklist_by_id.items()
)
]
test_list.extend(others)
test_list.sort()
contents = template.format(
cli=" ".join(sys.argv),
settings=yaml_settings,
test_list="\n".join(test_list),
skip="skips: " + str(skips) if skips else "skips:",
test="tests: " + str(tests) if tests else "tests:",
)
f.write(contents)
except OSError:
LOG.error("Unable to open %s for writing", args.output_file)
except Exception as e:
LOG.error("Error: %s", e)
else:
LOG.info("Successfully wrote profile: %s", args.output_file)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,701 @@
#
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# SPDX-License-Identifier: Apache-2.0
"""Bandit is a tool designed to find common security issues in Python code."""
import argparse
import fnmatch
import logging
import os
import sys
import textwrap
import bandit
from bandit.core import config as b_config
from bandit.core import constants
from bandit.core import manager as b_manager
from bandit.core import utils
BASE_CONFIG = "bandit.yaml"
LOG = logging.getLogger()
def _init_logger(log_level=logging.INFO, log_format=None):
"""Initialize the logger.
:param debug: Whether to enable debug mode
:return: An instantiated logging instance
"""
LOG.handlers = []
if not log_format:
# default log format
log_format_string = constants.log_format_string
else:
log_format_string = log_format
logging.captureWarnings(True)
LOG.setLevel(log_level)
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(logging.Formatter(log_format_string))
LOG.addHandler(handler)
LOG.debug("logging initialized")
def _get_options_from_ini(ini_path, target):
"""Return a dictionary of config options or None if we can't load any."""
ini_file = None
if ini_path:
ini_file = ini_path
else:
bandit_files = []
for t in target:
for root, _, filenames in os.walk(t):
for filename in fnmatch.filter(filenames, ".bandit"):
bandit_files.append(os.path.join(root, filename))
if len(bandit_files) > 1:
LOG.error(
"Multiple .bandit files found - scan separately or "
"choose one with --ini\n\t%s",
", ".join(bandit_files),
)
sys.exit(2)
elif len(bandit_files) == 1:
ini_file = bandit_files[0]
LOG.info("Found project level .bandit file: %s", bandit_files[0])
if ini_file:
return utils.parse_ini_file(ini_file)
else:
return None
def _init_extensions():
from bandit.core import extension_loader as ext_loader
return ext_loader.MANAGER
def _log_option_source(default_val, arg_val, ini_val, option_name):
"""It's useful to show the source of each option."""
# When default value is not defined, arg_val and ini_val is deterministic
if default_val is None:
if arg_val:
LOG.info("Using command line arg for %s", option_name)
return arg_val
elif ini_val:
LOG.info("Using ini file for %s", option_name)
return ini_val
else:
return None
# No value passed to commad line and default value is used
elif default_val == arg_val:
return ini_val if ini_val else arg_val
# Certainly a value is passed to commad line
else:
return arg_val
def _running_under_virtualenv():
if hasattr(sys, "real_prefix"):
return True
elif sys.prefix != getattr(sys, "base_prefix", sys.prefix):
return True
def _get_profile(config, profile_name, config_path):
profile = {}
if profile_name:
profiles = config.get_option("profiles") or {}
profile = profiles.get(profile_name)
if profile is None:
raise utils.ProfileNotFound(config_path, profile_name)
LOG.debug("read in legacy profile '%s': %s", profile_name, profile)
else:
profile["include"] = set(config.get_option("tests") or [])
profile["exclude"] = set(config.get_option("skips") or [])
return profile
def _log_info(args, profile):
inc = ",".join([t for t in profile["include"]]) or "None"
exc = ",".join([t for t in profile["exclude"]]) or "None"
LOG.info("profile include tests: %s", inc)
LOG.info("profile exclude tests: %s", exc)
LOG.info("cli include tests: %s", args.tests)
LOG.info("cli exclude tests: %s", args.skips)
def main():
"""Bandit CLI."""
# bring our logging stuff up as early as possible
debug = (
logging.DEBUG
if "-d" in sys.argv or "--debug" in sys.argv
else logging.INFO
)
_init_logger(debug)
extension_mgr = _init_extensions()
baseline_formatters = [
f.name
for f in filter(
lambda x: hasattr(x.plugin, "_accepts_baseline"),
extension_mgr.formatters,
)
]
# now do normal startup
parser = argparse.ArgumentParser(
description="Bandit - a Python source code security analyzer",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
if sys.version_info >= (3, 14):
parser.suggest_on_error = True
parser.color = False
parser.add_argument(
"targets",
metavar="targets",
type=str,
nargs="*",
help="source file(s) or directory(s) to be tested",
)
parser.add_argument(
"-r",
"--recursive",
dest="recursive",
action="store_true",
help="find and process files in subdirectories",
)
parser.add_argument(
"-a",
"--aggregate",
dest="agg_type",
action="store",
default="file",
type=str,
choices=["file", "vuln"],
help="aggregate output by vulnerability (default) or by filename",
)
parser.add_argument(
"-n",
"--number",
dest="context_lines",
action="store",
default=3,
type=int,
help="maximum number of code lines to output for each issue",
)
parser.add_argument(
"-c",
"--configfile",
dest="config_file",
action="store",
default=None,
type=str,
help="optional config file to use for selecting plugins and "
"overriding defaults",
)
parser.add_argument(
"-p",
"--profile",
dest="profile",
action="store",
default=None,
type=str,
help="profile to use (defaults to executing all tests)",
)
parser.add_argument(
"-t",
"--tests",
dest="tests",
action="store",
default=None,
type=str,
help="comma-separated list of test IDs to run",
)
parser.add_argument(
"-s",
"--skip",
dest="skips",
action="store",
default=None,
type=str,
help="comma-separated list of test IDs to skip",
)
severity_group = parser.add_mutually_exclusive_group(required=False)
severity_group.add_argument(
"-l",
"--level",
dest="severity",
action="count",
default=1,
help="report only issues of a given severity level or "
"higher (-l for LOW, -ll for MEDIUM, -lll for HIGH)",
)
severity_group.add_argument(
"--severity-level",
dest="severity_string",
action="store",
help="report only issues of a given severity level or higher."
' "all" and "low" are likely to produce the same results, but it'
" is possible for rules to be undefined which will"
' not be listed in "low".',
choices=["all", "low", "medium", "high"],
)
confidence_group = parser.add_mutually_exclusive_group(required=False)
confidence_group.add_argument(
"-i",
"--confidence",
dest="confidence",
action="count",
default=1,
help="report only issues of a given confidence level or "
"higher (-i for LOW, -ii for MEDIUM, -iii for HIGH)",
)
confidence_group.add_argument(
"--confidence-level",
dest="confidence_string",
action="store",
help="report only issues of a given confidence level or higher."
' "all" and "low" are likely to produce the same results, but it'
" is possible for rules to be undefined which will"
' not be listed in "low".',
choices=["all", "low", "medium", "high"],
)
output_format = (
"screen"
if (
sys.stdout.isatty()
and os.getenv("NO_COLOR") is None
and os.getenv("TERM") != "dumb"
)
else "txt"
)
parser.add_argument(
"-f",
"--format",
dest="output_format",
action="store",
default=output_format,
help="specify output format",
choices=sorted(extension_mgr.formatter_names),
)
parser.add_argument(
"--msg-template",
action="store",
default=None,
help="specify output message template"
" (only usable with --format custom),"
" see CUSTOM FORMAT section"
" for list of available values",
)
parser.add_argument(
"-o",
"--output",
dest="output_file",
action="store",
nargs="?",
type=argparse.FileType("w", encoding="utf-8"),
default=sys.stdout,
help="write report to filename",
)
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument(
"-v",
"--verbose",
dest="verbose",
action="store_true",
help="output extra information like excluded and included files",
)
parser.add_argument(
"-d",
"--debug",
dest="debug",
action="store_true",
help="turn on debug mode",
)
group.add_argument(
"-q",
"--quiet",
"--silent",
dest="quiet",
action="store_true",
help="only show output in the case of an error",
)
parser.add_argument(
"--ignore-nosec",
dest="ignore_nosec",
action="store_true",
help="do not skip lines with # nosec comments",
)
parser.add_argument(
"-x",
"--exclude",
dest="excluded_paths",
action="store",
default=",".join(constants.EXCLUDE),
help="comma-separated list of paths (glob patterns "
"supported) to exclude from scan "
"(note that these are in addition to the excluded "
"paths provided in the config file) (default: "
+ ",".join(constants.EXCLUDE)
+ ")",
)
parser.add_argument(
"-b",
"--baseline",
dest="baseline",
action="store",
default=None,
help="path of a baseline report to compare against "
"(only JSON-formatted files are accepted)",
)
parser.add_argument(
"--ini",
dest="ini_path",
action="store",
default=None,
help="path to a .bandit file that supplies command line arguments",
)
parser.add_argument(
"--exit-zero",
action="store_true",
dest="exit_zero",
default=False,
help="exit with 0, " "even with results found",
)
python_ver = sys.version.replace("\n", "")
parser.add_argument(
"--version",
action="version",
version=f"%(prog)s {bandit.__version__}\n"
f" python version = {python_ver}",
)
parser.set_defaults(debug=False)
parser.set_defaults(verbose=False)
parser.set_defaults(quiet=False)
parser.set_defaults(ignore_nosec=False)
plugin_info = [
f"{a[0]}\t{a[1].name}" for a in extension_mgr.plugins_by_id.items()
]
blacklist_info = []
for a in extension_mgr.blacklist.items():
for b in a[1]:
blacklist_info.append(f"{b['id']}\t{b['name']}")
plugin_list = "\n\t".join(sorted(set(plugin_info + blacklist_info)))
dedent_text = textwrap.dedent(
"""
CUSTOM FORMATTING
-----------------
Available tags:
{abspath}, {relpath}, {line}, {col}, {test_id},
{severity}, {msg}, {confidence}, {range}
Example usage:
Default template:
bandit -r examples/ --format custom --msg-template \\
"{abspath}:{line}: {test_id}[bandit]: {severity}: {msg}"
Provides same output as:
bandit -r examples/ --format custom
Tags can also be formatted in python string.format() style:
bandit -r examples/ --format custom --msg-template \\
"{relpath:20.20s}: {line:03}: {test_id:^8}: DEFECT: {msg:>20}"
See python documentation for more information about formatting style:
https://docs.python.org/3/library/string.html
The following tests were discovered and loaded:
-----------------------------------------------
"""
)
parser.epilog = dedent_text + f"\t{plugin_list}"
# setup work - parse arguments, and initialize BanditManager
args = parser.parse_args()
# Check if `--msg-template` is not present without custom formatter
if args.output_format != "custom" and args.msg_template is not None:
parser.error("--msg-template can only be used with --format=custom")
# Check if confidence or severity level have been specified with strings
if args.severity_string is not None:
if args.severity_string == "all":
args.severity = 1
elif args.severity_string == "low":
args.severity = 2
elif args.severity_string == "medium":
args.severity = 3
elif args.severity_string == "high":
args.severity = 4
# Other strings will be blocked by argparse
if args.confidence_string is not None:
if args.confidence_string == "all":
args.confidence = 1
elif args.confidence_string == "low":
args.confidence = 2
elif args.confidence_string == "medium":
args.confidence = 3
elif args.confidence_string == "high":
args.confidence = 4
# Other strings will be blocked by argparse
# Handle .bandit files in projects to pass cmdline args from file
ini_options = _get_options_from_ini(args.ini_path, args.targets)
if ini_options:
# prefer command line, then ini file
args.config_file = _log_option_source(
parser.get_default("configfile"),
args.config_file,
ini_options.get("configfile"),
"config file",
)
args.excluded_paths = _log_option_source(
parser.get_default("excluded_paths"),
args.excluded_paths,
ini_options.get("exclude"),
"excluded paths",
)
args.skips = _log_option_source(
parser.get_default("skips"),
args.skips,
ini_options.get("skips"),
"skipped tests",
)
args.tests = _log_option_source(
parser.get_default("tests"),
args.tests,
ini_options.get("tests"),
"selected tests",
)
ini_targets = ini_options.get("targets")
if ini_targets:
ini_targets = ini_targets.split(",")
args.targets = _log_option_source(
parser.get_default("targets"),
args.targets,
ini_targets,
"selected targets",
)
# TODO(tmcpeak): any other useful options to pass from .bandit?
args.recursive = _log_option_source(
parser.get_default("recursive"),
args.recursive,
ini_options.get("recursive"),
"recursive scan",
)
args.agg_type = _log_option_source(
parser.get_default("agg_type"),
args.agg_type,
ini_options.get("aggregate"),
"aggregate output type",
)
args.context_lines = _log_option_source(
parser.get_default("context_lines"),
args.context_lines,
int(ini_options.get("number") or 0) or None,
"max code lines output for issue",
)
args.profile = _log_option_source(
parser.get_default("profile"),
args.profile,
ini_options.get("profile"),
"profile",
)
args.severity = _log_option_source(
parser.get_default("severity"),
args.severity,
ini_options.get("level"),
"severity level",
)
args.confidence = _log_option_source(
parser.get_default("confidence"),
args.confidence,
ini_options.get("confidence"),
"confidence level",
)
args.output_format = _log_option_source(
parser.get_default("output_format"),
args.output_format,
ini_options.get("format"),
"output format",
)
args.msg_template = _log_option_source(
parser.get_default("msg_template"),
args.msg_template,
ini_options.get("msg-template"),
"output message template",
)
args.output_file = _log_option_source(
parser.get_default("output_file"),
args.output_file,
ini_options.get("output"),
"output file",
)
args.verbose = _log_option_source(
parser.get_default("verbose"),
args.verbose,
ini_options.get("verbose"),
"output extra information",
)
args.debug = _log_option_source(
parser.get_default("debug"),
args.debug,
ini_options.get("debug"),
"debug mode",
)
args.quiet = _log_option_source(
parser.get_default("quiet"),
args.quiet,
ini_options.get("quiet"),
"silent mode",
)
args.ignore_nosec = _log_option_source(
parser.get_default("ignore_nosec"),
args.ignore_nosec,
ini_options.get("ignore-nosec"),
"do not skip lines with # nosec",
)
args.baseline = _log_option_source(
parser.get_default("baseline"),
args.baseline,
ini_options.get("baseline"),
"path of a baseline report",
)
try:
b_conf = b_config.BanditConfig(config_file=args.config_file)
except utils.ConfigError as e:
LOG.error(e)
sys.exit(2)
if not args.targets:
parser.print_usage()
sys.exit(2)
# if the log format string was set in the options, reinitialize
if b_conf.get_option("log_format"):
log_format = b_conf.get_option("log_format")
_init_logger(log_level=logging.DEBUG, log_format=log_format)
if args.quiet:
_init_logger(log_level=logging.WARN)
try:
profile = _get_profile(b_conf, args.profile, args.config_file)
_log_info(args, profile)
profile["include"].update(args.tests.split(",") if args.tests else [])
profile["exclude"].update(args.skips.split(",") if args.skips else [])
extension_mgr.validate_profile(profile)
except (utils.ProfileNotFound, ValueError) as e:
LOG.error(e)
sys.exit(2)
b_mgr = b_manager.BanditManager(
b_conf,
args.agg_type,
args.debug,
profile=profile,
verbose=args.verbose,
quiet=args.quiet,
ignore_nosec=args.ignore_nosec,
)
if args.baseline is not None:
try:
with open(args.baseline) as bl:
data = bl.read()
b_mgr.populate_baseline(data)
except OSError:
LOG.warning("Could not open baseline report: %s", args.baseline)
sys.exit(2)
if args.output_format not in baseline_formatters:
LOG.warning(
"Baseline must be used with one of the following "
"formats: " + str(baseline_formatters)
)
sys.exit(2)
if args.output_format != "json":
if args.config_file:
LOG.info("using config: %s", args.config_file)
LOG.info(
"running on Python %d.%d.%d",
sys.version_info.major,
sys.version_info.minor,
sys.version_info.micro,
)
# initiate file discovery step within Bandit Manager
b_mgr.discover_files(args.targets, args.recursive, args.excluded_paths)
if not b_mgr.b_ts.tests:
LOG.error("No tests would be run, please check the profile.")
sys.exit(2)
# initiate execution of tests within Bandit Manager
b_mgr.run_tests()
LOG.debug(b_mgr.b_ma)
LOG.debug(b_mgr.metrics)
# trigger output of results by Bandit Manager
sev_level = constants.RANKING[args.severity - 1]
conf_level = constants.RANKING[args.confidence - 1]
b_mgr.output_results(
args.context_lines,
sev_level,
conf_level,
args.output_file,
args.output_format,
args.msg_template,
)
if (
b_mgr.results_count(sev_filter=sev_level, conf_filter=conf_level) > 0
and not args.exit_zero
):
sys.exit(1)
else:
sys.exit(0)
if __name__ == "__main__":
main()