Add Python 3.4 compatibility to bandit
This includes a number of changes to make this happen: - We handle the fact that in Python 3.3 and later, ast.TryExcept and ast.TryFinally were replaced by ast.Try - We handle the fact that ast.NameConstant is now the node type for True/False - We handle the cases where map and range need to return lists - We remove a property from the result store to prevent errors assigning to the underlying attribute - We check for exec conditionally based on the version of Python - We use proper octal notation, e.g., 0o755 Change-Id: I71c0bb61c9ee0bf1b751a719a4eb95bf7a0b4943
This commit is contained in:
parent
e7bf93f742
commit
ddf75663ce
@ -54,4 +54,4 @@ CONFIDENCE_DEFAULT = 'UNDEFINED'
|
||||
# These are only useful when we have a constant in code. If we
|
||||
# have a variable we cannot determine if False.
|
||||
# See https://docs.python.org/2/library/stdtypes.html#truth-value-testing
|
||||
FALSE_VALUES = [None, False, 'False', 0, 0L, 0.0, 0j, '', (), [], {}]
|
||||
FALSE_VALUES = [None, False, 'False', 0, 0.0, 0j, '', (), [], {}]
|
||||
|
@ -220,6 +220,9 @@ class Context():
|
||||
elif isinstance(literal, _ast.Name):
|
||||
return literal.id
|
||||
|
||||
elif hasattr(literal, 'value'):
|
||||
return str(literal.value)
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
|
@ -23,6 +23,12 @@ from bandit.core import utils as b_utils
|
||||
from bandit.core.utils import InvalidModulePath
|
||||
|
||||
|
||||
if hasattr(ast, 'TryExcept'):
|
||||
ast_Try = (ast.TryExcept, ast.TryFinally)
|
||||
else: # Python 3.3+
|
||||
ast_Try = ast.Try
|
||||
|
||||
|
||||
class StatementBuffer():
|
||||
'''Buffer for code statements
|
||||
|
||||
@ -82,20 +88,15 @@ class StatementBuffer():
|
||||
tmp_buf = stmt.body
|
||||
stmt.body = []
|
||||
stmt.orelse = []
|
||||
elif (isinstance(stmt, ast.TryExcept)):
|
||||
for handler in stmt.handlers:
|
||||
elif isinstance(stmt, ast_Try):
|
||||
for handler in getattr(stmt, 'handlers', []):
|
||||
stmt.body.extend(handler.body)
|
||||
stmt.body.extend(stmt.orelse)
|
||||
stmt.body.extend(getattr(stmt, 'orelse', []))
|
||||
stmt.body.extend(tmp_buf)
|
||||
tmp_buf = stmt.body
|
||||
stmt.body = []
|
||||
stmt.orelse = []
|
||||
stmt.handlers = []
|
||||
elif (isinstance(stmt, ast.TryFinally)):
|
||||
stmt.body.extend(stmt.finalbody)
|
||||
stmt.body.extend(tmp_buf)
|
||||
tmp_buf = stmt.body
|
||||
stmt.body = []
|
||||
stmt.finalbody = []
|
||||
|
||||
# once we are sure it's either a single statement or that
|
||||
@ -386,9 +387,9 @@ class BanditNodeVisitor(ast.NodeVisitor):
|
||||
def add(x, y):
|
||||
return x + y
|
||||
for score_type in self.scores:
|
||||
self.scores[score_type] = map(
|
||||
self.scores[score_type] = list(map(
|
||||
add, self.scores[score_type], scores[score_type]
|
||||
)
|
||||
))
|
||||
|
||||
def process(self, fdata):
|
||||
'''Main process loop
|
||||
|
@ -47,14 +47,6 @@ class BanditResultStore():
|
||||
self.format = 'txt'
|
||||
self.out_file = None
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
'''Count property - used to get the current number of test results
|
||||
|
||||
:return: The current count of test results
|
||||
'''
|
||||
return self.count
|
||||
|
||||
def skip(self, filename, reason):
|
||||
'''Indicates that the specified file was skipped and why
|
||||
|
||||
|
@ -13,15 +13,26 @@
|
||||
# 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 six
|
||||
|
||||
import bandit
|
||||
from bandit.core.test_properties import *
|
||||
|
||||
|
||||
@checks('Exec')
|
||||
def exec_used(context):
|
||||
def exec_issue():
|
||||
return bandit.Issue(
|
||||
severity=bandit.MEDIUM,
|
||||
confidence=bandit.HIGH,
|
||||
text="Use of exec detected."
|
||||
)
|
||||
|
||||
|
||||
if six.PY2:
|
||||
@checks('Exec')
|
||||
def exec_used(context):
|
||||
return exec_issue()
|
||||
else:
|
||||
@checks('Call')
|
||||
def exec_used(context):
|
||||
if context.call_function_name_qual == 'exec':
|
||||
return exec_issue()
|
||||
|
@ -31,7 +31,8 @@ def jinja2_autoescape_false(context):
|
||||
if isinstance(node, ast.keyword):
|
||||
# definite autoescape = False
|
||||
if (getattr(node, 'arg', None) == 'autoescape' and
|
||||
getattr(node.value, 'id', None) == 'False'):
|
||||
(getattr(node.value, 'id', None) == 'False' or
|
||||
getattr(node.value, 'value', None) is False)):
|
||||
return bandit.Issue(
|
||||
severity=bandit.HIGH,
|
||||
confidence=bandit.HIGH,
|
||||
@ -42,7 +43,8 @@ def jinja2_autoescape_false(context):
|
||||
)
|
||||
# found autoescape
|
||||
if getattr(node, 'arg', None) == 'autoescape':
|
||||
if(getattr(node.value, 'id', None) == 'True'):
|
||||
if (getattr(node.value, 'id', None) == 'True' or
|
||||
getattr(node.value, 'value', None) is True):
|
||||
return
|
||||
else:
|
||||
return bandit.Issue(
|
||||
|
@ -17,6 +17,7 @@ classifier =
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3.4
|
||||
Topic :: Security
|
||||
|
||||
[entry_points]
|
||||
|
@ -73,4 +73,4 @@ class StatementBufferTests(unittest.TestCase):
|
||||
self.assertEqual(3, len(stmt['linerange']))
|
||||
|
||||
# the range should be the correct line numbers
|
||||
self.assertEqual([11, 12, 13], stmt['linerange'])
|
||||
self.assertEqual([11, 12, 13], list(stmt['linerange']))
|
||||
|
@ -56,7 +56,7 @@ class UtilTests(unittest.TestCase):
|
||||
|
||||
# good/a/b/c/test_typical.py
|
||||
os.makedirs(os.path.join(
|
||||
self.tempdir, 'good', 'a', 'b', 'c'), 0755)
|
||||
self.tempdir, 'good', 'a', 'b', 'c'), 0o755)
|
||||
_touch(os.path.join(self.tempdir, 'good', '__init__.py'))
|
||||
_touch(os.path.join(self.tempdir, 'good', 'a', '__init__.py'))
|
||||
_touch(os.path.join(
|
||||
@ -68,7 +68,7 @@ class UtilTests(unittest.TestCase):
|
||||
|
||||
# missingmid/a/b/c/test_missingmid.py
|
||||
os.makedirs(os.path.join(
|
||||
self.tempdir, 'missingmid', 'a', 'b', 'c'), 0755)
|
||||
self.tempdir, 'missingmid', 'a', 'b', 'c'), 0o755)
|
||||
_touch(os.path.join(self.tempdir, 'missingmid', '__init__.py'))
|
||||
# no missingmid/a/__init__.py
|
||||
_touch(os.path.join(
|
||||
@ -80,7 +80,7 @@ class UtilTests(unittest.TestCase):
|
||||
|
||||
# missingend/a/b/c/test_missingend.py
|
||||
os.makedirs(os.path.join(
|
||||
self.tempdir, 'missingend', 'a', 'b', 'c'), 0755)
|
||||
self.tempdir, 'missingend', 'a', 'b', 'c'), 0o755)
|
||||
_touch(os.path.join(
|
||||
self.tempdir, 'missingend', '__init__.py'))
|
||||
_touch(os.path.join(
|
||||
@ -90,7 +90,7 @@ class UtilTests(unittest.TestCase):
|
||||
self.tempdir, 'missingend', 'a', 'b', 'c', 'test_missingend.py'))
|
||||
|
||||
# syms/a/bsym/c/test_typical.py
|
||||
os.makedirs(os.path.join(self.tempdir, 'syms', 'a'), 0755)
|
||||
os.makedirs(os.path.join(self.tempdir, 'syms', 'a'), 0o755)
|
||||
_touch(os.path.join(self.tempdir, 'syms', '__init__.py'))
|
||||
_touch(os.path.join(self.tempdir, 'syms', 'a', '__init__.py'))
|
||||
os.symlink(os.path.join(self.tempdir, 'good', 'a', 'b'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user