json.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #
  2. # SPDX-License-Identifier: Apache-2.0
  3. r"""
  4. ==============
  5. JSON formatter
  6. ==============
  7. This formatter outputs the issues in JSON.
  8. :Example:
  9. .. code-block:: javascript
  10. {
  11. "errors": [],
  12. "generated_at": "2015-12-16T22:27:34Z",
  13. "metrics": {
  14. "_totals": {
  15. "CONFIDENCE.HIGH": 1,
  16. "CONFIDENCE.LOW": 0,
  17. "CONFIDENCE.MEDIUM": 0,
  18. "CONFIDENCE.UNDEFINED": 0,
  19. "SEVERITY.HIGH": 0,
  20. "SEVERITY.LOW": 0,
  21. "SEVERITY.MEDIUM": 1,
  22. "SEVERITY.UNDEFINED": 0,
  23. "loc": 5,
  24. "nosec": 0
  25. },
  26. "examples/yaml_load.py": {
  27. "CONFIDENCE.HIGH": 1,
  28. "CONFIDENCE.LOW": 0,
  29. "CONFIDENCE.MEDIUM": 0,
  30. "CONFIDENCE.UNDEFINED": 0,
  31. "SEVERITY.HIGH": 0,
  32. "SEVERITY.LOW": 0,
  33. "SEVERITY.MEDIUM": 1,
  34. "SEVERITY.UNDEFINED": 0,
  35. "loc": 5,
  36. "nosec": 0
  37. }
  38. },
  39. "results": [
  40. {
  41. "code": "4 ystr = yaml.dump({'a' : 1, 'b' : 2, 'c' : 3})\n5
  42. y = yaml.load(ystr)\n6 yaml.dump(y)\n",
  43. "filename": "examples/yaml_load.py",
  44. "issue_confidence": "HIGH",
  45. "issue_severity": "MEDIUM",
  46. "issue_cwe": {
  47. "id": 20,
  48. "link": "https://cwe.mitre.org/data/definitions/20.html"
  49. },
  50. "issue_text": "Use of unsafe yaml load. Allows instantiation of
  51. arbitrary objects. Consider yaml.safe_load().\n",
  52. "line_number": 5,
  53. "line_range": [
  54. 5
  55. ],
  56. "more_info": "https://bandit.readthedocs.io/en/latest/",
  57. "test_name": "blacklist_calls",
  58. "test_id": "B301"
  59. }
  60. ]
  61. }
  62. .. versionadded:: 0.10.0
  63. .. versionchanged:: 1.5.0
  64. New field `more_info` added to output
  65. .. versionchanged:: 1.7.3
  66. New field `CWE` added to output
  67. """
  68. # Necessary so we can import the standard library json module while continuing
  69. # to name this file json.py. (Python 2 only)
  70. import datetime
  71. import json
  72. import logging
  73. import operator
  74. import sys
  75. from bandit.core import docs_utils
  76. from bandit.core import test_properties
  77. LOG = logging.getLogger(__name__)
  78. @test_properties.accepts_baseline
  79. def report(manager, fileobj, sev_level, conf_level, lines=-1):
  80. """''Prints issues in JSON format
  81. :param manager: the bandit manager object
  82. :param fileobj: The output file object, which may be sys.stdout
  83. :param sev_level: Filtering severity level
  84. :param conf_level: Filtering confidence level
  85. :param lines: Number of lines to report, -1 for all
  86. """
  87. machine_output = {"results": [], "errors": []}
  88. for (fname, reason) in manager.get_skipped():
  89. machine_output["errors"].append({"filename": fname, "reason": reason})
  90. results = manager.get_issue_list(
  91. sev_level=sev_level, conf_level=conf_level
  92. )
  93. baseline = not isinstance(results, list)
  94. if baseline:
  95. collector = []
  96. for r in results:
  97. d = r.as_dict(max_lines=lines)
  98. d["more_info"] = docs_utils.get_url(d["test_id"])
  99. if len(results[r]) > 1:
  100. d["candidates"] = [
  101. c.as_dict(max_lines=lines) for c in results[r]
  102. ]
  103. collector.append(d)
  104. else:
  105. collector = [r.as_dict(max_lines=lines) for r in results]
  106. for elem in collector:
  107. elem["more_info"] = docs_utils.get_url(elem["test_id"])
  108. itemgetter = operator.itemgetter
  109. if manager.agg_type == "vuln":
  110. machine_output["results"] = sorted(
  111. collector, key=itemgetter("test_name")
  112. )
  113. else:
  114. machine_output["results"] = sorted(
  115. collector, key=itemgetter("filename")
  116. )
  117. machine_output["metrics"] = manager.metrics.data
  118. # timezone agnostic format
  119. TS_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
  120. time_string = datetime.datetime.utcnow().strftime(TS_FORMAT)
  121. machine_output["generated_at"] = time_string
  122. result = json.dumps(
  123. machine_output, sort_keys=True, indent=2, separators=(",", ": ")
  124. )
  125. with fileobj:
  126. fileobj.write(result)
  127. if fileobj.name != sys.stdout.name:
  128. LOG.info("JSON output written to file: %s", fileobj.name)