# Copyright (c) 2015 Rackspace, Inc.
# Copyright (c) 2015 Hewlett Packard Enterprise
#
# 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.
r"""
Description
-----------
This formatter outputs the issues as HTML.
Sample Output
-------------
.. code-block:: html
Bandit Report
Metrics:
Total lines of code:
5
Total lines skipped (#nosec):
0
blacklist_calls: Use of unsafe yaml load. Allows instantiation
of arbitrary objects. Consider yaml.safe_load().
Severity: MEDIUM
Confidence: HIGH
File:
examples/yaml_load.py
4 ystr = yaml.dump({'a' : 1, 'b' : 2, 'c' : 3})
5 y = yaml.load(ystr)
6 yaml.dump(y)
.. versionadded:: 0.14.0
"""
import logging
from bandit.core.test_properties import accepts_baseline
from bandit.core import utils
logger = logging.getLogger(__name__)
@accepts_baseline
def report(manager, filename, sev_level, conf_level, lines=-1):
"""Writes issues to 'filename' in HTML format
:param manager: the bandit manager object
:param filename: output file name
:param sev_level: Filtering severity level
:param conf_level: Filtering confidence level
:param lines: Number of lines to report, -1 for all
"""
header_block = """
Bandit Report
"""
report_block = """
{metrics}
{skipped}
{results}
"""
issue_block = """
{test_name}: {test_text}
Severity: {severity}
Confidence: {confidence}
File: {path}
{code}
{candidates}
"""
code_block = """
{code}
"""
candidate_block = """
Candidates:
{candidate_list}
"""
candidate_issue = """
"""
skipped_block = """
Skipped files:
{files_list}
"""
metrics_block = """
Metrics:
Total lines of code:
{loc}
Total lines skipped (#nosec):
{nosec}
"""
issues = manager.get_issue_list(sev_level=sev_level, conf_level=conf_level)
baseline = not isinstance(issues, list)
# build the skipped string to insert in the report
skipped_str = ''.join('%s - %s\n' % (fname, reason)
for fname, reason in manager.skipped)
if skipped_str:
skipped_text = skipped_block.format(files_list=skipped_str)
else:
skipped_text = ''
# build the results string to insert in the report
results_str = ''
for index, issue in enumerate(issues):
if not baseline or len(issues[issue]) == 1:
candidates = ''
code = code_block.format(code=issue.get_code(lines, True).
strip('\n').lstrip(' '))
else:
candidates_str = ''
code = ''
for candidate in issues[issue]:
candidate_code = (candidate.get_code(lines, True).strip('\n').
lstrip(' '))
candidates_str += candidate_issue.format(code=candidate_code)
candidates = candidate_block.format(candidate_list=candidates_str)
results_str += issue_block.format(issue_no=index,
issue_class='issue-sev-{}'.
format(issue.severity.lower()),
test_name=issue.test,
test_text=issue.text,
severity=issue.severity,
confidence=issue.confidence,
path=issue.fname, code=code,
candidates=candidates)
# build the metrics string to insert in the report
metrics_summary = metrics_block.format(
loc=manager.metrics.data['_totals']['loc'],
nosec=manager.metrics.data['_totals']['nosec'])
# build the report and output it
report_contents = report_block.format(metrics=metrics_summary,
skipped=skipped_text,
results=results_str)
with utils.output_file(filename, 'w') as fout:
fout.write(header_block)
fout.write(report_contents)
if filename is not None:
logger.info("HTML output written to file: %s" % filename)