# Copyright (c) 2015 Rackspace, Inc. # Copyright (c) 2015 Hewlett Packard Enterprise # # SPDX-License-Identifier: Apache-2.0 r""" ============== HTML formatter ============== This formatter outputs the issues as HTML. :Example: .. code-block:: html Bandit Report
Metrics:
Total lines of code: 9
Total lines skipped (#nosec): 0

yaml_load: Use of unsafe yaml load. Allows instantiation of arbitrary objects. Consider yaml.safe_load().
Test ID: B506
Severity: MEDIUM
Confidence: HIGH
CWE: CWE-20 (https://cwe.mitre.org/data/definitions/20.html)
File: examples/yaml_load.py
More info: https://bandit.readthedocs.io/en/latest/plugins/yaml_load.html
    5       ystr = yaml.dump({'a' : 1, 'b' : 2, 'c' : 3})
    6       y = yaml.load(ystr)
    7       yaml.dump(y)
    
.. versionadded:: 0.14.0 .. versionchanged:: 1.5.0 New field `more_info` added to output .. versionchanged:: 1.7.3 New field `CWE` added to output """ import logging import sys from html import escape as html_escape from bandit.core import docs_utils from bandit.core import test_properties from bandit.formatters import utils LOG = logging.getLogger(__name__) @test_properties.accepts_baseline def report(manager, fileobj, sev_level, conf_level, lines=-1): """Writes issues to 'fileobj' in HTML format :param manager: the bandit manager object :param fileobj: The output file object, which may be sys.stdout :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}
Test ID: {test_id}
Severity: {severity}
Confidence: {confidence}
CWE: CWE-{cwe.id}
File: {path}
Line number: {line_number}
More info: {url}
{code} {candidates}
""" code_block = """
{code}
""" candidate_block = """

Candidates: {candidate_list}
""" candidate_issue = """
{code}
""" 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( f"{fname} reason: {reason}
" for fname, reason in manager.get_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 = "" safe_code = html_escape( issue.get_code(lines, True).strip("\n").lstrip(" ") ) code = code_block.format(code=safe_code) else: candidates_str = "" code = "" for candidate in issues[issue]: candidate_code = html_escape( candidate.get_code(lines, True).strip("\n").lstrip(" ") ) candidates_str += candidate_issue.format(code=candidate_code) candidates = candidate_block.format(candidate_list=candidates_str) url = docs_utils.get_url(issue.test_id) results_str += issue_block.format( issue_no=index, issue_class=f"issue-sev-{issue.severity.lower()}", test_name=issue.test, test_id=issue.test_id, test_text=issue.text, severity=issue.severity, confidence=issue.confidence, cwe=issue.cwe, cwe_link=issue.cwe.link(), path=issue.fname, code=code, candidates=candidates, url=url, line_number=issue.lineno, ) # 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 fileobj: wrapped_file = utils.wrap_file_object(fileobj) wrapped_file.write(header_block) wrapped_file.write(report_contents) if fileobj.name != sys.stdout.name: LOG.info("HTML output written to file: %s", fileobj.name)