Skip to content

Commit 442a692

Browse files
committed
Use .gitignore as part of the excluded file list
When using Bandit to scan projects based on Git source control, it would be benefitual to ignore files based on the patterns in the .gitignore file. Today, Bandit has some default excludes that get overridden if a user passes in other excludes. This is a bit confusing to the end user. But it also serves a purpose similar to .gitignore in that the paths excluded by default are typically included in a .gitignore. Note, it will only check for .gitignore files in top-level directories specified on the Bandit command line as targets. It does not recursive look for .gitignore files. This is done because recursive searching for .gitignore files would be complex to add to Bandit existing file discovery. This change adds a new Apache 2 licensed dependency of ignorelib. Fixes #826 Signed-off-by: Eric Brown <[email protected]>
1 parent 0779eb0 commit 442a692

File tree

5 files changed

+25
-10
lines changed

5 files changed

+25
-10
lines changed

bandit/cli/main.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@ def main():
340340
help="comma-separated list of paths (glob patterns "
341341
"supported) to exclude from scan "
342342
"(note that these are in addition to the excluded "
343-
"paths provided in the config file) (default: "
343+
"paths provided in the config file and any files "
344+
"matching patterns defined in .gitignore) (default: "
344345
+ ",".join(constants.EXCLUDE)
345346
+ ")",
346347
)

bandit/core/manager.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import tokenize
1414
import traceback
1515

16+
import ignorelib
1617
from rich import progress
1718

1819
from bandit.core import constants as b_constants
@@ -226,10 +227,11 @@ def discover_files(self, targets, recursive=False, excluded_paths=""):
226227
if os.path.isdir(fname):
227228
if recursive:
228229
new_files, newly_excluded = _get_files_from_dir(
229-
fname,
230+
_build_gitignore_mgr(fname),
230231
included_globs=included_globs,
231232
excluded_path_strings=excluded_path_globs,
232233
)
234+
233235
files_list.update(new_files)
234236
excluded_files.update(newly_excluded)
235237
else:
@@ -238,7 +240,6 @@ def discover_files(self, targets, recursive=False, excluded_paths=""):
238240
"scan contents",
239241
fname,
240242
)
241-
242243
else:
243244
# if the user explicitly mentions a file on command line,
244245
# we'll scan it, regardless of whether it's in the included
@@ -365,8 +366,17 @@ def _execute_ast_visitor(self, fname, fdata, data, nosec_lines):
365366
return score
366367

367368

369+
def _build_gitignore_mgr(path):
370+
return ignorelib.IgnoreFilterManager.build(
371+
path,
372+
global_ignore_file_paths=[],
373+
global_patterns=[],
374+
ignore_file_name=".gitignore",
375+
)
376+
377+
368378
def _get_files_from_dir(
369-
files_dir, included_globs=None, excluded_path_strings=None
379+
ignore_mgr, included_globs=None, excluded_path_strings=None
370380
):
371381
if not included_globs:
372382
included_globs = ["*.py"]
@@ -376,7 +386,7 @@ def _get_files_from_dir(
376386
files_list = set()
377387
excluded_files = set()
378388

379-
for root, _, files in os.walk(files_dir):
389+
for root, _, files in ignore_mgr.walk():
380390
for filename in files:
381391
path = os.path.join(root, filename)
382392
if _is_file_included(path, included_globs, excluded_path_strings):

doc/source/man/bandit.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ OPTIONS
6262
comma-separated list of paths (glob patterns
6363
supported) to exclude from scan (note that these are
6464
in addition to the excluded paths provided in the
65-
config file) (default:
65+
config file and any files matching patterns defined in
66+
.gitignore) (default:
6667
.svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg)
6768
-b BASELINE, --baseline BASELINE
6869
path of a baseline report to compare against (only

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ PyYAML>=5.3.1 # MIT
66
stevedore>=1.20.0 # Apache-2.0
77
colorama>=0.3.9;platform_system=="Windows" # BSD License (3 clause)
88
rich # MIT
9+
ignorelib # Apache-2.0

tests/unit/core/test_manager.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,17 @@ def test_is_file_included(self):
113113
self.assertFalse(e)
114114
self.assertTrue(f)
115115

116-
@mock.patch("os.walk")
117-
def test_get_files_from_dir(self, os_walk):
118-
os_walk.return_value = [
116+
def test_get_files_from_dir(self):
117+
ignore_walk = mock.Mock()
118+
ignore_walk.walk.return_value = [
119119
("/", ("a"), ()),
120120
("/a", (), ("a.py", "b.py", "c.ww")),
121121
]
122122

123123
inc, exc = manager._get_files_from_dir(
124-
files_dir="", included_globs=["*.py"], excluded_path_strings=None
124+
ignore_mgr=ignore_walk,
125+
included_globs=["*.py"],
126+
excluded_path_strings=None,
125127
)
126128

127129
self.assertEqual({"/a/c.ww"}, exc)

0 commit comments

Comments
 (0)