Skip to content

Commit

Permalink
Fixed bool params not working in ini file
Browse files Browse the repository at this point in the history
  • Loading branch information
Babarberousse committed Oct 20, 2019
1 parent acd6b40 commit a82aa79
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 117 deletions.
227 changes: 115 additions & 112 deletions bandit/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def _find_ini_file(target):


def _get_options_from_ini(ini_path, target):
"""Return a dictionary of config options or None if we can't load any."""
"""Return a dictionary of config options we could find"""
if ini_path:
ini_file = ini_path
else:
Expand All @@ -96,7 +96,7 @@ def _get_options_from_ini(ini_path, target):
if ini_file:
return utils.parse_ini_file(ini_file)
else:
return None
return {}


def _init_extensions():
Expand Down Expand Up @@ -146,6 +146,109 @@ def _log_info(args, profile):
LOG.info("cli exclude tests: %s", args.skips)


def _handle_bool_in_ini(ini_options, args):
"""Sets args values from cli, ini file or default value
To enable setting bool options in the ini file, their default values
can only be set after comparing cli and ini options
:param ini_options:
:param args:
:return:
"""
bool_options = {
'recursive': True,
'verbose': False,
'debug': False,
'quiet': False,
'ignore-nosec': False,
'exit-zero': False
}

for option, default_value in bool_options.items():
ini_value = ini_options.get(option)
cli_value = getattr(args, option.replace('-', '_'))
_log_option_source(cli_value, ini_value, option)

if ini_value is not None and cli_value is None:
setattr(args, option.replace('-', '_'), ini_value)
elif ini_value is None and cli_value is None:
setattr(args, option.replace('-', '_'), default_value)


def _handle_ini_options(ini_options, args):
# prefer command line, then ini file
args.excluded_paths = _log_option_source(
args.excluded_paths,
ini_options.get('exclude'),
'excluded paths')

args.skips = _log_option_source(
args.skips,
ini_options.get('skips'),
'skipped tests')

