Split each formatter into separate modules

As we increase the number of formatters, it doesn't make sense to
cram each into a single module.  This patch splits them up by
output format type.

Any new formatter should also be implemented as a separate module.

Change-Id: Ibbd0edb9af06a52bef28804a6619a07f323931e6
This commit is contained in:
Eric Brown 2015-09-07 19:42:49 -07:00
parent ca68d805f8
commit f8c22f8b64
14 changed files with 623 additions and 429 deletions

View File

@ -1,274 +0,0 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# 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 collections
import csv
import datetime
import json
import logging
from operator import itemgetter
import six
from bandit.core import constants
logger = logging.getLogger(__name__)
def _sum_scores(manager, sev):
summation = 0
for scores in manager.scores:
summation += sum(scores['CONFIDENCE'][sev:])
summation += sum(scores['SEVERITY'][sev:])
return summation
def report_csv(manager, filename, sev_level, conf_level, lines=-1,
out_format='csv'):
'''Prints issues in CSV format
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
results = manager.get_issue_list()
if filename is None:
filename = 'bandit_results.csv'
with open(filename, 'w') as fout:
fieldnames = ['filename',
'test_name',
'issue_severity',
'issue_confidence',
'issue_text',
'line_number',
'line_range']
writer = csv.DictWriter(fout, fieldnames=fieldnames,
extrasaction='ignore')
writer.writeheader()
for result in results:
if result.filter(sev_level, conf_level):
writer.writerow(result.as_dict(with_code=False))
print("CSV output written to file: %s" % filename)
def report_json(manager, filename, sev_level, conf_level, lines=-1,
out_format='json'):
'''''Prints issues in JSON format
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
stats = dict(zip(manager.files_list, manager.scores))
machine_output = dict({'results': [], 'errors': [], 'stats': []})
for (fname, reason) in manager.skipped:
machine_output['errors'].append({'filename': fname,
'reason': reason})
for filer, score in six.iteritems(stats):
totals = {}
rank = constants.RANKING
sev_idx = rank.index(sev_level)
for i in range(sev_idx, len(rank)):
severity = rank[i]
severity_value = constants.RANKING_VALUES[severity]
try:
sc = score['SEVERITY'][i] / severity_value
except ZeroDivisionError:
sc = 0
totals[severity] = sc
machine_output['stats'].append({
'filename': filer,
'score': _sum_scores(manager, sev_idx),
'issue totals': totals})
results = manager.get_issue_list()
collector = []
for result in results:
if result.filter(sev_level, conf_level):
collector.append(result.as_dict())
if manager.agg_type == 'vuln':
machine_output['results'] = sorted(collector,
key=itemgetter('test_name'))
else:
machine_output['results'] = sorted(collector,
key=itemgetter('filename'))
# timezone agnostic format
TS_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
time_string = datetime.datetime.utcnow().strftime(TS_FORMAT)
machine_output['generated_at'] = time_string
result = json.dumps(machine_output, sort_keys=True,
indent=2, separators=(',', ': '))
if filename:
with open(filename, 'w') as fout:
fout.write(result)
logger.info("JSON output written to file: %s" % filename)
else:
print(result)
def report_text(manager, filename, sev_level, conf_level, lines=-1,
out_format='txt'):
'''Prints issues in Text formt
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
tmpstr_list = []
# use a defaultdict to default to an empty string
color = collections.defaultdict(str)
if out_format == 'txt':
# get text colors from settings for TTY output
get_setting = manager.b_conf.get_setting
color = {'HEADER': get_setting('color_HEADER'),
'DEFAULT': get_setting('color_DEFAULT'),
'LOW': get_setting('color_LOW'),
'MEDIUM': get_setting('color_MEDIUM'),
'HIGH': get_setting('color_HIGH')
}
# print header
tmpstr_list.append("%sRun started:%s\n\t%s\n" % (
color['HEADER'],
color['DEFAULT'],
datetime.datetime.utcnow()
))
if manager.verbose:
# print which files were inspected
tmpstr_list.append("\n%sFiles in scope (%s):%s\n" % (
color['HEADER'], len(manager.files_list),
color['DEFAULT']
))
for item in zip(manager.files_list, map(_sum_scores, manager.scores)):
tmpstr_list.append("\t%s (score: %i)\n" % item)
# print which files were excluded and why
tmpstr_list.append("\n%sFiles excluded (%s):%s\n" %
(color['HEADER'], len(manager.skipped),
color['DEFAULT']))
for fname in manager.skipped:
tmpstr_list.append("\t%s\n" % fname)
# print which files were skipped and why
tmpstr_list.append("\n%sFiles skipped (%s):%s\n" % (
color['HEADER'], len(manager.skipped),
color['DEFAULT']
))
for (fname, reason) in manager.skipped:
tmpstr_list.append("\t%s (%s)\n" % (fname, reason))
# print the results
tmpstr_list.append("\n%sTest results:%s\n" % (
color['HEADER'], color['DEFAULT']
))
issues = manager.get_issue_list()
if not len(issues):
tmpstr_list.append("\tNo issues identified.\n")
for issue in issues:
# if the result isn't filtered out by severity
if issue.filter(sev_level, conf_level):
tmpstr_list.append("\n%s>> Issue: %s\n" % (
color.get(issue.severity, color['DEFAULT']),
issue.text
))
tmpstr_list.append(" Severity: %s Confidence: %s\n" % (
issue.severity.capitalize(),
issue.confidence.capitalize()
))
tmpstr_list.append(" Location: %s:%s\n" % (
issue.fname,
issue.lineno
))
tmpstr_list.append(color['DEFAULT'])
tmpstr_list.append(
issue.get_code(lines, True))
result = ''.join(tmpstr_list)
if filename:
with open(filename, 'w') as fout:
fout.write(result)
logger.info("Text output written to file: %s", filename)
else:
print(result)
def report_xml(manager, filename, sev_level, conf_level, lines=-1,
out_format='xml'):
'''Prints issues in XML formt
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
import xml.etree.cElementTree as ET
if filename is None:
filename = 'bandit_results.xml'
issues = manager.get_issue_list()
root = ET.Element('testsuite', name='bandit', tests=str(len(issues)))
for issue in issues:
test = issue.test
testcase = ET.SubElement(root, 'testcase',
classname=issue.fname, name=test)
if issue.filter(sev_level, conf_level):
text = 'Severity: %s Confidence: %s\n%s\nLocation %s:%s'
text = text % (
issue.severity, issue.confidence,
issue.text, issue.fname, issue.lineno)
ET.SubElement(testcase, 'error',
type=issue.severity,
message=issue.text).text = text
tree = ET.ElementTree(root)
tree.write(filename, encoding='utf-8', xml_declaration=True)
print("XML output written to file: %s" % filename)

