Skip to content

Commit

Permalink
Interpret wildcards in the file exclusion list (#450)
Browse files Browse the repository at this point in the history
This allows to specify wildcards in the excluded files list, which in
turns makes it possible to use Bandit in projects where test files are
not in a separate repository, but have just a name prefixed with test_
(as is common with Pytest).

* bandit.core.manager: reuse _matches_glob_list for exclusion list
* fix pep8: remove superfluous blank line
* update documentation: -x accepts glob patterns
* add failing test showing that exclude file globs are not supported
  • Loading branch information
Thibaut Le Page authored and ericwb committed Apr 12, 2019
1 parent 2a1dbab commit fb18e17
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 18 deletions.
8 changes: 4 additions & 4 deletions README.rst
Expand Up @@ -143,9 +143,9 @@ Usage::
only show output in the case of an error
--ignore-nosec do not skip lines with # nosec comments
-x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
comma-separated list of paths to exclude from scan
(note that these are in addition to the excluded paths
provided in the config file)
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)
-b BASELINE, --baseline BASELINE
path of a baseline report to compare against (only
JSON-formatted files are accepted)
Expand Down Expand Up @@ -289,7 +289,7 @@ Configuration
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
scanning (glob patterns supported)
- overridden plugin settings - may provide different settings for some
plugins

Expand Down
3 changes: 2 additions & 1 deletion bandit/cli/main.py
Expand Up @@ -235,7 +235,8 @@ def main():
)
parser.add_argument(
'-x', '--exclude', dest='excluded_paths', action='store',
default='', help='comma-separated list of paths to exclude from scan '
default='', 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)'
)
Expand Down
13 changes: 7 additions & 6 deletions bandit/core/manager.py
Expand Up @@ -184,13 +184,13 @@ def discover_files(self, targets, recursive=False, excluded_paths=''):
files_list = set()
excluded_files = set()

excluded_path_strings = self.b_conf.get_option('exclude_dirs') or []
excluded_path_globs = self.b_conf.get_option('exclude_dirs') or []
included_globs = self.b_conf.get_option('include') or ['*.py']

# if there are command line provided exclusions add them to the list
if excluded_paths:
for path in excluded_paths.split(','):
excluded_path_strings.append(path)
excluded_path_globs.append(path)

# build list of files we will analyze
for fname in targets:
Expand All @@ -200,7 +200,7 @@ def discover_files(self, targets, recursive=False, excluded_paths=''):
new_files, newly_excluded = _get_files_from_dir(
fname,
included_globs=included_globs,
excluded_path_strings=excluded_path_strings
excluded_path_strings=excluded_path_globs
)
files_list.update(new_files)
excluded_files.update(newly_excluded)
Expand All @@ -213,7 +213,7 @@ def discover_files(self, targets, recursive=False, excluded_paths=''):
# we'll scan it, regardless of whether it's in the included
# file types list
if _is_file_included(fname, included_globs,
excluded_path_strings,
excluded_path_globs,
enforce_glob=False):
files_list.add(fname)
else:
Expand Down Expand Up @@ -353,7 +353,8 @@ def _is_file_included(path, included_globs, excluded_path_strings,
:param path: Full path of file to check
:param parsed_extensions: List of parsed extensions
:param excluded_paths: List of paths from which we should not include files
:param excluded_paths: List of paths (globbing supported) from which we
should not include files
:param enforce_glob: Can set to false to bypass extension check
:return: Boolean indicating whether a file should be included
'''
Expand All @@ -362,7 +363,7 @@ def _is_file_included(path, included_globs, excluded_path_strings,
# if this is matches a glob of files we look at, and it isn't in an
# excluded path
if _matches_glob_list(path, included_globs) or not enforce_glob:
if not any(x in path for x in excluded_path_strings):
if not _matches_glob_list(path, excluded_path_strings):
return_value = True

return return_value
Expand Down
6 changes: 3 additions & 3 deletions doc/source/man/bandit.rst
Expand Up @@ -59,9 +59,9 @@ OPTIONS
only show output in the case of an error
--ignore-nosec do not skip lines with # nosec comments
-x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
comma-separated list of paths to exclude from scan
(note that these are in addition to the excluded paths
provided in the config file)
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)
-b BASELINE, --baseline BASELINE
path of a baseline report to compare against (only
JSON-formatted files are accepted)
Expand Down
26 changes: 22 additions & 4 deletions tests/unit/core/test_manager.py
Expand Up @@ -70,24 +70,34 @@ def test_matches_globlist(self):

def test_is_file_included(self):
a = manager._is_file_included(path='a.py', included_globs=['*.py'],
excluded_path_strings='',
excluded_path_strings=[],
enforce_glob=True)

b = manager._is_file_included(path='a.dd', included_globs=['*.py'],
excluded_path_strings='',
excluded_path_strings=[],
enforce_glob=False)

c = manager._is_file_included(path='a.py', included_globs=['*.py'],
excluded_path_strings='a.py',
excluded_path_strings=['a.py'],
enforce_glob=True)

d = manager._is_file_included(path='a.dd', included_globs=['*.py'],
excluded_path_strings='',
excluded_path_strings=[],
enforce_glob=True)

e = manager._is_file_included(path='x_a.py', included_globs=['*.py'],
excluded_path_strings=['x_*.py'],
enforce_glob=True)

f = manager._is_file_included(path='x.py', included_globs=['*.py'],
excluded_path_strings=['x_*.py'],
enforce_glob=True)
self.assertTrue(a)
self.assertTrue(b)
self.assertFalse(c)
self.assertFalse(d)
self.assertFalse(e)
self.assertTrue(f)

@mock.patch('os.walk')
def test_get_files_from_dir(self, os_walk):
Expand Down Expand Up @@ -209,6 +219,14 @@ def test_discover_files_exclude_cmdline(self, isdir):
m.assert_called_with('c', ['*.py', '*.pyw'], ['a', 'b'],
enforce_glob=False)

@mock.patch('os.path.isdir')
def test_discover_files_exclude_glob(self, isdir):
isdir.return_value = False
self.manager.discover_files(['a.py', 'test_a.py', 'test.py'], True,
excluded_paths='test_*.py')
self.assertEqual(['a.py', 'test.py'], self.manager.files_list)
self.assertEqual(['test_a.py'], self.manager.excluded_files)

@mock.patch('os.path.isdir')
def test_discover_files_include(self, isdir):
isdir.return_value = False
Expand Down

0 comments on commit fb18e17

Please sign in to comment.