Add capability to pipe a file into bandit
Allows someone to feed a file/text into bandit from a pipe rather than just the 'targets' argument. Usage example: cat examples/imports.py | bandit - Change-Id: I1566684c0ae5476374960095816cb1720ff465a2
This commit is contained in:
parent
3cf14c773e
commit
aae396e9bc
|
@ -73,6 +73,11 @@ using only the plugins listed in the ``ShellInjection`` profile::
|
|||
|
||||
bandit examples/*.py -p ShellInjection
|
||||
|
||||
Bandit also supports passing lines of code to scan using standard input. To
|
||||
run Bandit with standard input::
|
||||
|
||||
cat examples/imports.py | bandit -
|
||||
|
||||
Usage::
|
||||
|
||||
$ bandit -h
|
||||
|
|
|
@ -222,48 +222,12 @@ class BanditManager():
|
|||
sys.stderr.write("%s.. " % count)
|
||||
sys.stderr.flush()
|
||||
try:
|
||||
with open(fname, 'rb') as fdata:
|
||||
try:
|
||||
# parse the current file
|
||||
data = fdata.read()
|
||||
lines = data.splitlines()
|
||||
self.metrics.begin(fname)
|
||||
self.metrics.count_locs(lines)
|
||||
if self.ignore_nosec:
|
||||
nosec_lines = set()
|
||||
else:
|
||||
nosec_lines = set(
|
||||
lineno + 1 for
|
||||
(lineno, line) in enumerate(lines)
|
||||
if b'#nosec' in line or b'# nosec' in line)
|
||||
score = self._execute_ast_visitor(fname, data,
|
||||
nosec_lines)
|
||||
self.scores.append(score)
|
||||
self.metrics.count_issues([score, ])
|
||||
except KeyboardInterrupt as e:
|
||||
sys.exit(2)
|
||||
except SyntaxError as e:
|
||||
self.skipped.append((
|
||||
fname,
|
||||
"syntax error while parsing AST from file"
|
||||
))
|
||||
new_files_list.remove(fname)
|
||||
except Exception as e:
|
||||
LOG.error(
|
||||
"Exception occurred when executing tests against "
|
||||
"%s. Run \"bandit --debug %s\" to see the full "
|
||||
"traceback.", fname, fname
|
||||
)
|
||||
self.skipped.append(
|
||||
(fname, 'exception while scanning file')
|
||||
)
|
||||
new_files_list.remove(fname)
|
||||
LOG.debug(" Exception string: %s", e)
|
||||
LOG.debug(
|
||||
" Exception traceback: %s",
|
||||
traceback.format_exc()
|
||||
)
|
||||
continue
|
||||
if fname == '-':
|
||||
sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
|
||||
self._parse_file('<stdin>', sys.stdin, new_files_list)
|
||||
else:
|
||||
with open(fname, 'rb') as fdata:
|
||||
self._parse_file(fname, fdata, new_files_list)
|
||||
except IOError as e:
|
||||
self.skipped.append((fname, e.strerror))
|
||||
new_files_list.remove(fname)
|
||||
|
@ -278,6 +242,38 @@ class BanditManager():
|
|||
# do final aggregation of metrics
|
||||
self.metrics.aggregate()
|
||||
|
||||
def _parse_file(self, fname, fdata, new_files_list):
|
||||
try:
|
||||
# parse the current file
|
||||
data = fdata.read()
|
||||
lines = data.splitlines()
|
||||
self.metrics.begin(fname)
|
||||
self.metrics.count_locs(lines)
|
||||
if self.ignore_nosec:
|
||||
nosec_lines = set()
|
||||
else:
|
||||
nosec_lines = set(
|
||||
lineno + 1 for
|
||||
(lineno, line) in enumerate(lines)
|
||||
if b'#nosec' in line or b'# nosec' in line)
|
||||
score = self._execute_ast_visitor(fname, data, nosec_lines)
|
||||
self.scores.append(score)
|
||||
self.metrics.count_issues([score, ])
|
||||
except KeyboardInterrupt as e:
|
||||
sys.exit(2)
|
||||
except SyntaxError as e:
|
||||
self.skipped.append((fname,
|
||||
"syntax error while parsing AST from file"))
|
||||
new_files_list.remove(fname)
|
||||
except Exception as e:
|
||||
LOG.error("Exception occurred when executing tests against "
|
||||
"%s. Run \"bandit --debug %s\" to see the full "
|
||||
"traceback.", fname, fname)
|
||||
self.skipped.append((fname, 'exception while scanning file'))
|
||||
new_files_list.remove(fname)
|
||||
LOG.debug(" Exception string: %s", e)
|
||||
LOG.debug(" Exception traceback: %s", traceback.format_exc())
|
||||
|
||||
def _execute_ast_visitor(self, fname, data, nosec_lines):
|
||||
'''Execute AST parse on each file
|
||||
|
||||
|
|
|
@ -88,6 +88,11 @@ using only the plugins listed in the ShellInjection profile::
|
|||
|
||||
bandit examples/*.py -p ShellInjection
|
||||
|
||||
Bandit also supports passing lines of code to scan using standard input. To
|
||||
run Bandit with standard input::
|
||||
|
||||
cat examples/imports.py | bandit -
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ import testtools
|
|||
|
||||
class RuntimeTests(testtools.TestCase):
|
||||
|
||||
def _test_runtime(self, cmdlist):
|
||||
def _test_runtime(self, cmdlist, infile=None):
|
||||
process = subprocess.Popen(
|
||||
cmdlist,
|
||||
stdin=subprocess.PIPE,
|
||||
stdin=infile if infile else subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
close_fds=True
|
||||
|
@ -38,7 +38,6 @@ class RuntimeTests(testtools.TestCase):
|
|||
cmdlist.append(os.path.join(os.getcwd(), 'examples', t))
|
||||
return self._test_runtime(cmdlist)
|
||||
|
||||
# test direct execution of bandit
|
||||
def test_no_arguments(self):
|
||||
(retcode, output) = self._test_runtime(['bandit', ])
|
||||
self.assertEqual(2, retcode)
|
||||
|
@ -47,6 +46,18 @@ class RuntimeTests(testtools.TestCase):
|
|||
else:
|
||||
self.assertIn("arguments are required: targets", output)
|
||||
|
||||
def test_piped_input(self):
|
||||
with open('examples/imports.py', 'r') as infile:
|
||||
(retcode, output) = self._test_runtime(['bandit', '-'], infile)
|
||||
self.assertEqual(1, retcode)
|
||||
self.assertIn("Total lines of code: 4", output)
|
||||
self.assertIn("Low: 2", output)
|
||||
self.assertIn("High: 2", output)
|
||||
self.assertIn("Files skipped (0):", output)
|
||||
self.assertIn("Issue: [B403:blacklist] Consider possible", output)
|
||||
self.assertIn("<stdin>:2", output)
|
||||
self.assertIn("<stdin>:4", output)
|
||||
|
||||
def test_nonexistent_config(self):
|
||||
(retcode, output) = self._test_runtime([
|
||||
'bandit', '-c', 'nonexistent.yml', 'xx.py'
|
||||
|
|
Loading…
Reference in New Issue