View File

@ -386,3 +386,11 @@ def get_path_for_function(f):
else:
logger.warn("Cannot resolve file path for module %s", module_name)
return None
def sum_scores(manager, sev):
summation = 0
for scores in manager.scores:
summation += sum(scores['CONFIDENCE'][sev:])
summation += sum(scores['SEVERITY'][sev:])
return summation

View File

52
bandit/formatters/csv.py Normal file
View File

@ -0,0 +1,52 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import csv
def report(manager, filename, sev_level, conf_level, lines=-1,
out_format='csv'):
'''Prints issues in CSV format
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
results = manager.get_issue_list()
if filename is None:
filename = 'bandit_results.csv'
with open(filename, 'w') as fout:
fieldnames = ['filename',
'test_name',
'issue_severity',
'issue_confidence',
'issue_text',
'line_number',
'line_range']
writer = csv.DictWriter(fout, fieldnames=fieldnames,
extrasaction='ignore')
writer.writeheader()
for result in results:
if result.filter(sev_level, conf_level):
writer.writerow(result.as_dict(with_code=False))
print("CSV output written to file: %s" % filename)

92
bandit/formatters/json.py Normal file
View File

@ -0,0 +1,92 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import datetime
import json
import logging
from operator import itemgetter
import six
from bandit.core import constants
from bandit.core import utils
logger = logging.getLogger(__name__)
def report(manager, filename, sev_level, conf_level, lines=-1,
out_format='json'):
'''''Prints issues in JSON format
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
stats = dict(zip(manager.files_list, manager.scores))
machine_output = dict({'results': [], 'errors': [], 'stats': []})
for (fname, reason) in manager.skipped:
machine_output['errors'].append({'filename': fname,
'reason': reason})
for filer, score in six.iteritems(stats):
totals = {}
rank = constants.RANKING
sev_idx = rank.index(sev_level)
for i in range(sev_idx, len(rank)):
severity = rank[i]
severity_value = constants.RANKING_VALUES[severity]
try:
sc = score['SEVERITY'][i] / severity_value
except ZeroDivisionError:
sc = 0
totals[severity] = sc
machine_output['stats'].append({
'filename': filer,
'score': utils.sum_scores(manager, sev_idx),
'issue totals': totals})
results = manager.get_issue_list()
collector = []
for result in results:
if result.filter(sev_level, conf_level):
collector.append(result.as_dict())
if manager.agg_type == 'vuln':
machine_output['results'] = sorted(collector,
key=itemgetter('test_name'))
else:
machine_output['results'] = sorted(collector,
key=itemgetter('filename'))
# timezone agnostic format
TS_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
time_string = datetime.datetime.utcnow().strftime(TS_FORMAT)
machine_output['generated_at'] = time_string
result = json.dumps(machine_output, sort_keys=True,
indent=2, separators=(',', ': '))
if filename:
with open(filename, 'w') as fout:
fout.write(result)
logger.info("JSON output written to file: %s" % filename)
else:
print(result)

