Skip to content

Commit

Permalink
Update setup.cfg
Browse files Browse the repository at this point in the history
Signed-off-by: Eric Brown <[email protected]>
  • Loading branch information
ericwb committed Oct 16, 2024
1 parent c4af4a8 commit 4d94bd8
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 76 deletions.
4 changes: 2 additions & 2 deletions bandit/core/blacklisting.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def blacklist(context, config):
func = context.node.func
if isinstance(func, ast.Name) and func.id == "__import__":
if len(context.node.args):
if isinstance(context.node.args[0], ast.Str):
name = context.node.args[0].s
if isinstance(context.node.args[0], ast.Constant):
name = context.node.args[0].value
else:
# TODO(??): import through a variable, need symbol tab
name = "UNKNOWN"
Expand Down
22 changes: 7 additions & 15 deletions bandit/core/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,13 @@ def _get_literal_value(self, literal):
:param literal: The AST literal to convert
:return: The value of the AST literal
"""
if isinstance(literal, ast.Num):
literal_value = literal.n

elif isinstance(literal, ast.Str):
literal_value = literal.s
if isinstance(literal, ast.Constant):
if isinstance(literal.value, bool):
literal_value = str(literal.value)
elif literal.value is None:
literal_value = str(literal.value)
else:
literal_value = literal.value

elif isinstance(literal, ast.List):
return_list = list()
Expand All @@ -205,19 +207,9 @@ def _get_literal_value(self, literal):
elif isinstance(literal, ast.Dict):
literal_value = dict(zip(literal.keys, literal.values))

elif isinstance(literal, ast.Ellipsis):
# what do we want to do with this?
literal_value = None

elif isinstance(literal, ast.Name):
literal_value = literal.id

elif isinstance(literal, ast.NameConstant):
literal_value = str(literal.value)

elif isinstance(literal, ast.Bytes):
literal_value = literal.s

else:
literal_value = None

Expand Down
5 changes: 3 additions & 2 deletions bandit/core/node_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ast
import logging
import operator
import sys

from bandit.core import constants
from bandit.core import tester as b_tester
Expand Down Expand Up @@ -168,7 +169,7 @@ def visit_Str(self, node):
:param node: The node that is being inspected
:return: -
"""
self.context["str"] = node.s
self.context["str"] = node.value
if not isinstance(node._bandit_parent, ast.Expr): # docstring
self.context["linerange"] = b_utils.linerange(node._bandit_parent)
self.update_scores(self.tester.run_tests(self.context, "Str"))
Expand All @@ -181,7 +182,7 @@ def visit_Bytes(self, node):
:param node: The node that is being inspected
:return: -
"""
self.context["bytes"] = node.s
self.context["bytes"] = node.value
if not isinstance(node._bandit_parent, ast.Expr): # docstring
self.context["linerange"] = b_utils.linerange(node._bandit_parent)
self.update_scores(self.tester.run_tests(self.context, "Bytes"))
Expand Down
22 changes: 18 additions & 4 deletions bandit/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,12 @@ def linerange(node):
def concat_string(node, stop=None):
"""Builds a string from a ast.BinOp chain.
This will build a string from a series of ast.Str nodes wrapped in
This will build a string from a series of ast.Constant nodes wrapped in
ast.BinOp nodes. Something like "a" + "b" + "c" or "a %s" % val etc.
The provided node can be any participant in the BinOp chain.
:param node: (ast.Str or ast.BinOp) The node to process
:param stop: (ast.Str or ast.BinOp) Optional base node to stop at
:param node: (ast.Constant or ast.BinOp) The node to process
:param stop: (ast.Constant or ast.BinOp) Optional base node to stop at
:returns: (Tuple) the root node of the expression, the string value
"""

Expand All @@ -300,7 +300,10 @@ def _get(node, bits, stop=None):
node = node._bandit_parent
if isinstance(node, ast.BinOp):
_get(node, bits, stop)
return (node, " ".join([x.s for x in bits if isinstance(x, ast.Str)]))
return (
node,
" ".join([x.value for x in bits if isinstance(x, ast.Constant)]),
)


def get_called_name(node):
Expand Down Expand Up @@ -361,6 +364,17 @@ def parse_ini_file(f_loc):
def check_ast_node(name):
"Check if the given name is that of a valid AST node."
try:
# These ast Node types don't exist in Python 3.14, but plugins may
# still check on them.
if sys.version_info >= (3, 14) and name in (
"Num",
"Str",
"Ellipsis",
"NameConstant",
"Bytes",
):
return name

node = getattr(ast, name)
if issubclass(node, ast.AST):
return name
Expand Down
8 changes: 4 additions & 4 deletions bandit/plugins/django_sql_injection.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def django_extra_used(context):
if key in kwargs:
if isinstance(kwargs[key], ast.List):
for val in kwargs[key].elts:
if not isinstance(val, ast.Str):
if not isinstance(val, ast.Constant):
insecure = True
break
else:
Expand All @@ -77,12 +77,12 @@ def django_extra_used(context):
if not insecure and "select" in kwargs:
if isinstance(kwargs["select"], ast.Dict):
for k in kwargs["select"].keys:
if not isinstance(k, ast.Str):
if not isinstance(k, ast.Constant):
insecure = True
break
if not insecure:
for v in kwargs["select"].values:
if not isinstance(v, ast.Str):
if not isinstance(v, ast.Constant):
insecure = True
break
else:
Expand Down Expand Up @@ -135,7 +135,7 @@ def django_rawsql_used(context):
kwargs = keywords2dict(context.node.keywords)
sql = kwargs["sql"]

if not isinstance(sql, ast.Str):
if not isinstance(sql, ast.Constant):
return bandit.Issue(
severity=bandit.MEDIUM,
confidence=bandit.MEDIUM,
Expand Down
17 changes: 10 additions & 7 deletions bandit/plugins/django_xss.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def evaluate_var(xss_var, parent, until, ignore_nodes=None):
break
to = analyser.is_assigned(node)
if to:
if isinstance(to, ast.Str):
if isinstance(to, ast.Constant):
secure = True
elif isinstance(to, ast.Name):
secure = evaluate_var(to, parent, to.lineno, ignore_nodes)
Expand All @@ -105,7 +105,7 @@ def evaluate_var(xss_var, parent, until, ignore_nodes=None):
elif isinstance(to, (list, tuple)):
num_secure = 0
for some_to in to:
if isinstance(some_to, ast.Str):
if isinstance(some_to, ast.Constant):
num_secure += 1
elif isinstance(some_to, ast.Name):
if evaluate_var(
Expand All @@ -131,7 +131,10 @@ def evaluate_call(call, parent, ignore_nodes=None):
secure = False
evaluate = False
if isinstance(call, ast.Call) and isinstance(call.func, ast.Attribute):
if isinstance(call.func.value, ast.Str) and call.func.attr == "format":
if (
isinstance(call.func.value, ast.Constant)
and call.func.attr == "format"
):
evaluate = True
if call.keywords:
evaluate = False # TODO(??) get support for this
Expand All @@ -140,7 +143,7 @@ def evaluate_call(call, parent, ignore_nodes=None):
args = list(call.args)
num_secure = 0
for arg in args:
if isinstance(arg, ast.Str):
if isinstance(arg, ast.Constant):
num_secure += 1
elif isinstance(arg, ast.Name):
if evaluate_var(arg, parent, call.lineno, ignore_nodes):
Expand All @@ -167,7 +170,7 @@ def evaluate_call(call, parent, ignore_nodes=None):
def transform2call(var):
if isinstance(var, ast.BinOp):
is_mod = isinstance(var.op, ast.Mod)
is_left_str = isinstance(var.left, ast.Str)
is_left_str = isinstance(var.left, ast.Constant)
if is_mod and is_left_str:
new_call = ast.Call()
new_call.args = []
Expand Down Expand Up @@ -212,7 +215,7 @@ def check_risk(node):
secure = evaluate_call(xss_var, parent)
elif isinstance(xss_var, ast.BinOp):
is_mod = isinstance(xss_var.op, ast.Mod)
is_left_str = isinstance(xss_var.left, ast.Str)
is_left_str = isinstance(xss_var.left, ast.Constant)
if is_mod and is_left_str:
parent = node._bandit_parent
while not isinstance(parent, (ast.Module, ast.FunctionDef)):
Expand Down Expand Up @@ -272,5 +275,5 @@ def django_mark_safe(context):
]
if context.call_function_name in affected_functions:
xss = context.node.args[0]
if not isinstance(xss, ast.Str):
if not isinstance(xss, ast.Constant):
return check_risk(context.node)
32 changes: 16 additions & 16 deletions bandit/plugins/general_hardcoded_password.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,45 +83,45 @@ def hardcoded_password_string(context):
# looks for "candidate='some_string'"
for targ in node._bandit_parent.targets:
if isinstance(targ, ast.Name) and RE_CANDIDATES.search(targ.id):
return _report(node.s)
return _report(node.value)
elif isinstance(targ, ast.Attribute) and RE_CANDIDATES.search(
targ.attr
):
return _report(node.s)
return _report(node.value)

elif isinstance(
node._bandit_parent, ast.Subscript
) and RE_CANDIDATES.search(node.s):
) and RE_CANDIDATES.search(node.value):
# Py39+: looks for "dict[candidate]='some_string'"
# subscript -> index -> string
assign = node._bandit_parent._bandit_parent
if isinstance(assign, ast.Assign) and isinstance(
assign.value, ast.Str
assign.value, ast.Constant
):
return _report(assign.value.s)
return _report(assign.value.value)

elif isinstance(node._bandit_parent, ast.Index) and RE_CANDIDATES.search(
node.s
node.value
):
# looks for "dict[candidate]='some_string'"
# assign -> subscript -> index -> string
assign = node._bandit_parent._bandit_parent._bandit_parent
if isinstance(assign, ast.Assign) and isinstance(
assign.value, ast.Str
assign.value, ast.Constant
):
return _report(assign.value.s)
return _report(assign.value.value)

elif isinstance(node._bandit_parent, ast.Compare):
# looks for "candidate == 'some_string'"
comp = node._bandit_parent
if isinstance(comp.left, ast.Name):
if RE_CANDIDATES.search(comp.left.id):
if isinstance(comp.comparators[0], ast.Str):
return _report(comp.comparators[0].s)
if isinstance(comp.comparators[0], ast.Constant):
return _report(comp.comparators[0].value)
elif isinstance(comp.left, ast.Attribute):
if RE_CANDIDATES.search(comp.left.attr):
if isinstance(comp.comparators[0], ast.Str):
return _report(comp.comparators[0].s)
if isinstance(comp.comparators[0], ast.Constant):
return _report(comp.comparators[0].value)


@test.checks("Call")
Expand Down Expand Up @@ -176,8 +176,8 @@ def hardcoded_password_funcarg(context):
"""
# looks for "function(candidate='some_string')"
for kw in context.node.keywords:
if isinstance(kw.value, ast.Str) and RE_CANDIDATES.search(kw.arg):
return _report(kw.value.s)
if isinstance(kw.value, ast.Constant) and RE_CANDIDATES.search(kw.arg):
return _report(kw.value.value)


