From 7bffe6b2d53ff4948c85bb8aa5991e8022e999d9 Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Wed, 7 Dec 2022 13:04:38 +0100 Subject: [PATCH] fix(html): fix error html generator (#1530) Co-authored-by: sergargar Co-authored-by: Toni de la Fuente --- lib/check/check.py | 33 ++++++------ lib/outputs/outputs.py | 117 +++++++++++++++++++++-------------------- prowler | 8 +-- 3 files changed, 82 insertions(+), 76 deletions(-) diff --git a/lib/check/check.py b/lib/check/check.py index 538a42f1..7ac29b26 100644 --- a/lib/check/check.py +++ b/lib/check/check.py @@ -140,25 +140,26 @@ def print_compliance_frameworks( def print_compliance_requirements( - bulk_compliance_frameworks: dict, compliance_framework: str + bulk_compliance_frameworks: dict, compliance_frameworks: list ): - for compliance in bulk_compliance_frameworks.values(): - # Workaround until we have more Compliance Frameworks - split_compliance = compliance_framework.split("_") - framework = split_compliance[0].upper() - version = split_compliance[1].upper() - provider = split_compliance[2].upper() - if compliance.Framework == framework and compliance.Version == version: - print( - f"Listing {framework} {version} {provider} Compliance Requirements:\n" - ) - for requirement in compliance.Requirements: - checks = "" - for check in requirement.Checks: - checks += f" {Fore.YELLOW}\t\t{check}\n{Style.RESET_ALL}" + for compliance_framework in compliance_frameworks: + for compliance in bulk_compliance_frameworks.values(): + # Workaround until we have more Compliance Frameworks + split_compliance = compliance_framework.split("_") + framework = split_compliance[0].upper() + version = split_compliance[1].upper() + provider = split_compliance[2].upper() + if framework in compliance.Framework and compliance.Version == version: print( - f"Requirement Id: {Fore.MAGENTA}{requirement.Id}{Style.RESET_ALL}\n\t- Description: {requirement.Description}\n\t- Checks:\n{checks}" + f"Listing {framework} {version} {provider} Compliance Requirements:\n" ) + for requirement in compliance.Requirements: + checks = "" + for check in requirement.Checks: + checks += f" {Fore.YELLOW}\t\t{check}\n{Style.RESET_ALL}" + print( + f"Requirement Id: {Fore.MAGENTA}{requirement.Id}{Style.RESET_ALL}\n\t- Description: {requirement.Description}\n\t- Checks:\n{checks}" + ) def print_checks( diff --git a/lib/outputs/outputs.py b/lib/outputs/outputs.py index ecae3d67..0171ded6 100644 --- a/lib/outputs/outputs.py +++ b/lib/outputs/outputs.py @@ -16,7 +16,6 @@ from config.config import ( json_asff_file_suffix, json_file_suffix, orange_color, - output_file_timestamp, prowler_version, timestamp, timestamp_iso, @@ -304,7 +303,6 @@ def initialize_file_descriptor( if output_mode in ("json", "json-asff"): file_descriptor.write("[") - if "html" in output_mode: add_html_header(file_descriptor, audit_info) except Exception as error: @@ -463,34 +461,6 @@ def fill_json_asff(finding_output, audit_info, finding): return finding_output -def fill_html(file_descriptor, audit_info, finding): - row_class = "p-3 mb-2 bg-success-custom" - if finding.status == "INFO": - row_class = "table-info" - elif finding.status == "FAIL": - row_class = "table-danger" - elif finding.status == "WARNING": - row_class = "table-warning" - file_descriptor.write( - f""" - - {finding.status} - {finding.check_metadata.Severity} - {audit_info.audited_account} - {finding.region} - {finding.check_metadata.ServiceName} - {finding.check_metadata.CheckID} - {finding.check_metadata.CheckTitle} - {finding.status_extended} -

{finding.check_metadata.Risk}

-

{finding.check_metadata.Remediation.Recommendation.Text}

- - {finding.resource_id} - - """ - ) - - def close_json(output_filename, output_directory, mode): try: suffix = json_file_suffix @@ -638,8 +608,10 @@ def display_summary_table( print(f" - HTML: {output_directory}/{output_filename}.html") if "json-asff" in output_options.output_modes: print(f" - JSON-ASFF: {output_directory}/{output_filename}.asff.json") - print(f" - CSV: {output_directory}/{output_filename}.csv") - print(f" - JSON: {output_directory}/{output_filename}.json") + if "csv" in output_options.output_modes: + print(f" - CSV: {output_directory}/{output_filename}.csv") + if "json" in output_options.output_modes: + print(f" - JSON: {output_directory}/{output_filename}.json") else: print( @@ -887,8 +859,12 @@ def display_compliance_table( def add_html_header(file_descriptor, audit_info): try: + if not audit_info.profile: + audit_info.profile = "ENV" if isinstance(audit_info.audited_regions, list): audited_regions = " ".join(audit_info.audited_regions) + elif not audit_info.audited_regions: + audited_regions = "All Regions" else: audited_regions = audit_info.audited_regions file_descriptor.write( @@ -901,7 +877,8 @@ def add_html_header(file_descriptor, audit_info): @@ -913,12 +890,9 @@ def add_html_header(file_descriptor, audit_info): display: none; } - Prowler - AWS Security Assessments + Prowler - The Handy Cloud Security Tool -
@@ -927,6 +901,14 @@ def add_html_header(file_descriptor, audit_info): Report Information:
    +
  • + prowler-logo +
  • @@ -943,17 +925,9 @@ def add_html_header(file_descriptor, audit_info):
  • Date: """ - + output_file_timestamp + + timestamp.isoformat() + """
  • -
  • - prowler-logo -
@@ -998,16 +972,16 @@ def add_html_header(file_descriptor, audit_info): Status Severity - Account ID + Service Name Region - Service - Check ID Check Title - Check Output - Risk - Remediation - Related URL Resource ID + Check Description + Check ID + Status Extended + Risk + Recomendation + Recomendation URL @@ -1019,6 +993,34 @@ def add_html_header(file_descriptor, audit_info): ) +def fill_html(file_descriptor, audit_info, finding): + row_class = "p-3 mb-2 bg-success-custom" + if finding.status == "INFO": + row_class = "table-info" + elif finding.status == "FAIL": + row_class = "table-danger" + elif finding.status == "WARNING": + row_class = "table-warning" + file_descriptor.write( + f""" + + {finding.status} + {finding.check_metadata.Severity} + {finding.check_metadata.ServiceName} + {finding.region} + {finding.check_metadata.CheckTitle} + {finding.resource_id} + {finding.check_metadata.Description} + {finding.check_metadata.CheckID} + {finding.status_extended} +

{finding.check_metadata.Risk}

+

{finding.check_metadata.Remediation.Recommendation.Text}

+ + + """ + ) + + def add_html_footer(output_filename, output_directory): try: filename = f"{output_directory}/{output_filename}{html_file_suffix}" @@ -1045,6 +1047,8 @@ def add_html_footer(output_filename, output_directory): $(document).ready(function(){ // Initialise the table with 50 rows, and some search/filtering panes $('#findingsTable').DataTable( { + lengthChange: true, + buttons: [ 'copy', 'excel', 'pdf' ], lengthMenu: [ [50, 100, -1], [50, 100, "All"] ], searchPanes: { cascadePanes: true, @@ -1054,10 +1058,11 @@ def add_html_footer(output_filename, output_directory): columnDefs: [ { searchPanes: { - show: false + show: true, + pagingType: 'numbers', + searching: true }, - // Hide Compliance, Check ID (in favour of Check Title), CAF Epic, Risk, Remediation, Link - targets: [4, 6, 9, 10, 11, 12] + targets: [0, 1, 2, 3, 4] } ] }); diff --git a/prowler b/prowler index 941bbedb..e73d6dea 100755 --- a/prowler +++ b/prowler @@ -102,9 +102,9 @@ if __name__ == "__main__": ) list_group.add_argument( "--list-compliance-requirements", - nargs="?", + nargs="+", help="List compliance requirements for a given requirement", - choices=["ens_rd2022_aws"], + choices=["ens_rd2022_aws", "cis_1.4_aws", "cis_1.5_aws"], ) list_group.add_argument( "--list-categories", @@ -174,8 +174,8 @@ if __name__ == "__main__": "-M", "--output-modes", nargs="+", - help="Output mode, by default csv and json", - default=["csv", "json"], + help="Output modes, by default csv, html and json", + default=["csv", "json", "html"], choices=["csv", "json", "json-asff", "html"], ) parser.add_argument(