From ffcacec6304c692e73d174042fce9a50cf9302c7 Mon Sep 17 00:00:00 2001 From: Michael Hohn Date: Thu, 2 Dec 2021 11:41:11 -0800 Subject: [PATCH] sarif-results-summary: add csv output option --- bin/sarif-results-summary | 48 +++++++++++++++++++++++++++++++-------- sarif_cli/__init__.py | 10 ++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/bin/sarif-results-summary b/bin/sarif-results-summary index 3dad16c..cfb1269 100755 --- a/bin/sarif-results-summary +++ b/bin/sarif-results-summary @@ -12,11 +12,17 @@ parser.add_argument('-s', '--list-source', metavar='srcroot', type=str, help='list source snippets using srcroot as sarif SRCROOT') parser.add_argument('-r', '--related-locations', action="store_true", help='list related locations like "hides [parameter](1)"') +# TODO mutually exclusive options +parser.add_argument('-c', '--csv', action="store_true", + help='output csv instead of human-readable summary') args = parser.parse_args() with open(args.file, 'r') if args.file != '-' else sys.stdin as fp: sarif_struct = json.load(fp) +if args.csv: + cw = S.get_csv_writer() + for runi in S.indices(sarif_struct, 'runs'): num_results = len(S.get(sarif_struct, 'runs', runi, 'results')) if num_results == 0: continue @@ -25,14 +31,21 @@ for runi in S.indices(sarif_struct, 'runs'): result = S.get(sarif_struct, 'runs', runi, 'results', resi) if 'locations' in result: # Non-path problems + # TODO: just pull out the uri, not the artifact message, artifact, region = S.get_location_message_info(result) l1, c1, l2, c2 = S.lineinfo(region) filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2) - S.msg("RESULT: %s: %s\n\n" % (filepath, message)) + if args.csv: + S.write_csv(cw, "result", artifact['uri'], l1, c1, l2, c2, message) + else: + S.msg("RESULT: %s: %s\n\n" % (filepath, message)) if args.list_source: lines = S.load_lines(args.list_source, artifact['uri'], l1, l2) - for line, line_num in zip(lines, range(l1, l2+1)): - S.display_underlined(l1, c1, l2, c2, line, line_num) + if args.csv: + pass + else: + for line, line_num in zip(lines, range(l1, l2+1)): + S.display_underlined(l1, c1, l2, c2, line, line_num) if args.related_locations: # Full path: S.get(sarif_struct, 'runs', runi, 'results', resi, 'relatedLocations') relatedLocations = result.get('relatedLocations', None) @@ -42,11 +55,17 @@ for runi in S.indices(sarif_struct, 'runs'): message, artifact, region = S.get_relatedlocation_message_info(relo) l1, c1, l2, c2 = S.lineinfo(region) filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2) - S.msg("REFERENCE: %s: %s\n\n" % (filepath, message)) + if args.csv: + S.write_csv(cw, "result", artifact['uri'], l1, c1, l2, c2, message) + else: + S.msg("REFERENCE: %s: %s\n\n" % (filepath, message)) if args.list_source: lines = S.load_lines(args.list_source, artifact['uri'], l1, l2) - for line, line_num in zip(lines, range(l1, l2+1)): - S.display_underlined(l1, c1, l2, c2, line, line_num) + if args.csv: + pass + else: + for line, line_num in zip(lines, range(l1, l2+1)): + S.display_underlined(l1, c1, l2, c2, line, line_num) if 'codeFlows' in result: # Path problems for codeFlow in S.get(result, 'codeFlows'): @@ -56,9 +75,18 @@ for runi in S.indices(sarif_struct, 'runs'): message, artifact, region = S.get_relatedlocation_message_info(location) l1, c1, l2, c2 = S.lineinfo(region) filepath = "%s:%d:%d:%d:%d" % (artifact['uri'], l1, c1, l2, c2) - S.msg("FLOW STEP %d: %s: %s\n\n" % (loci, filepath, message)) + if args.csv: + S.write_csv(cw, "flow_step", loci, artifact['uri'], l1, c1, l2, c2, message) + else: + S.msg("FLOW STEP %d: %s: %s\n\n" % (loci, filepath, message)) if args.list_source: lines = S.load_lines(args.list_source, artifact['uri'], l1, l2) - for line, line_num in zip(lines, range(l1, l2+1)): - S.display_underlined(l1, c1, l2, c2, line, line_num) - S.msg("\n") + if args.csv: + pass + else: + for line, line_num in zip(lines, range(l1, l2+1)): + S.display_underlined(l1, c1, l2, c2, line, line_num) + if args.csv: + pass + else: + S.msg("\n") diff --git a/sarif_cli/__init__.py b/sarif_cli/__init__.py index 90927f9..ec694ef 100644 --- a/sarif_cli/__init__.py +++ b/sarif_cli/__init__.py @@ -2,11 +2,21 @@ import sys import os import re import codecs +import csv MIN_PYTHON = (3, 7) if sys.version_info < MIN_PYTHON: sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) +def get_csv_writer(): + """ Set up and return the default csv writer on stdout. + """ + return csv.writer(sys.stdout, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL) + +def write_csv(writer, *columns): + """ Print via `writer`, with some additional processing """ + writer.writerow(columns) + def get_relatedlocation_message_info(related_location): """ Given a relatedLocation, extract message information.