121
bandit/formatters/text.py Normal file
View File

@ -0,0 +1,121 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# 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 collections
import datetime
import logging
from bandit.core import utils
logger = logging.getLogger(__name__)
def report(manager, filename, sev_level, conf_level, lines=-1,
out_format='txt'):
'''Prints issues in Text formt
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
tmpstr_list = []
# use a defaultdict to default to an empty string
color = collections.defaultdict(str)
if out_format == 'txt':
# get text colors from settings for TTY output
get_setting = manager.b_conf.get_setting
color = {'HEADER': get_setting('color_HEADER'),
'DEFAULT': get_setting('color_DEFAULT'),
'LOW': get_setting('color_LOW'),
'MEDIUM': get_setting('color_MEDIUM'),
'HIGH': get_setting('color_HIGH')
}
# print header
tmpstr_list.append("%sRun started:%s\n\t%s\n" % (
color['HEADER'],
color['DEFAULT'],
datetime.datetime.utcnow()
))
if manager.verbose:
# print which files were inspected
tmpstr_list.append("\n%sFiles in scope (%s):%s\n" % (
color['HEADER'], len(manager.files_list),
color['DEFAULT']
))
for item in zip(manager.files_list, map(utils.sum_scores,
manager.scores)):
tmpstr_list.append("\t%s (score: %i)\n" % item)
# print which files were excluded and why
tmpstr_list.append("\n%sFiles excluded (%s):%s\n" %
(color['HEADER'], len(manager.skipped),
color['DEFAULT']))
for fname in manager.skipped:
tmpstr_list.append("\t%s\n" % fname)
# print which files were skipped and why
tmpstr_list.append("\n%sFiles skipped (%s):%s\n" % (
color['HEADER'], len(manager.skipped),
color['DEFAULT']
))
for (fname, reason) in manager.skipped:
tmpstr_list.append("\t%s (%s)\n" % (fname, reason))
# print the results
tmpstr_list.append("\n%sTest results:%s\n" % (
color['HEADER'], color['DEFAULT']
))
issues = manager.get_issue_list()
if not len(issues):
tmpstr_list.append("\tNo issues identified.\n")
for issue in issues:
# if the result isn't filtered out by severity
if issue.filter(sev_level, conf_level):
tmpstr_list.append("\n%s>> Issue: %s\n" % (
color.get(issue.severity, color['DEFAULT']),
issue.text
))
tmpstr_list.append(" Severity: %s Confidence: %s\n" % (
issue.severity.capitalize(),
issue.confidence.capitalize()
))
tmpstr_list.append(" Location: %s:%s\n" % (
issue.fname,
issue.lineno
))
tmpstr_list.append(color['DEFAULT'])
tmpstr_list.append(
issue.get_code(lines, True))
result = ''.join(tmpstr_list)
if filename:
with open(filename, 'w') as fout:
fout.write(result)
logger.info("Text output written to file: %s", filename)
else:
print(result)

53
bandit/formatters/xml.py Normal file
View File

@ -0,0 +1,53 @@
# -*- coding:utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
from xml.etree import cElementTree as ET
def report(manager, filename, sev_level, conf_level, lines=-1,
out_format='xml'):
'''Prints issues in XML formt
:param manager: the bandit manager object
:param filename: The output file name, or None for stdout
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
:param out_format: The ouput format name
'''
if filename is None:
filename = 'bandit_results.xml'
issues = manager.get_issue_list()
root = ET.Element('testsuite', name='bandit', tests=str(len(issues)))
for issue in issues:
test = issue.test
testcase = ET.SubElement(root, 'testcase',
classname=issue.fname, name=test)
if issue.filter(sev_level, conf_level):
text = 'Severity: %s Confidence: %s\n%s\nLocation %s:%s'
text = text % (
issue.severity, issue.confidence,
issue.text, issue.fname, issue.lineno)
ET.SubElement(testcase, 'error',
type=issue.severity,
message=issue.text).text = text
tree = ET.ElementTree(root)
tree.write(filename, encoding='utf-8', xml_declaration=True)
print("XML output written to file: %s" % filename)

View File

@ -25,10 +25,10 @@ classifier =
console_scripts =
bandit = bandit.bandit:main
bandit.formatters =
csv = bandit.core.formatters:report_csv
json = bandit.core.formatters:report_json
txt = bandit.core.formatters:report_text
xml = bandit.core.formatters:report_xml
csv = bandit.formatters.csv:report
json = bandit.formatters.json:report
txt = bandit.formatters.text:report
xml = bandit.formatters.xml:report
bandit.plugins =
# bandit/plugins/asserts.py
assert_used = bandit.plugins.asserts:assert_used

View File

@ -1,151 +0,0 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from collections import defaultdict
import csv
import json
import os
import tempfile
from xml.etree import cElementTree as ET
import six
import testtools
import bandit
from bandit.core import constants
from bandit.core import config
from bandit.core import manager
from bandit.core import formatters
from bandit.core import issue
class FormattersTests(testtools.TestCase):
def setUp(self):
super(FormattersTests, self).setUp()
cfg_file = os.path.join(os.getcwd(), 'bandit/config/bandit.yaml')
conf = config.BanditConfig(cfg_file)
self.manager = manager.BanditManager(conf, 'file')
(tmp_fd, self.tmp_fname) = tempfile.mkstemp()
self.context = {'filename': self.tmp_fname,
'lineno': 4,
'linerange': [4]}
self.check_name = 'hardcoded_bind_all_interfaces'
self.issue = issue.Issue(bandit.MEDIUM, bandit.MEDIUM,
'Possible binding to all interfaces.')
self.manager.out_file = self.tmp_fname
self.issue.fname = self.context['filename']
self.issue.lineno = self.context['lineno']
self.issue.linerange = self.context['linerange']
self.issue.test = self.check_name
self.manager.results.append(self.issue)
def test_report_csv(self):
formatters.report_csv(self.manager, self.tmp_fname,
self.issue.severity, self.issue.confidence)
with open(self.tmp_fname) as f:
reader = csv.DictReader(f)
data = six.next(reader)
self.assertEqual(self.tmp_fname, data['filename'])
self.assertEqual(self.issue.severity, data['issue_severity'])
self.assertEqual(self.issue.confidence, data['issue_confidence'])
self.assertEqual(self.issue.text, data['issue_text'])
self.assertEqual(six.text_type(self.context['lineno']),
data['line_number'])
self.assertEqual(six.text_type(self.context['linerange']),
data['line_range'])
self.assertEqual(self.check_name, data['test_name'])
def test_report_json(self):
self.manager.files_list = ['binding.py']
self.manager.scores = [{'SEVERITY': [0] * len(constants.RANKING),
'CONFIDENCE': [0] * len(constants.RANKING)}]
formatters.report_json(self.manager, self.tmp_fname,
self.issue.severity, self.issue.confidence)
with open(self.tmp_fname) as f:
data = json.loads(f.read())
self.assertIsNotNone(data['generated_at'])
self.assertEqual(self.tmp_fname, data['results'][0]['filename'])
self.assertEqual(self.issue.severity,
data['results'][0]['issue_severity'])
self.assertEqual(self.issue.confidence,
data['results'][0]['issue_confidence'])
self.assertEqual(self.issue.text, data['results'][0]['issue_text'])
self.assertEqual(self.context['lineno'],
data['results'][0]['line_number'])
self.assertEqual(self.context['linerange'],
data['results'][0]['line_range'])
self.assertEqual(self.check_name, data['results'][0]['test_name'])
self.assertEqual('binding.py', data['stats'][0]['filename'])
self.assertEqual(0, data['stats'][0]['score'])
def test_report_text(self):
self.manager.verbose = True
file_list = ['binding.py']
scores = [{'SEVERITY': [0] * len(constants.RANKING),
'CONFIDENCE': [0] * len(constants.RANKING)}]
exc_files = ['test_binding.py']
formatters.report_text(self.manager, self.tmp_fname,
self.issue.severity, self.issue.confidence)
with open(self.tmp_fname) as f:
data = f.read()
expected = '>> Issue: %s' % self.issue.text
self.assertIn(expected, data)
expected = ' Severity: %s Confidence: %s' % (
self.issue.severity.capitalize(),
self.issue.confidence.capitalize())
self.assertIn(expected, data)
expected = ' Location: %s:%d' % (self.tmp_fname,
self.context['lineno'])
self.assertIn(expected, data)
def _xml_to_dict(self, t):
d = {t.tag: {} if t.attrib else None}
children = list(t)
if children:
dd = defaultdict(list)
for dc in map(self._xml_to_dict, children):
for k, v in six.iteritems(dc):
dd[k].append(v)
d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in six.iteritems(dd)}}
if t.attrib:
d[t.tag].update(('@' + k, v) for k, v in six.iteritems(t.attrib))
if t.text:
text = t.text.strip()
if children or t.attrib:
if text:
d[t.tag]['#text'] = text
else:
d[t.tag] = text
return d
def test_report_xml(self):
formatters.report_xml(self.manager, self.tmp_fname,
self.issue.severity, self.issue.confidence)
with open(self.tmp_fname) as f:
data = self._xml_to_dict(ET.XML(f.read()))
self.assertEqual(self.tmp_fname,
data['testsuite']['testcase']['@classname'])
self.assertEqual(self.issue.text,
data['testsuite']['testcase']['error']['@message'])
self.assertEqual(self.check_name,
data['testsuite']['testcase']['@name'])

View File

View File

@ -0,0 +1,66 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# 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 csv
import os
import tempfile
import six
import testtools
import bandit
from bandit.core import config
from bandit.core import manager
from bandit.core import issue
from bandit.formatters import csv as b_csv
class CsvFormatterTests(testtools.TestCase):
def setUp(self):
super(CsvFormatterTests, self).setUp()
cfg_file = os.path.join(os.getcwd(), 'bandit/config/bandit.yaml')
conf = config.BanditConfig(cfg_file)
self.manager = manager.BanditManager(conf, 'file')
(tmp_fd, self.tmp_fname) = tempfile.mkstemp()
self.context = {'filename': self.tmp_fname,
'lineno': 4,
'linerange': [4]}
self.check_name = 'hardcoded_bind_all_interfaces'
self.issue = issue.Issue(bandit.MEDIUM, bandit.MEDIUM,
'Possible binding to all interfaces.')
self.manager.out_file = self.tmp_fname
self.issue.fname = self.context['filename']
self.issue.lineno = self.context['lineno']
self.issue.linerange = self.context['linerange']
self.issue.test = self.check_name
self.manager.results.append(self.issue)
def test_report(self):
b_csv.report(self.manager, self.tmp_fname, self.issue.severity,
self.issue.confidence)
with open(self.tmp_fname) as f:
reader = csv.DictReader(f)
data = six.next(reader)
self.assertEqual(self.tmp_fname, data['filename'])
self.assertEqual(self.issue.severity, data['issue_severity'])
self.assertEqual(self.issue.confidence, data['issue_confidence'])
self.assertEqual(self.issue.text, data['issue_text'])
self.assertEqual(six.text_type(self.context['lineno']),
data['line_number'])
self.assertEqual(six.text_type(self.context['linerange']),
data['line_range'])
self.assertEqual(self.check_name, data['test_name'])

View File

@ -0,0 +1,74 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# 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 json
import os
import tempfile
import testtools
import bandit
from bandit.core import constants
from bandit.core import config
from bandit.core import manager
from bandit.core import issue
from bandit.formatters import json as b_json
class JsonFormatterTests(testtools.TestCase):
def setUp(self):
super(JsonFormatterTests, self).setUp()
cfg_file = os.path.join(os.getcwd(), 'bandit/config/bandit.yaml')
conf = config.BanditConfig(cfg_file)
self.manager = manager.BanditManager(conf, 'file')
(tmp_fd, self.tmp_fname) = tempfile.mkstemp()
self.context = {'filename': self.tmp_fname,
'lineno': 4,
'linerange': [4]}
self.check_name = 'hardcoded_bind_all_interfaces'
self.issue = issue.Issue(bandit.MEDIUM, bandit.MEDIUM,
'Possible binding to all interfaces.')
self.manager.out_file = self.tmp_fname
self.issue.fname = self.context['filename']
self.issue.lineno = self.context['lineno']
self.issue.linerange = self.context['linerange']
self.issue.test = self.check_name
self.manager.results.append(self.issue)
def test_report(self):
self.manager.files_list = ['binding.py']
self.manager.scores = [{'SEVERITY': [0] * len(constants.RANKING),
'CONFIDENCE': [0] * len(constants.RANKING)}]
b_json.report(self.manager, self.tmp_fname, self.issue.severity,
self.issue.confidence)
with open(self.tmp_fname) as f:
data = json.loads(f.read())
self.assertIsNotNone(data['generated_at'])
self.assertEqual(self.tmp_fname, data['results'][0]['filename'])
self.assertEqual(self.issue.severity,
data['results'][0]['issue_severity'])
self.assertEqual(self.issue.confidence,
data['results'][0]['issue_confidence'])
self.assertEqual(self.issue.text, data['results'][0]['issue_text'])
self.assertEqual(self.context['lineno'],
data['results'][0]['line_number'])
self.assertEqual(self.context['linerange'],
data['results'][0]['line_range'])
self.assertEqual(self.check_name, data['results'][0]['test_name'])
self.assertEqual('binding.py', data['stats'][0]['filename'])
self.assertEqual(0, data['stats'][0]['score'])

View File

@ -0,0 +1,70 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# 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 os
import tempfile
import testtools
import bandit
from bandit.core import constants
from bandit.core import config
from bandit.core import manager
from bandit.core import issue
from bandit.formatters import text as b_text
class TextFormatterTests(testtools.TestCase):
def setUp(self):
super(TextFormatterTests, self).setUp()
cfg_file = os.path.join(os.getcwd(), 'bandit/config/bandit.yaml')
conf = config.BanditConfig(cfg_file)
self.manager = manager.BanditManager(conf, 'file')
(tmp_fd, self.tmp_fname) = tempfile.mkstemp()
self.context = {'filename': self.tmp_fname,
'lineno': 4,
'linerange': [4]}
self.check_name = 'hardcoded_bind_all_interfaces'
self.issue = issue.Issue(bandit.MEDIUM, bandit.MEDIUM,
'Possible binding to all interfaces.')
self.manager.out_file = self.tmp_fname
self.issue.fname = self.context['filename']
self.issue.lineno = self.context['lineno']
self.issue.linerange = self.context['linerange']
self.issue.test = self.check_name
self.manager.results.append(self.issue)
def test_report(self):
self.manager.verbose = True
file_list = ['binding.py']
scores = [{'SEVERITY': [0] * len(constants.RANKING),
'CONFIDENCE': [0] * len(constants.RANKING)}]
exc_files = ['test_binding.py']
b_text.report(self.manager, self.tmp_fname, self.issue.severity,
self.issue.confidence)
with open(self.tmp_fname) as f:
data = f.read()
expected = '>> Issue: %s' % self.issue.text
self.assertIn(expected, data)
expected = ' Severity: %s Confidence: %s' % (
self.issue.severity.capitalize(),
self.issue.confidence.capitalize())
self.assertIn(expected, data)
expected = ' Location: %s:%d' % (self.tmp_fname,
self.context['lineno'])
self.assertIn(expected, data)

View File

@ -0,0 +1,83 @@
# Copyright (c) 2015 VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from collections import defaultdict
import os
import tempfile
from xml.etree import cElementTree as ET
import six
import testtools
import bandit
from bandit.core import config
from bandit.core import manager
from bandit.core import issue
from bandit.formatters import xml as b_xml
class XmlFormatterTests(testtools.TestCase):
def setUp(self):
super(XmlFormatterTests, self).setUp()
cfg_file = os.path.join(os.getcwd(), 'bandit/config/bandit.yaml')
conf = config.BanditConfig(cfg_file)
self.manager = manager.BanditManager(conf, 'file')
(tmp_fd, self.tmp_fname) = tempfile.mkstemp()
self.context = {'filename': self.tmp_fname,
'lineno': 4,
'linerange': [4]}
self.check_name = 'hardcoded_bind_all_interfaces'
self.issue = issue.Issue(bandit.MEDIUM, bandit.MEDIUM,
'Possible binding to all interfaces.')
self.manager.out_file = self.tmp_fname
self.issue.fname = self.context['filename']
self.issue.lineno = self.context['lineno']
self.issue.linerange = self.context['linerange']
self.issue.test = self.check_name
self.manager.results.append(self.issue)
def _xml_to_dict(self, t):
d = {t.tag: {} if t.attrib else None}
children = list(t)
if children:
dd = defaultdict(list)
for dc in map(self._xml_to_dict, children):
for k, v in six.iteritems(dc):
dd[k].append(v)
d = {t.tag: {k:v[0] if len(v) == 1 else v for k, v in six.iteritems(dd)}}
if t.attrib:
d[t.tag].update(('@' + k, v) for k, v in six.iteritems(t.attrib))
if t.text:
text = t.text.strip()
if children or t.attrib:
if text:
d[t.tag]['#text'] = text
else:
d[t.tag] = text
return d
def test_report(self):
b_xml.report(self.manager, self.tmp_fname, self.issue.severity,
self.issue.confidence)
with open(self.tmp_fname) as f:
data = self._xml_to_dict(ET.XML(f.read()))
self.assertEqual(self.tmp_fname,
data['testsuite']['testcase']['@classname'])
self.assertEqual(self.issue.text,
data['testsuite']['testcase']['error']['@message'])
self.assertEqual(self.check_name,
data['testsuite']['testcase']['@name'])