Skip to content

Commit a003d11

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 PyCQA#826 Signed-off-by: Eric Brown <[email protected]>
1 parent 0779eb0 commit a003d11

File tree

5 files changed

+27
-10
lines changed

5 files changed

+27
-10
lines changed

bandit/cli/main.py

Lines changed: 2 additions & 1 deletion
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

Lines changed: 16 additions & 4 deletions
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
@@ -225,11 +226,14 @@ def discover_files(self, targets, recursive=False, excluded_paths=""):
225226
# if this is a directory and recursive is set, find all files
226227
if os.path.isdir(fname):
227228
if recursive:
229+
gitignore_mgr = _build_gitignore_mgr(fname)
230+
228231
new_files, newly_excluded = _get_files_from_dir(
229-
fname,
232+
gitignore_mgr,
230233
included_globs=included_globs,
231234
excluded_path_strings=excluded_path_globs,
232235
)
236+
233237
files_list.update(new_files)
234238
excluded_files.update(newly_excluded)
235239
else:
@@ -238,7 +242,6 @@ def discover_files(self, targets, recursive=False, excluded_paths=""):
238242
"scan contents",
239243
fname,
240244
)
241-
242245
else:
243246
# if the user explicitly mentions a file on command line,
244247
# we'll scan it, regardless of whether it's in the included
@@ -365,8 +368,17 @@ def _execute_ast_visitor(self, fname, fdata, data, nosec_lines):
365368
return score
366369

367370

371+
def _build_gitignore_mgr(path):
372+
return ignorelib.IgnoreFilterManager.build(
373+
path,
374+
global_ignore_file_paths=[],
375+
global_patterns=[],
376+
ignore_file_name=".gitignore",
377+
)
378+
379+
368380
def _get_files_from_dir(
369-
files_dir, included_globs=None, excluded_path_strings=None
381+
ignore_mgr, included_globs=None, excluded_path_strings=None
370382
):
371383
if not included_globs:
372384
included_globs = ["*.py"]
@@ -376,7 +388,7 @@ def _get_files_from_dir(
376388
files_list = set()
377389
excluded_files = set()
378390

379-
for root, _, files in os.walk(files_dir):
391+
for root, _, files in ignore_mgr.walk():
380392
for filename in files:
381393
path = os.path.join(root, filename)
382394
if _is_file_included(path, included_globs, excluded_path_strings):

doc/source/man/bandit.rst

Lines changed: 2 additions & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 6 additions & 4 deletions
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)