From 3ae9636f02198fc4e6cf1fa79e28eaafa3e82d8a Mon Sep 17 00:00:00 2001 From: Elango Senthilnathan Date: Thu, 9 Nov 2023 08:50:43 -0800 Subject: [PATCH 1/2] Added category report --- shiftleft-utils/bestfix.py | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/shiftleft-utils/bestfix.py b/shiftleft-utils/bestfix.py index adaf095..91e75dd 100644 --- a/shiftleft-utils/bestfix.py +++ b/shiftleft-utils/bestfix.py @@ -1025,6 +1025,101 @@ def print_scan_stats(scan, counts): table.add_row(col, num_to_emoji(ratings_counts_dict[col])) console.print(table) +# Code introduced to print a tabluar severity + Category count report : Elango +def print_category_report(org_id, app, scan, findings, counts, source_dir): + if not findings: + return table_report + data_found = False + table = Table( + title=f"""Severity + Category Report for {app["name"]}""", + show_lines=True, + box=box.DOUBLE_EDGE, + header_style="bold green", + expand=True, + ) + table.add_column("Severity", justify="right", style="cyan") + table.add_column("Category") + table.add_column("Total Count") + table.add_column("Open Count", justify="right", style="cyan") + table.add_column("Fixed Count", justify="right", style="cyan") + table.add_column("Ignored Count", justify="right", style="cyan") + table.add_column("3rd Party Count", justify="right", style="cyan") + + nestedDictionary = {} + + counts = 0 + for afinding in findings: + category = afinding.get("category") + status = afinding.get("status") + ids = afinding.get("id") + type = afinding.get("type") + if not category: + category = "OSS Vuln" + + if type == "oss_vuln": + continue + counts += 1 + if status: + if status.lower() == "none": + status = "open" + else: + status = "open" + tags = afinding.get("tags") + if tags: + for tag in tags: + if tag.get("key") == "cvss_31_severity_rating": + cvss_31_severity_rating = tag.get("value") + if cvss_31_severity_rating == "critical": + cvss_31_severity_rating = "01" + ":" + cvss_31_severity_rating + elif cvss_31_severity_rating == "high": + cvss_31_severity_rating = "02" + ":" + cvss_31_severity_rating + elif cvss_31_severity_rating == "medium": + cvss_31_severity_rating = "03" + ":" + cvss_31_severity_rating + else: + cvss_31_severity_rating = "04" + ":" + "low" + + #console.print(f'{counts}) {ids} category is {category} |||| Status is {status}') + + catSev = cvss_31_severity_rating + ":" + category + if not ( catSev in nestedDictionary.keys()): + nestedDictionary[catSev] = {} + nestedDictionary[catSev][status] = 1 + else: + if not (status in nestedDictionary[catSev].keys()): + nestedDictionary[catSev][status] = 1 + else: + nestedDictionary[catSev][status] = nestedDictionary[catSev][status] + 1 + + for eachRow in sorted(nestedDictionary): + splitCategoryDict = nestedDictionary[eachRow] + splitCategory = eachRow.split(":") + openCount = 0 + fixedCount = 0 + ignoredCount = 0 + partyCount = 0 + if "open" in splitCategoryDict.keys(): + openCount = splitCategoryDict["open"] + if "fixed" in splitCategoryDict.keys(): + fixedCount = splitCategoryDict["fixed"] + if "ignore" in splitCategoryDict.keys(): + ignoredCount = splitCategoryDict["ignore"] + if "3rdparty" in splitCategoryDict.keys(): + partyCount = splitCategoryDict["3rdparty"] + totalCount = int(openCount) + int(fixedCount) + int(ignoredCount) + int(partyCount) + if int(openCount) == 0: + openCount = " " + if int(fixedCount) == 0: + fixedCount = " " + if int(ignoredCount) == 0: + ignoredCount = " " + if int(partyCount) == 0: + partyCount = " " + + table.add_row( f'{splitCategory[1]}', f'{splitCategory[2]}', f'{totalCount}', f'{openCount}', f'{fixedCount}', f'{ignoredCount}', f'{partyCount}') + console.print(table) + + + def find_best_fix(org_id, app, scan, findings, counts, source_dir): annotated_findings = [] @@ -1604,6 +1699,7 @@ def find_best_fix(org_id, app, scan, findings, counts, source_dir): # Executive summary section if scan: print_scan_stats(scan, counts) + print_category_report(org_id, app, scan, findings, counts, source_dir) # Find the best oss fixes find_best_oss_fix( org_id, @@ -1738,6 +1834,7 @@ def export_report( scan, findings, counts = get_all_findings_with_scan( client, org_id, app_id, version, ratings ) + annotated_findings = find_best_fix( org_id, app, scan, findings, counts, source_dir ) @@ -1860,6 +1957,7 @@ def build_args(): else ["critical", "high"], args.troubleshoot, ) + end_time = time.monotonic_ns() total_time_sec = round((end_time - start_time) / 1000000000, 2) if args.rformat == "html": @@ -1867,13 +1965,17 @@ def build_args(): report_file, theme=MONOKAI if os.getenv("USE_DARK_THEME") else DEFAULT_TERMINAL_THEME, ) + console.print(f"HTML report saved to {report_file}") try: import pdfkit pdf_file = report_file.replace(".html", ".pdf") + pdfkit.from_file(report_file, pdf_file, options=pdf_options) + console.print(f"PDF report saved to {pdf_file}") + except Exception: console.print( "Please install wkhtmltopdf to enable PDF exports https://wkhtmltopdf.org/downloads.html" From caad576ebcc045213a74beb7a92998f81c84323c Mon Sep 17 00:00:00 2001 From: Elango Senthilnathan Date: Thu, 9 Nov 2023 16:14:57 -0800 Subject: [PATCH 2/2] Included Security Issues --- shiftleft-utils/bestfix.py | 42 ++++++++++++++------------------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/shiftleft-utils/bestfix.py b/shiftleft-utils/bestfix.py index 91e75dd..b5acd26 100644 --- a/shiftleft-utils/bestfix.py +++ b/shiftleft-utils/bestfix.py @@ -1027,27 +1027,23 @@ def print_scan_stats(scan, counts): # Code introduced to print a tabluar severity + Category count report : Elango def print_category_report(org_id, app, scan, findings, counts, source_dir): - if not findings: - return table_report - data_found = False table = Table( - title=f"""Severity + Category Report for {app["name"]}""", + title=f"""SAST/SCA/SecurityIssues with Severity & Category Count Report for {app["name"]}""", show_lines=True, box=box.DOUBLE_EDGE, header_style="bold green", - expand=True, + expand=False, ) - table.add_column("Severity", justify="right", style="cyan") + table.add_column("Severity", style="cyan") table.add_column("Category") - table.add_column("Total Count") - table.add_column("Open Count", justify="right", style="cyan") - table.add_column("Fixed Count", justify="right", style="cyan") - table.add_column("Ignored Count", justify="right", style="cyan") - table.add_column("3rd Party Count", justify="right", style="cyan") + table.add_column("Total Count" , justify="center") + table.add_column("Open Count", justify="center", style="red") + table.add_column("Fixed Count",justify="center", style="green") + table.add_column("Ignored Count",justify="center", style="purple") + table.add_column("3rd Party Count", justify="center", style="blue") nestedDictionary = {} - counts = 0 for afinding in findings: category = afinding.get("category") status = afinding.get("status") @@ -1056,9 +1052,9 @@ def print_category_report(org_id, app, scan, findings, counts, source_dir): if not category: category = "OSS Vuln" - if type == "oss_vuln": - continue - counts += 1 + # if type == "oss_vuln": + # continue + if status: if status.lower() == "none": status = "open" @@ -1078,8 +1074,6 @@ def print_category_report(org_id, app, scan, findings, counts, source_dir): else: cvss_31_severity_rating = "04" + ":" + "low" - #console.print(f'{counts}) {ids} category is {category} |||| Status is {status}') - catSev = cvss_31_severity_rating + ":" + category if not ( catSev in nestedDictionary.keys()): nestedDictionary[catSev] = {} @@ -1093,10 +1087,8 @@ def print_category_report(org_id, app, scan, findings, counts, source_dir): for eachRow in sorted(nestedDictionary): splitCategoryDict = nestedDictionary[eachRow] splitCategory = eachRow.split(":") - openCount = 0 - fixedCount = 0 - ignoredCount = 0 - partyCount = 0 + openCount = fixedCount = ignoredCount = partyCount = 0 + if "open" in splitCategoryDict.keys(): openCount = splitCategoryDict["open"] if "fixed" in splitCategoryDict.keys(): @@ -1123,6 +1115,7 @@ def print_category_report(org_id, app, scan, findings, counts, source_dir): def find_best_fix(org_id, app, scan, findings, counts, source_dir): annotated_findings = [] + if not findings: return annotated_findings data_found = False @@ -1750,7 +1743,7 @@ def get_all_findings_with_scan(client, org_id, app_name, version, ratings): """Method to retrieve all findings""" findings_list = [] version_suffix = f"&version={version}" if version else "" - findings_url = f"https://{config.SHIFTLEFT_API_HOST}/api/v4/orgs/{org_id}/apps/{app_name}/findings?per_page=249&type=oss_vuln&type=vuln&include_dataflows=true{version_suffix}" + findings_url = f"https://{config.SHIFTLEFT_API_HOST}/api/v4/orgs/{org_id}/apps/{app_name}/findings?per_page=249&type=oss_vuln&type=security_issue&type=vuln&include_dataflows=true{version_suffix}" for rating in ratings: findings_url = f"{findings_url}&finding_tags=cvss_31_severity_rating={rating}" page_available = True @@ -1957,7 +1950,6 @@ def build_args(): else ["critical", "high"], args.troubleshoot, ) - end_time = time.monotonic_ns() total_time_sec = round((end_time - start_time) / 1000000000, 2) if args.rformat == "html": @@ -1969,13 +1961,9 @@ def build_args(): console.print(f"HTML report saved to {report_file}") try: import pdfkit - pdf_file = report_file.replace(".html", ".pdf") - pdfkit.from_file(report_file, pdf_file, options=pdf_options) - console.print(f"PDF report saved to {pdf_file}") - except Exception: console.print( "Please install wkhtmltopdf to enable PDF exports https://wkhtmltopdf.org/downloads.html"