Skip to content

Commit

Permalink
Add end_col_offset if available (#851)
Browse files Browse the repository at this point in the history
Python 3.8 and above include an end_col_offset attribute on nodes
to indicate the end column offset of the node. If available,
Bandit should include end_col_offset for more clarity on the column
range where the issue was found.

Signed-off-by: Eric Brown <browne@vmware.com>
  • Loading branch information
ericwb committed Jul 8, 2022
1 parent 39cdfab commit da58ceb
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 4 deletions.
7 changes: 6 additions & 1 deletion bandit/core/issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def __init__(
lineno=None,
test_id="",
col_offset=0,
end_col_offset=0,
):
self.severity = severity
self.cwe = Cwe(cwe)
Expand All @@ -99,12 +100,13 @@ def __init__(
self.test_id = test_id
self.lineno = lineno
self.col_offset = col_offset
self.end_col_offset = end_col_offset
self.linerange = []

def __str__(self):
return (
"Issue: '%s' from %s:%s: CWE: %s, Severity: %s Confidence: "
"%s at %s:%i"
"%s at %s:%i:%i"
) % (
self.text,
self.test_id,
Expand All @@ -114,6 +116,7 @@ def __str__(self):
self.confidence,
self.fname,
self.lineno,
self.col_offset,
)

def __eq__(self, other):
Expand Down Expand Up @@ -206,6 +209,7 @@ def as_dict(self, with_code=True):
"line_number": self.lineno,
"line_range": self.linerange,
"col_offset": self.col_offset,
"end_col_offset": self.end_col_offset,
}

if with_code:
Expand All @@ -224,6 +228,7 @@ def from_dict(self, data, with_code=True):
self.lineno = data["line_number"]
self.linerange = data["line_range"]
self.col_offset = data.get("col_offset", 0)
self.end_col_offset = data.get("end_col_offset", 0)


def cwe_from_dict(data):
Expand Down
2 changes: 2 additions & 0 deletions bandit/core/node_visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ def pre_visit(self, node):

if hasattr(node, "col_offset"):
self.context["col_offset"] = node.col_offset
if hasattr(node, "end_col_offset"):
self.context["end_col_offset"] = node.end_col_offset

self.context["node"] = node
self.context["linerange"] = b_utils.linerange(node)
Expand Down
3 changes: 3 additions & 0 deletions bandit/core/tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def run_tests(self, raw_context, checktype):
result.lineno = temp_context["lineno"]
result.linerange = temp_context["linerange"]
result.col_offset = temp_context["col_offset"]
result.end_col_offset = temp_context.get(
"end_col_offset", 0
)
result.test = name
if result.test_id == "":
result.test_id = test._test_id
Expand Down
1 change: 1 addition & 0 deletions bandit/formatters/csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def report(manager, fileobj, sev_level, conf_level, lines=-1):
"issue_text",
"line_number",
"col_offset",
"end_col_offset",
"line_range",
"more_info",
]
Expand Down
1 change: 1 addition & 0 deletions bandit/formatters/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def report(manager, fileobj, sev_level, conf_level, template=None):
"relpath": lambda issue: os.path.relpath(issue.fname),
"line": lambda issue: issue.lineno,
"col": lambda issue: issue.col_offset,
"end_col": lambda issue: issue.end_col_offset,
"test_id": lambda issue: issue.test_id,
"severity": lambda issue: issue.severity,
"msg": lambda issue: issue.text,
Expand Down
14 changes: 13 additions & 1 deletion tests/unit/core/test_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_issue_str(self):
"Issue: 'Test issue' from B999:bandit_plugin:"
" CWE: %s,"
" Severity: MEDIUM "
"Confidence: MEDIUM at code.py:1"
"Confidence: MEDIUM at code.py:1:8"
)

self.assertEqual(
Expand All @@ -37,10 +37,19 @@ def test_issue_as_dict(self):
self.assertEqual("bandit_plugin", test_issue_dict["test_name"])
self.assertEqual("B999", test_issue_dict["test_id"])
self.assertEqual("MEDIUM", test_issue_dict["issue_severity"])
self.assertEqual(
{
"id": 605,
"link": "https://cwe.mitre.org/data/definitions/605.html",
},
test_issue_dict["issue_cwe"],
)
self.assertEqual("MEDIUM", test_issue_dict["issue_confidence"])
self.assertEqual("Test issue", test_issue_dict["issue_text"])
self.assertEqual(1, test_issue_dict["line_number"])
self.assertEqual([], test_issue_dict["line_range"])
self.assertEqual(8, test_issue_dict["col_offset"])
self.assertEqual(16, test_issue_dict["end_col_offset"])

def test_issue_filter_severity(self):
levels = [bandit.LOW, bandit.MEDIUM, bandit.HIGH]
Expand Down Expand Up @@ -131,4 +140,7 @@ def _get_issue_instance(
new_issue.test = "bandit_plugin"
new_issue.test_id = "B999"
new_issue.lineno = 1
new_issue.col_offset = 8
new_issue.end_col_offset = 16

return new_issue
8 changes: 8 additions & 0 deletions tests/unit/formatters/test_csv.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def setUp(self):
"filename": self.tmp_fname,
"lineno": 4,
"linerange": [4],
"col_offset": 8,
"end_col_offset": 16,
}
self.check_name = "hardcoded_bind_all_interfaces"
self.issue = issue.Issue(
Expand All @@ -36,6 +38,8 @@ def setUp(self):
self.issue.fname = self.context["filename"]
self.issue.lineno = self.context["lineno"]
self.issue.linerange = self.context["linerange"]
self.issue.col_offset = self.context["col_offset"]
self.issue.end_col_offset = self.context["end_col_offset"]
self.issue.test = self.check_name

self.manager.results.append(self.issue)
Expand All @@ -62,3 +66,7 @@ def test_report(self):
)
self.assertEqual(self.check_name, data["test_name"])
self.assertIsNotNone(data["more_info"])
self.assertEqual(str(self.issue.col_offset), data["col_offset"])
self.assertEqual(
str(self.issue.end_col_offset), data["end_col_offset"]
)
11 changes: 9 additions & 2 deletions tests/unit/formatters/test_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def setUp(self):
"lineno": 4,
"linerange": [4],
"col_offset": 30,
"end_col_offset": 38,
}
self.check_name = "hardcoded_bind_all_interfaces"
self.issue = issue.Issue(
Expand All @@ -35,6 +36,7 @@ def setUp(self):
self.issue.lineno = self.context["lineno"]
self.issue.linerange = self.context["linerange"]
self.issue.col_offset = self.context["col_offset"]
self.issue.end_col_offset = self.context["end_col_offset"]
self.issue.test = self.check_name

self.manager.results.append(self.issue)
Expand All @@ -46,13 +48,18 @@ def test_report(self):
tmp_file,
self.issue.severity,
self.issue.confidence,
template="{line},{col},{severity},{msg}",
template="{line},{col},{end_col},{severity},{msg}",
)

with open(self.tmp_fname) as f:
reader = csv.DictReader(f, ["line", "col", "severity", "message"])
reader = csv.DictReader(
f, ["line", "col", "end_col", "severity", "message"]
)
data = next(reader)
self.assertEqual(str(self.context["lineno"]), data["line"])
self.assertEqual(str(self.context["col_offset"]), data["col"])
self.assertEqual(
str(self.context["end_col_offset"]), data["end_col"]
)
self.assertEqual(self.issue.severity, data["severity"])
self.assertEqual(self.issue.text, data["message"])

0 comments on commit da58ceb

Please sign in to comment.