@test.checks("FunctionDef")
Expand Down Expand Up @@ -242,5 +242,5 @@ def hardcoded_password_default(context):
# go through all (param, value)s and look for candidates
for key, val in zip(context.node.args.args, defs):
if isinstance(key, (ast.Name, ast.arg)):
if isinstance(val, ast.Str) and RE_CANDIDATES.search(key.arg):
return _report(val.s)
if isinstance(val, ast.Constant) and RE_CANDIDATES.search(key.arg):
return _report(val.value)
12 changes: 6 additions & 6 deletions bandit/plugins/injection_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


def _evaluate_shell_call(context):
no_formatting = isinstance(context.node.args[0], ast.Str)
no_formatting = isinstance(context.node.args[0], ast.Constant)

if no_formatting:
return bandit.LOW
Expand Down Expand Up @@ -83,16 +83,14 @@ def has_shell(context):
for key in keywords:
if key.arg == "shell":
val = key.value
if isinstance(val, ast.Num):
result = bool(val.n)
if isinstance(val, ast.Constant):
result = bool(val.value)
elif isinstance(val, ast.List):
result = bool(val.elts)
elif isinstance(val, ast.Dict):
result = bool(val.keys)
elif isinstance(val, ast.Name) and val.id in ["False", "None"]:
result = False
elif isinstance(val, ast.NameConstant):
result = val.value
else:
result = True
return result
Expand Down Expand Up @@ -687,7 +685,9 @@ def start_process_with_partial_path(context, config):
node = node.elts[0]

