Making config optional
This commit removes the requirement for having a config file. Sometimes projects may want to use one to list out tests, define a profile, or override a setting, but they are no longer required. Change-Id: I6e467f58b2b27cae647901ac2c3f75a764e74c0c
This commit is contained in:
parent
67ed78447c
commit
54a06aaebb
32
README.rst
32
README.rst
|
@ -98,8 +98,8 @@ Usage::
|
|||
max number of code lines to display for each issue
|
||||
identified
|
||||
-c CONFIG_FILE, --configfile CONFIG_FILE
|
||||
if omitted default locations are checked. Check
|
||||
documentation for searched paths
|
||||
optional config file to use for selecting plugins and
|
||||
overriding defaults
|
||||
-p PROFILE, --profile PROFILE
|
||||
test set profile in config to use (defaults to all
|
||||
tests)
|
||||
|
@ -193,32 +193,12 @@ Usage::
|
|||
|
||||
Configuration
|
||||
-------------
|
||||
The Bandit config file is used to set several things, including:
|
||||
- profiles - defines group of tests which should or shouldn't be run
|
||||
An optional config file may be supplied and may include:
|
||||
- lists of tests which should or shouldn't be run
|
||||
- exclude_dirs - sections of the path, that if matched, will be excluded from
|
||||
scanning
|
||||
- plugin configs - used to tune plugins, for example: by tuning
|
||||
blacklist_imports, you can set which imports should be flagged
|
||||
- other - plugins directory, included file types, shell display
|
||||
colors, etc.
|
||||
|
||||
Bandit requires a config file which can be specified on the command line via
|
||||
-c/--configfile. If this is not provided Bandit will search for a default
|
||||
config file (bandit.yaml) in the following preference order:
|
||||
|
||||
GNU/Linux:
|
||||
- ./bandit.yaml
|
||||
- ~/.config/bandit/bandit.yaml
|
||||
- /etc/bandit/bandit.yaml
|
||||
- /usr/local/etc/bandit/bandit.yaml
|
||||
- <path to venv>/etc/bandit/bandit.yaml (if running within virtualenv)
|
||||
|
||||
Mac OSX:
|
||||
- ./bandit.yaml
|
||||
- /Users/${USER}/Library/Application Support/bandit/bandit.yaml
|
||||
- /Library/Application Support/bandit/bandit.yaml
|
||||
- /usr/local/etc/bandit/bandit.yaml
|
||||
- <path to venv>/bandit/config/bandit.yaml (if running within virtualenv)
|
||||
- overridden plugin settings - may provide different settings for some
|
||||
plugins
|
||||
|
||||
Per Project Command Line Args
|
||||
-----------------------------
|
||||
|
|
|
@ -18,9 +18,7 @@ import fnmatch
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
import appdirs
|
||||
import six
|
||||
|
||||
import bandit
|
||||
|
@ -115,40 +113,10 @@ def _running_under_virtualenv():
|
|||
return True
|
||||
|
||||
|
||||
def _find_config():
|
||||
# prefer config file in the following order:
|
||||
# 1) current directory, 2) user home directory, 3) bundled config
|
||||
config_dirs = (
|
||||
['.'] + [appdirs.user_config_dir("bandit")] +
|
||||
appdirs.site_config_dir("bandit", multipath=True).split(':'))
|
||||
if _running_under_virtualenv():
|
||||
config_dirs.append(os.path.join(sys.prefix, 'etc', 'bandit'))
|
||||
config_dirs.append(
|
||||
os.path.join(sysconfig.get_paths().get('purelib', ''),
|
||||
'bandit', 'config'))
|
||||
config_locations = [os.path.join(s, BASE_CONFIG) for s in config_dirs]
|
||||
|
||||
# pip on Mac installs to the following path, but appdirs expects to
|
||||
# follow Mac's BPFileSystem spec which doesn't include this path so
|
||||
# we'll insert it. Issue raised as http://git.io/vOreU
|
||||
mac_pip_cfg_path = "/usr/local/etc/bandit/bandit.yaml"
|
||||
if mac_pip_cfg_path not in config_locations:
|
||||
config_locations.append(mac_pip_cfg_path)
|
||||
|
||||
for config_file in config_locations:
|
||||
if os.path.isfile(config_file):
|
||||
return config_file # Found a valid config
|
||||
else:
|
||||
# Failed to find any config, raise an error.
|
||||
raise utils.NoConfigFileFound(config_locations)
|
||||
|
||||
|
||||
def main():
|
||||
# bring our logging stuff up as early as possible
|
||||
debug = ('-d' in sys.argv or '--debug' in sys.argv)
|
||||
_init_logger(debug)
|
||||
# By default path would be /etx/xdg/bandit, we want system paths
|
||||
os.environ['XDG_CONFIG_DIRS'] = '/etc:/usr/local/etc'
|
||||
extension_mgr = _init_extensions()
|
||||
|
||||
baseline_formatters = [f.name for f in filter(lambda x:
|
||||
|
@ -183,8 +151,8 @@ def main():
|
|||
parser.add_argument(
|
||||
'-c', '--configfile', dest='config_file',
|
||||
action='store', default=None, type=str,
|
||||
help=('if omitted default locations are checked. '
|
||||
'Check documentation for searched paths')
|
||||
help=('optional config file to use for selecting plugins and '
|
||||
'overriding defaults')
|
||||
)
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
|
@ -274,16 +242,9 @@ def main():
|
|||
|
||||
# setup work - parse arguments, and initialize BanditManager
|
||||
args = parser.parse_args()
|
||||
config_file = args.config_file
|
||||
if not config_file:
|
||||
try:
|
||||
config_file = _find_config()
|
||||
except utils.NoConfigFileFound as e:
|
||||
logger.error(e)
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
b_conf = b_config.BanditConfig(config_file)
|
||||
b_conf = b_config.BanditConfig(config_file=args.config_file)
|
||||
except (utils.ConfigFileUnopenable, utils.ConfigFileInvalidYaml) as e:
|
||||
logger.error('%s', e)
|
||||
sys.exit(2)
|
||||
|
@ -353,7 +314,9 @@ def main():
|
|||
sys.exit(2)
|
||||
|
||||
if args.output_format != "json":
|
||||
logger.info("using config: %s", config_file)
|
||||
if args.config_file:
|
||||
logger.info("using config: %s", args.config_file)
|
||||
|
||||
logger.info("running on Python %d.%d.%d", sys.version_info.major,
|
||||
sys.version_info.minor, sys.version_info.micro)
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class BanditConfig():
|
|||
'B001' # Built in blacklist test
|
||||
]
|
||||
|
||||
def __init__(self, config_file):
|
||||
def __init__(self, config_file=None):
|
||||
'''Attempt to initialize a config dictionary from a yaml file.
|
||||
|
||||
Error out if loading the yaml file fails for any reason.
|
||||
|
@ -46,20 +46,31 @@ class BanditConfig():
|
|||
|
||||
'''
|
||||
self.config_file = config_file
|
||||
try:
|
||||
f = open(config_file, 'r')
|
||||
except IOError:
|
||||
raise utils.ConfigFileUnopenable(config_file)
|
||||
self._config = {}
|
||||
|
||||
try:
|
||||
self._config = yaml.safe_load(f)
|
||||
except yaml.YAMLError:
|
||||
raise utils.ConfigFileInvalidYaml(config_file)
|
||||
if config_file:
|
||||
try:
|
||||
f = open(config_file, 'r')
|
||||
except IOError:
|
||||
raise utils.ConfigFileUnopenable(config_file)
|
||||
|
||||
try:
|
||||
self._config = yaml.safe_load(f)
|
||||
except yaml.YAMLError:
|
||||
raise utils.ConfigFileInvalidYaml(config_file)
|
||||
|
||||
# valid config must be a dict
|
||||
if not isinstance(self._config, dict):
|
||||
raise utils.ConfigFileInvalidYaml(config_file)
|
||||
|
||||
if self._config:
|
||||
self.convert_legacy_config()
|
||||
self.validate_profiles()
|
||||
|
||||
else:
|
||||
# use sane defaults
|
||||
self._config['plugin_name_pattern'] = '*.py'
|
||||
self._config['include'] = ['*.py', '*.pyw']
|
||||
|
||||
self.validate_profiles()
|
||||
self._init_settings()
|
||||
|
||||
def get_option(self, option_string):
|
||||
|
|
|
@ -79,7 +79,9 @@ class BanditManager():
|
|||
self.scores = []
|
||||
|
||||
def _get_profile(self, profile_name):
|
||||
if profile_name not in self.b_conf.config['profiles']:
|
||||
if(not self.b_conf.get_option('profiles') or
|
||||
profile_name not in self.b_conf.config['profiles']):
|
||||
|
||||
raise utils.ProfileNotFound(self.b_conf.config_file, profile_name)
|
||||
|
||||
profile = self.b_conf.config['profiles'][profile_name]
|
||||
|
|
|
@ -121,13 +121,6 @@ class InvalidModulePath(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class NoConfigFileFound(Exception):
|
||||
def __init__(self, config_locations):
|
||||
message = ("no config found - tried: " +
|
||||
", ".join(config_locations))
|
||||
super(NoConfigFileFound, self).__init__(message)
|
||||
|
||||
|
||||
class ConfigFileUnopenable(Exception):
|
||||
"""Raised when the config file cannot be opened."""
|
||||
def __init__(self, config_file):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
appdirs>=1.3.0 # MIT License
|
||||
GitPython>=1.0.1 # BSD License (3 clause)
|
||||
PyYAML>=3.1.0 # MIT
|
||||
six>=1.9.0 # MIT
|
||||
|
|
|
@ -36,8 +36,8 @@ profiles:
|
|||
- start_process_with_a_shell
|
||||
|
||||
shell_injection:
|
||||
subprocess:
|
||||
|
||||
subprocess: []
|
||||
no_shell: []
|
||||
shell:
|
||||
- os.system
|
||||
"""
|
||||
|
@ -102,7 +102,8 @@ class BanditBaselineToolTests(testtools.TestCase):
|
|||
'benign_two.py'],
|
||||
'expected_return': 0}]
|
||||
|
||||
baseline_command = ['bandit-baseline', '-r', '.', '-p', 'test']
|
||||
baseline_command = ['bandit-baseline', '-c', 'bandit.yaml', '-r', '.',
|
||||
'-p', 'test']
|
||||
|
||||
for branch in branches:
|
||||
branch['branch'] = git_repo.create_head(branch['name'])
|
||||
|
|
|
@ -156,15 +156,6 @@ class BanditCLIMainTests(testtools.TestCase):
|
|||
option_name = 'aggregate'
|
||||
self.assertIsNone(bandit._log_option_source(None, None, option_name))
|
||||
|
||||
@patch('sys.argv', ['bandit', 'test'])
|
||||
def test_main_no_config(self):
|
||||
# Test that bandit exits when a config file cannot be found, raising a
|
||||
# NoConfigFileFound error
|
||||
with patch('bandit.cli.main._find_config') as mock_find_config:
|
||||
mock_find_config.side_effect = utils.NoConfigFileFound('')
|
||||
# assert a SystemExit with code 2
|
||||
self.assertRaisesRegex(SystemExit, '2', bandit.main)
|
||||
|
||||
@patch('sys.argv', ['bandit', '-c', 'bandit.yaml', 'test'])
|
||||
def test_main_config_unopenable(self):
|
||||
# Test that bandit exits when a config file cannot be opened
|
||||
|
@ -299,32 +290,3 @@ class BanditCLIMainTests(testtools.TestCase):
|
|||
mock_mgr_results_ct.return_value = 0
|
||||
# assert a SystemExit with code 0
|
||||
self.assertRaisesRegex(SystemExit, '0', bandit.main)
|
||||
|
||||
|
||||
class BanditCLIMainFindConfigTests(testtools.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BanditCLIMainFindConfigTests, self).setUp()
|
||||
self.current_directory = os.getcwd()
|
||||
|
||||
def tearDown(self):
|
||||
super(BanditCLIMainFindConfigTests, self).tearDown()
|
||||
os.chdir(self.current_directory)
|
||||
|
||||
def test_find_config_no_config(self):
|
||||
# Test that a utils.NoConfigFileFound error is raised when no config
|
||||
# file is found
|
||||
with patch('os.path.isfile') as mock_os_path_isfile:
|
||||
# patch to make sure no config files can be found
|
||||
mock_os_path_isfile.return_value = False
|
||||
self.assertRaises(utils.NoConfigFileFound, bandit._find_config)
|
||||
|
||||
def test_find_config_local_config(self):
|
||||
# Test that when a config file is found is current directory, it is
|
||||
# used as the config file
|
||||
temp_directory = self.useFixture(fixtures.TempDir()).path
|
||||
os.chdir(temp_directory)
|
||||
local_config = "./bandit.yaml"
|
||||
with open(local_config, 'wt') as fd:
|
||||
fd.write(bandit_config_content)
|
||||
self.assertEqual(local_config, bandit._find_config())
|
||||
|
|
|
@ -109,7 +109,8 @@ class TestGetOption(testtools.TestCase):
|
|||
class TestGetSetting(testtools.TestCase):
|
||||
def setUp(self):
|
||||
super(TestGetSetting, self).setUp()
|
||||
f = self.useFixture(TempFile())
|
||||
test_yaml = 'key: value'
|
||||
f = self.useFixture(TempFile(test_yaml))
|
||||
self.b_config = config.BanditConfig(f.name)
|
||||
|
||||
def test_not_exist(self):
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
# Copyright (c) 2015 VMware, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
|
||||
from bandit.cli import main as bandit
|
||||
from bandit.core import utils
|
||||
|
||||
BASE_CONFIG = '/bandit.yaml'
|
||||
|
||||
|
||||
class FindConfigTests(testtools.TestCase):
|
||||
|
||||
def _test(self, directory_with_config=None, user_config_dir=None,
|
||||
site_config_dir=None):
|
||||
|
||||
user_config_dir = user_config_dir or self.getUniqueString()
|
||||
site_config_dir = site_config_dir or self.getUniqueString()
|
||||
|
||||
self.useFixture(
|
||||
fixtures.MockPatch('appdirs.user_config_dir',
|
||||
return_value=user_config_dir))
|
||||
self.useFixture(
|
||||
fixtures.MockPatch('appdirs.site_config_dir',
|
||||
return_value=site_config_dir))
|
||||
|
||||
def is_current_config(arg):
|
||||
if not directory_with_config:
|
||||
return False
|
||||
return arg == (directory_with_config + BASE_CONFIG)
|
||||
|
||||
self.useFixture(
|
||||
fixtures.MockPatch('os.path.isfile', is_current_config))
|
||||
|
||||
found_config = bandit._find_config()
|
||||
exp_config = directory_with_config + BASE_CONFIG
|
||||
self.assertEqual(exp_config, found_config)
|
||||
|
||||
def test_current_directory(self):
|
||||
# the config file in the current directory is returned if it's there.
|
||||
self._test(directory_with_config='.')
|
||||
|
||||
def test_user_home_directory(self):
|
||||
# the config file in the user home directory is returned if there isn't
|
||||
# one in the current directory.
|
||||
user_config_dir = self.getUniqueString()
|
||||
self._test(directory_with_config=user_config_dir,
|
||||
user_config_dir=user_config_dir)
|
||||
|
||||
def test_bundled_config(self):
|
||||
# the bundled config file is returned if there isn't one in the current
|
||||
# directory or user home directory.
|
||||
site_config_dir = self.getUniqueString()
|
||||
self._test(directory_with_config=site_config_dir,
|
||||
site_config_dir=site_config_dir)
|
||||
|
||||
def test_mac_pip_cfg_path(self):
|
||||
# pip on Mac installs to /usr/local/etc/bandit/bandit.yaml and that's
|
||||
# checked, too. See issue at http://git.io/vOreU
|
||||
self._test(directory_with_config='/usr/local/etc/bandit')
|
||||
|
||||
def test_not_found(self):
|
||||
# NoConfigFileFound is raised if there's no config in any location.
|
||||
self.assertRaises(utils.NoConfigFileFound, self._test)
|
||||
|
||||
def test_bundled_config_split(self):
|
||||
# the bundled config can return a path separated by : and all those
|
||||
# paths are searched in order.
|
||||
dirs = [self.getUniqueString(), self.getUniqueString()]
|
||||
site_config_dirs = ':'.join(dirs)
|
||||
|
||||
# Check all the directories
|
||||
for dir in dirs:
|
||||
self._test(directory_with_config=dir,
|
||||
site_config_dir=site_config_dirs)
|
Loading…
Reference in New Issue