Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix line range using Python 3.8 end_lineno #821

Merged
merged 1 commit into from Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 3 additions & 7 deletions bandit/core/node_visitor.py
Expand Up @@ -172,9 +172,7 @@ def visit_Str(self, node):
"""
self.context["str"] = node.s
if not isinstance(node._bandit_parent, ast.Expr): # docstring
self.context["linerange"] = b_utils.linerange_fix(
node._bandit_parent
)
self.context["linerange"] = b_utils.linerange(node._bandit_parent)
self.update_scores(self.tester.run_tests(self.context, "Str"))

def visit_Bytes(self, node):
Expand All @@ -187,9 +185,7 @@ def visit_Bytes(self, node):
"""
self.context["bytes"] = node.s
if not isinstance(node._bandit_parent, ast.Expr): # docstring
self.context["linerange"] = b_utils.linerange_fix(
node._bandit_parent
)
self.context["linerange"] = b_utils.linerange(node._bandit_parent)
self.update_scores(self.tester.run_tests(self.context, "Bytes"))

def pre_visit(self, node):
Expand All @@ -215,7 +211,7 @@ def pre_visit(self, node):
self.context["col_offset"] = node.col_offset

self.context["node"] = node
self.context["linerange"] = b_utils.linerange_fix(node)
self.context["linerange"] = b_utils.linerange(node)
self.context["filename"] = self.fname
self.context["file_data"] = self.fdata

Expand Down
100 changes: 50 additions & 50 deletions bandit/core/utils.py
Expand Up @@ -220,56 +220,56 @@ def calc_linerange(node):

def linerange(node):
"""Get line number range from a node."""
if hasattr(node, "_bandit_linerange_stripped"):
lines_minmax = node._bandit_linerange_stripped
return list(range(lines_minmax[0], lines_minmax[1] + 1))

strip = {
"body": None,
"orelse": None,
"handlers": None,
"finalbody": None,
}
for key in strip.keys():
if hasattr(node, key):
strip[key] = getattr(node, key)
setattr(node, key, [])

lines_min = 9999999999
lines_max = -1
if hasattr(node, "lineno"):
lines_min = node.lineno
lines_max = node.lineno
for n in ast.iter_child_nodes(node):
lines_minmax = calc_linerange(n)
lines_min = min(lines_min, lines_minmax[0])
lines_max = max(lines_max, lines_minmax[1])

for key in strip.keys():
if strip[key] is not None:
setattr(node, key, strip[key])

if lines_max == -1:
lines_min = 0
lines_max = 1

node._bandit_linerange_stripped = (lines_min, lines_max)

return list(range(lines_min, lines_max + 1))


def linerange_fix(node):
"""Try and work around a known Python bug with multi-line strings."""
# deal with multiline strings lineno behavior (Python issue #16806)
lines = linerange(node)
if hasattr(node, "_bandit_sibling") and hasattr(
node._bandit_sibling, "lineno"
):
start = min(lines)
delta = node._bandit_sibling.lineno - start
if delta > 1:
return list(range(start, node._bandit_sibling.lineno))
return lines
if sys.version_info >= (3, 8) and hasattr(node, "lineno"):
return list(range(node.lineno, node.end_lineno + 1))
else:
if hasattr(node, "_bandit_linerange_stripped"):
lines_minmax = node._bandit_linerange_stripped
return list(range(lines_minmax[0], lines_minmax[1] + 1))

strip = {
"body": None,
"orelse": None,
"handlers": None,
"finalbody": None,
}
for key in strip.keys():
if hasattr(node, key):
strip[key] = getattr(node, key)
setattr(node, key, [])

lines_min = 9999999999
lines_max = -1
if hasattr(node, "lineno"):
lines_min = node.lineno
lines_max = node.lineno
for n in ast.iter_child_nodes(node):
lines_minmax = calc_linerange(n)
lines_min = min(lines_min, lines_minmax[0])
lines_max = max(lines_max, lines_minmax[1])

for key in strip.keys():
if strip[key] is not None:
setattr(node, key, strip[key])

if lines_max == -1:
lines_min = 0
lines_max = 1

node._bandit_linerange_stripped = (lines_min, lines_max)

lines = list(range(lines_min, lines_max + 1))

"""Try and work around a known Python bug with multi-line strings."""
# deal with multiline strings lineno behavior (Python issue #16806)
if hasattr(node, "_bandit_sibling") and hasattr(
node._bandit_sibling, "lineno"
):
start = min(lines)
delta = node._bandit_sibling.lineno - start
if delta > 1:
return list(range(start, node._bandit_sibling.lineno))
return lines


def concat_string(node, stop=None):
Expand Down
7 changes: 7 additions & 0 deletions examples/multiline_statement.py
Expand Up @@ -4,3 +4,10 @@
"args",
shell=True,
universal_newlines=True)

subprocess.check_output(
"/some_command",
"args",
shell=True,
universal_newlines=True
)
14 changes: 11 additions & 3 deletions tests/functional/test_functional.py
Expand Up @@ -738,17 +738,25 @@ def test_multiline_code(self):
)

issues = self.b_mgr.get_issue_list()
self.assertEqual(2, len(issues))
self.assertEqual(3, len(issues))
self.assertTrue(
issues[0].fname.endswith("examples/multiline_statement.py")
)

self.assertEqual(1, issues[0].lineno)
self.assertEqual(list(range(1, 3)), issues[0].linerange)
if sys.version_info >= (3, 8):
self.assertEqual(list(range(1, 2)), issues[0].linerange)
else:
self.assertEqual(list(range(1, 3)), issues[0].linerange)
self.assertIn("subprocess", issues[0].get_code())
self.assertEqual(5, issues[1].lineno)
self.assertEqual(list(range(3, 6 + 1)), issues[1].linerange)
self.assertIn("shell=True", issues[1].get_code())
self.assertEqual(11, issues[2].lineno)
if sys.version_info >= (3, 8):
self.assertEqual(list(range(8, 13 + 1)), issues[2].linerange)
else:
self.assertEqual(list(range(8, 12 + 1)), issues[2].linerange)
self.assertIn("shell=True", issues[2].get_code())

def test_code_line_numbers(self):
self.run_example("binding.py")
Expand Down