# make sure the param is a string literal and not a var name
if isinstance(node, ast.Str) and not full_path_match.match(node.s):
if isinstance(node, ast.Constant) and not full_path_match.match(
node.value
):
return bandit.Issue(
severity=bandit.LOW,
confidence=bandit.HIGH,
Expand Down
6 changes: 3 additions & 3 deletions bandit/plugins/injection_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def _evaluate_ast(node):
elif isinstance(
node._bandit_parent, ast.Attribute
) and node._bandit_parent.attr in ("format", "replace"):
statement = node.s
statement = node.value
# Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str
wrapper = node._bandit_parent._bandit_parent._bandit_parent
if node._bandit_parent.attr == "replace":
Expand All @@ -107,14 +107,14 @@ def _evaluate_ast(node):
substrings = [
child
for child in node._bandit_parent.values
if isinstance(child, ast.Str)
if isinstance(child, ast.Constant)
]
# JoinedStr consists of list of Constant and FormattedValue
# instances. Let's perform one test for the whole string
# and abandon all parts except the first one to raise one
# failed test instead of many for the same SQL statement.
if substrings and node == substrings[0]:
statement = "".join([str(child.s) for child in substrings])
statement = "".join([str(child.value) for child in substrings])
wrapper = node._bandit_parent._bandit_parent

if isinstance(wrapper, ast.Call): # wrapped in "execute" call?
Expand Down
2 changes: 1 addition & 1 deletion bandit/plugins/tarfile_unsafe_members.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def is_filter_data(context):
for keyword in context.node.keywords:
if keyword.arg == "filter":
arg = keyword.value
return isinstance(arg, ast.Str) and arg.s == "data"
return isinstance(arg, ast.Constant) and arg.value == "data"


@test.test_id("B202")
Expand Down
Loading

0 comments on commit 4d94bd8

Please sign in to comment.