args.tests = _log_option_source(
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(
args.targets,
ini_targets,
'selected targets')

args.agg_type = _log_option_source(
args.agg_type,
ini_options.get('aggregate'),
'aggregate output type')

args.context_lines = _log_option_source(
args.context_lines,
ini_options.get('number'),
'max code lines output for issue')

args.profile = _log_option_source(
args.profile,
ini_options.get('profile'),
'profile')

args.severity = _log_option_source(
args.severity,
ini_options.get('level'),
'severity level')

args.confidence = _log_option_source(
args.confidence,
ini_options.get('confidence'),
'confidence level')

args.output_format = _log_option_source(
args.output_format,
ini_options.get('format'),
'output format')

args.msg_template = _log_option_source(
args.msg_template,
ini_options.get('msg-template'),
'output message template')

args.output_file = _log_option_source(
args.output_file,
ini_options.get('output'),
'output file')

args.baseline = _log_option_source(
args.baseline,
ini_options.get('baseline'),
'path of a baseline report')
_handle_bool_in_ini(ini_options, args)


def main():
# bring our logging stuff up as early as possible
debug = (logging.DEBUG if '-d' in sys.argv or '--debug' in sys.argv else
Expand All @@ -169,7 +272,7 @@ def main():
)
parser.add_argument(
'-r', '--recursive', dest='recursive',
action='store_const', const=True,
action='store_true', default=None,
help='find and process files in subdirectories'
)
parser.add_argument(
Expand Down Expand Up @@ -234,20 +337,20 @@ def main():
)
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument(
'-v', '--verbose', dest='verbose', action='store_true',
'-v', '--verbose', dest='verbose', action='store_true', default=None,
help='output extra information like excluded and included files'
)
parser.add_argument(
'-d', '--debug', dest='debug', action='store_true',
'-d', '--debug', dest='debug', action='store_true', default=None,
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'
default=None, 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'
default=None, help='do not skip lines with # nosec comments'
)
parser.add_argument(
'-x', '--exclude', dest='excluded_paths', action='store',
Expand All @@ -265,21 +368,17 @@ def main():
'--ini', dest='ini_path', action='store', default=None,
help='path to an ini 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')
parser.add_argument(
'--exit-zero', action='store_true', dest='exit_zero',
default=None, help='exit with 0, even with results found'
)
python_ver = sys.version.replace('\n', '')
parser.add_argument(
'--version', action='version',
version='%(prog)s {version}\n python version = {python}'.format(
version=bandit.__version__, python=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 = ["%s\t%s" % (a[0], a[1].name) for a in
extension_mgr.plugins_by_id.items()]
blacklist_info = []
Expand Down Expand Up @@ -332,103 +431,7 @@ def main():

# 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.excluded_paths = _log_option_source(
args.excluded_paths,
ini_options.get('exclude'),
'excluded paths')

args.skips = _log_option_source(
args.skips,
ini_options.get('skips'),
'skipped tests')

args.tests = _log_option_source(
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(
args.targets,
ini_targets,
'selected targets')

# TODO(tmcpeak): any other useful options to pass from .bandit?

ini_recursive = ini_options.get('recursive')
if ini_recursive and args.recursive is None:
# In this case, the ini file provides the intended config
args.recursive = ini_recursive

args.agg_type = _log_option_source(
args.agg_type,
ini_options.get('aggregate'),
'aggregate output type')

args.context_lines = _log_option_source(
args.context_lines,
ini_options.get('number'),
'max code lines output for issue')

args.profile = _log_option_source(
args.profile,
ini_options.get('profile'),
'profile')

args.severity = _log_option_source(
args.severity,
ini_options.get('level'),
'severity level')

args.confidence = _log_option_source(
args.confidence,
ini_options.get('confidence'),
'confidence level')

args.output_format = _log_option_source(
args.output_format,
ini_options.get('format'),
'output format')

args.msg_template = _log_option_source(
args.msg_template,
ini_options.get('msg-template'),
'output message template')

args.output_file = _log_option_source(
args.output_file,
ini_options.get('output'),
'output file')

args.verbose = _log_option_source(
args.verbose,
ini_options.get('verbose'),
'output extra information')

args.debug = _log_option_source(
args.debug,
ini_options.get('debug'),
'debug mode')

args.quiet = _log_option_source(
args.quiet,
ini_options.get('quiet'),
'silent mode')

args.ignore_nosec = _log_option_source(
args.ignore_nosec,
ini_options.get('ignore-nosec'),
'do not skip lines with # nosec')

args.baseline = _log_option_source(
args.baseline,
ini_options.get('baseline'),
'path of a baseline report')
_handle_ini_options(ini_options, args)

# If no target has been set through args or ini file, then use a default
if not args.targets:
Expand Down
17 changes: 16 additions & 1 deletion bandit/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,22 @@ def parse_ini_file(f_loc):
config = configparser.ConfigParser()
try:
config.read(f_loc)
return {k: v for k, v in config.items('bandit')}
bool_params = [
'recursive',
'verbose',
'debug',
'quiet',
'ignore-nosec',
'exit-zero'
]
options = {k: v for k, v in config['bandit'].items()}
for bool_param in bool_params:
if config['bandit'].getboolean(bool_param) is not None:
options.update(
{bool_param: config['bandit'].getboolean(bool_param)}
)

return options

except (configparser.Error, KeyError, TypeError):
LOG.debug("Config file %s not found or missing [bandit] "
Expand Down
1 change: 1 addition & 0 deletions examples/ini_file_test/okay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print('hopefully no vulnerabilities here')
1 change: 1 addition & 0 deletions examples/ini_file_test/recursive2/okay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print('hopefully no vulnerabilities here')
2 changes: 2 additions & 0 deletions examples/ini_file_test/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[bandit]
recursive=false
18 changes: 18 additions & 0 deletions tests/functional/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ def test_recurse(self):
self.assertIn("Files skipped (0):", output)
self.assertIn("No issues identified.", output)

def test_ini_file_override(self):
"""Tests that ini file properly overrides default values"""
(retcode, output) = self._test_runtime(['bandit',
'examples/ini_file_test'])
self.assertEqual(0, retcode)
self.assertIn("Total lines of code: 2", output)
self.assertIn("Files skipped (0):", output)
self.assertIn("No issues identified.", output)

def test_cli_before_ini_file(self):
"""Tests that ini file doesn't override cli args"""
(retcode, output) = self._test_runtime(['bandit', '-r',
'examples/ini_file_test'])
self.assertEqual(0, retcode)
self.assertIn("Total lines of code: 2", output)
self.assertIn("Files skipped (0):", output)
self.assertIn("No issues identified.", output)

def test_example_nonsense(self):
(retcode, output) = self._test_example(['bandit', ], ['nonsense.py', ])
self.assertEqual(0, retcode)
Expand Down
10 changes: 6 additions & 4 deletions tests/unit/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def tearDown(self):
def test_get_options_from_ini_no_ini_path_no_target(self):
# Test that no config options are loaded when no ini path or target
# directory are provided
self.assertIsNone(bandit._get_options_from_ini(None, []))
self.assertEqual(bandit._get_options_from_ini(None, []), {})

def test_get_options_from_ini_empty_directory_no_target(self):
# Test that no config options are loaded when an empty directory is
Expand All @@ -109,10 +109,12 @@ def test_get_options_from_ini_empty_directory_no_target(self):

def test_get_options_from_ini_no_ini_path_no_bandit_files(self):
# Test that no config options are loaded when no ini path is provided
# and the target directory contains no bandit config files (.bandit)
# and the target directory contains no bandit config files
target_directory = self.useFixture(fixtures.TempDir()).path
self.assertIsNone(bandit._get_options_from_ini(None,
[target_directory]))
self.assertEqual(
bandit._get_options_from_ini(None, [target_directory]),
{}
)

def test_get_options_from_ini_no_ini_path_multi_bandit_files(self):
# Test that bandit exits when no ini path is provided and the target
Expand Down

0 comments on commit a82aa79

Please sign in to comment.