updates
This commit is contained in:
252
Backend/venv/lib/python3.12/site-packages/bandit/cli/baseline.py
Normal file
252
Backend/venv/lib/python3.12/site-packages/bandit/cli/baseline.py
Normal 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()
|
||||
Reference in New Issue
Block a user