diff --git a/prowler/__main__.py b/prowler/__main__.py index 1606d62c0e..8ebcc5c528 100644 --- a/prowler/__main__.py +++ b/prowler/__main__.py @@ -33,7 +33,6 @@ from prowler.lib.cli.parser import ProwlerArgumentParser from prowler.lib.logger import logger, set_logging_config from prowler.lib.outputs.compliance.compliance import display_compliance_table -from prowler.lib.outputs.json import close_json from prowler.lib.outputs.outputs import extract_findings_statistics from prowler.lib.outputs.summary_table import display_summary_table from prowler.providers.aws.lib.s3.s3 import send_to_s3_bucket @@ -222,13 +221,6 @@ def prowler(): if args.output_modes: for mode in args.output_modes: - # Close json file if exists - if "json" in mode: - close_json( - global_provider.output_options.output_filename, - args.output_directory, - mode, - ) # Send output to S3 if needed (-B / -D) if provider == "aws" and ( args.output_bucket or args.output_bucket_no_assume diff --git a/prowler/lib/cli/parser.py b/prowler/lib/cli/parser.py index 03245e7359..691e710bf4 100644 --- a/prowler/lib/cli/parser.py +++ b/prowler/lib/cli/parser.py @@ -128,8 +128,8 @@ def __init_outputs_parser__(self): "--output-modes", nargs="+", help="Output modes, by default csv and json", - default=["csv", "json", "json-ocsf"], - choices=["csv", "json", "json-asff", "json-ocsf"], + default=["csv", "json-ocsf"], + choices=["csv", "json-asff", "json-ocsf"], ) common_outputs_parser.add_argument( "-F", diff --git a/prowler/lib/outputs/file_descriptors.py b/prowler/lib/outputs/file_descriptors.py index 62a7016d73..0719a4c66c 100644 --- a/prowler/lib/outputs/file_descriptors.py +++ b/prowler/lib/outputs/file_descriptors.py @@ -5,7 +5,6 @@ from prowler.config.config import ( csv_file_suffix, json_asff_file_suffix, - json_file_suffix, json_ocsf_file_suffix, ) from prowler.lib.logger import logger @@ -39,7 +38,7 @@ def initialize_file_descriptor( "a", ) - if output_mode in ("json", "json-asff", "json-ocsf"): + if output_mode in ("json-asff", "json-ocsf"): file_descriptor.write("[") else: # Format is the class model of the CSV format to print the headers @@ -70,11 +69,6 @@ def fill_file_descriptors(output_modes, output_directory, output_filename, provi ) file_descriptors.update({output_mode: file_descriptor}) - elif output_mode == "json": - filename = f"{output_directory}/{output_filename}{json_file_suffix}" - file_descriptor = initialize_file_descriptor(filename, output_mode) - file_descriptors.update({output_mode: file_descriptor}) - elif output_mode == "json-ocsf": filename = ( f"{output_directory}/{output_filename}{json_ocsf_file_suffix}" diff --git a/prowler/lib/outputs/models.py b/prowler/lib/outputs/models.py index af81bdc176..d6ef8363a8 100644 --- a/prowler/lib/outputs/models.py +++ b/prowler/lib/outputs/models.py @@ -1,12 +1,10 @@ -import importlib import sys from datetime import datetime from typing import List, Literal, Optional from pydantic import BaseModel -from prowler.config.config import prowler_version, timestamp -from prowler.lib.check.models import Remediation +from prowler.config.config import prowler_version from prowler.lib.logger import logger from prowler.lib.utils.utils import outputs_unix_timestamp from prowler.providers.aws.models import AWSOrganizationsInfo @@ -133,172 +131,6 @@ def parse_json_tags(tags: list): return dict_tags -def generate_provider_output_json(provider, finding, mode: str, output_options): - """ - generate_provider_output_json configures automatically the outputs based on the selected provider and returns the Check_Output_JSON object. - """ - try: - # Dynamically load the Provider_Output_Options class for the JSON format - finding_output_model = ( - f"{provider.type.capitalize()}_Check_Output_{mode.upper()}" - ) - output_model = getattr(importlib.import_module(__name__), finding_output_model) - # Instantiate the class for the cloud provider - finding_output = output_model(**finding.check_metadata.dict()) - # Fill common fields - finding_output.AssessmentStartTime = outputs_unix_timestamp( - output_options.unix_timestamp, timestamp - ) - finding_output.Status = finding.status - finding_output.StatusExtended = finding.status_extended - finding_output.ResourceDetails = finding.resource_details - - if provider.type == "azure": - finding_output.Tenant_Domain = provider.identity.tenant_domain - finding_output.Subscription = finding.subscription - finding_output.ResourceId = finding.resource_id - finding_output.ResourceName = finding.resource_name - finding_output.FindingUniqueId = f"prowler-{provider.type}-{finding.check_metadata.CheckID}-{finding.subscription}-{finding.resource_id}" - finding_output.Compliance = get_check_compliance( - finding, provider.type, output_options - ) - - if provider.type == "gcp": - finding_output.ProjectId = finding.project_id - finding_output.Location = finding.location.lower() - finding_output.ResourceId = finding.resource_id - finding_output.ResourceName = finding.resource_name - finding_output.FindingUniqueId = f"prowler-{provider.type}-{finding.check_metadata.CheckID}-{finding.project_id}-{finding.resource_id}" - finding_output.Compliance = get_check_compliance( - finding, provider.type, output_options - ) - - if provider.type == "kubernetes": - finding_output.Context = provider.identity.context - finding_output.Namespace = finding.namespace - finding_output.ResourceId = finding.resource_id - finding_output.ResourceName = finding.resource_name - finding_output.FindingUniqueId = f"prowler-{provider.type}-{finding.check_metadata.CheckID}-{finding.namespace}-{finding.resource_id}" - finding_output.Compliance = get_check_compliance( - finding, provider.type, output_options - ) - - if provider.type == "aws": - finding_output.Profile = provider.identity.profile - finding_output.AccountId = provider.identity.account - finding_output.Region = finding.region - finding_output.ResourceId = finding.resource_id - finding_output.ResourceArn = finding.resource_arn - finding_output.ResourceTags = parse_json_tags(finding.resource_tags) - finding_output.FindingUniqueId = f"prowler-{provider.type}-{finding.check_metadata.CheckID}-{provider.identity.account}-{finding.region}-{finding.resource_id}" - finding_output.Compliance = get_check_compliance( - finding, provider.type, output_options - ) - - if provider.organizations_metadata: - finding_output.OrganizationsInfo = ( - provider.organizations_metadata.__dict__ - ) - - except Exception as error: - logger.critical( - f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" - ) - sys.exit(1) - else: - return finding_output - - -class Check_Output_JSON(BaseModel): - """ - Check_Output_JSON generates a finding's output in JSON format. - - This is the base JSON output model for every provider. - """ - - AssessmentStartTime: str = "" - FindingUniqueId: str = "" - Provider: str - CheckID: str - CheckTitle: str - CheckType: List[str] - ServiceName: str - SubServiceName: str - Status: str = "" - StatusExtended: str = "" - Severity: str - ResourceType: str - ResourceDetails: str = "" - Description: str - Risk: str - RelatedUrl: str - Remediation: Remediation - Compliance: Optional[dict] - Categories: List[str] - DependsOn: List[str] - RelatedTo: List[str] - Notes: str - - -class Aws_Check_Output_JSON(Check_Output_JSON): - """ - Aws_Check_Output_JSON generates a finding's output in JSON format for the AWS provider. - """ - - Profile: str = "" - AccountId: str = "" - OrganizationsInfo: Optional[AWSOrganizationsInfo] - Region: str = "" - ResourceId: str = "" - ResourceArn: str = "" - ResourceTags: list = [] - - def __init__(self, **metadata): - super().__init__(**metadata) - - -class Azure_Check_Output_JSON(Check_Output_JSON): - """ - Azure_Check_Output_JSON generates a finding's output in JSON format for the AWS provider. - """ - - Tenant_Domain: str = "" - Subscription: str = "" - ResourceId: str = "" - ResourceName: str = "" - - def __init__(self, **metadata): - super().__init__(**metadata) - - -class Gcp_Check_Output_JSON(Check_Output_JSON): - """ - Gcp_Check_Output_JSON generates a finding's output in JSON format for the GCP provider. - """ - - ProjectId: str = "" - ResourceId: str = "" - ResourceName: str = "" - Location: str = "" - - def __init__(self, **metadata): - super().__init__(**metadata) - - -class Kubernetes_Check_Output_JSON(Check_Output_JSON): - """ - Kubernetes_Check_Output_JSON generates a finding's output in JSON format for the Kubernetes provider. - """ - - ResourceId: str = "" - ResourceName: str = "" - Context: str = "" - Namespace: str = "" - - def __init__(self, **metadata): - super().__init__(**metadata) - - class Check_Output_MITRE_ATTACK(BaseModel): """ Check_Output_MITRE_ATTACK generates a finding's output in CSV MITRE ATTACK format. diff --git a/prowler/lib/outputs/outputs.py b/prowler/lib/outputs/outputs.py index 1b76b6f79f..7fa0b9bf6a 100644 --- a/prowler/lib/outputs/outputs.py +++ b/prowler/lib/outputs/outputs.py @@ -20,7 +20,6 @@ from prowler.lib.outputs.json import fill_json_asff, fill_json_ocsf from prowler.lib.outputs.models import ( Check_Output_JSON_ASFF, - generate_provider_output_json, get_check_compliance, unroll_dict, ) @@ -141,20 +140,6 @@ def report(check_findings, provider): csv_writer.writerow(finding_output.dict()) - if "json" in file_descriptors: - finding_output = generate_provider_output_json( - provider, - finding, - "json", - output_options, - ) - json.dump( - finding_output.dict(), - file_descriptors["json"], - indent=4, - ) - file_descriptors["json"].write(",") - if "json-ocsf" in file_descriptors: finding_output = fill_json_ocsf( provider, finding, output_options diff --git a/prowler/lib/outputs/summary_table.py b/prowler/lib/outputs/summary_table.py index 0a67e63059..cb1a3d8412 100644 --- a/prowler/lib/outputs/summary_table.py +++ b/prowler/lib/outputs/summary_table.py @@ -6,7 +6,6 @@ from prowler.config.config import ( csv_file_suffix, json_asff_file_suffix, - json_file_suffix, json_ocsf_file_suffix, ) from prowler.lib.logger import logger @@ -124,10 +123,6 @@ def display_summary_table( ) if "csv" in output_options.output_modes: print(f" - CSV: {output_directory}/{output_filename}{csv_file_suffix}") - if "json" in output_options.output_modes: - print( - f" - JSON: {output_directory}/{output_filename}{json_file_suffix}" - ) else: print( diff --git a/prowler/providers/aws/lib/s3/s3.py b/prowler/providers/aws/lib/s3/s3.py index 62ec246c9d..afcb724d13 100644 --- a/prowler/providers/aws/lib/s3/s3.py +++ b/prowler/providers/aws/lib/s3/s3.py @@ -1,7 +1,6 @@ from prowler.config.config import ( csv_file_suffix, json_asff_file_suffix, - json_file_suffix, json_ocsf_file_suffix, ) from prowler.lib.logger import logger @@ -15,8 +14,6 @@ def send_to_s3_bucket( # Get only last part of the path if output_mode == "csv": filename = f"{output_filename}{csv_file_suffix}" - elif output_mode == "json": - filename = f"{output_filename}{json_file_suffix}" elif output_mode == "json-asff": filename = f"{output_filename}{json_asff_file_suffix}" elif output_mode == "json-ocsf": diff --git a/tests/lib/cli/parser_test.py b/tests/lib/cli/parser_test.py index 3da2bc478c..d4dc44394d 100644 --- a/tests/lib/cli/parser_test.py +++ b/tests/lib/cli/parser_test.py @@ -45,7 +45,6 @@ def test_default_parser_no_arguments_aws(self): assert len(parsed.output_modes) == 4 assert "csv" in parsed.output_modes - assert "json" in parsed.output_modes assert not parsed.output_filename assert "output" in parsed.output_directory assert not parsed.verbose @@ -93,7 +92,6 @@ def test_default_parser_no_arguments_azure(self): assert len(parsed.output_modes) == 4 assert "csv" in parsed.output_modes - assert "json" in parsed.output_modes assert not parsed.output_filename assert "output" in parsed.output_directory assert not parsed.verbose @@ -133,7 +131,6 @@ def test_default_parser_no_arguments_gcp(self): assert len(parsed.output_modes) == 4 assert "csv" in parsed.output_modes - assert "json" in parsed.output_modes assert not parsed.output_filename assert "output" in parsed.output_directory assert not parsed.verbose @@ -168,7 +165,6 @@ def test_default_parser_no_arguments_kubernetes(self): assert len(parsed.output_modes) == 4 assert "csv" in parsed.output_modes - assert "json" in parsed.output_modes assert not parsed.output_filename assert "output" in parsed.output_directory assert not parsed.verbose @@ -267,7 +263,6 @@ def test_root_parser_default_output_modes(self): parsed = self.parser.parse(command) assert len(parsed.output_modes) == 4 assert "csv" in parsed.output_modes - assert "json" in parsed.output_modes def test_root_parser_output_modes_short(self): command = [prowler_command, "-M", "csv"] diff --git a/tests/lib/outputs/outputs_test.py b/tests/lib/outputs/outputs_test.py index fe77510e10..ac62bf6525 100644 --- a/tests/lib/outputs/outputs_test.py +++ b/tests/lib/outputs/outputs_test.py @@ -98,10 +98,9 @@ def test_fill_file_descriptors(self): ) test_output_modes = [ ["csv"], - ["json"], ["json-asff"], - ["csv", "json"], - ["csv", "json", "json-asff"], + ["json-ocsf"], + ["csv", "json-asff", "json-ocsf"], ] output_filename = f"prowler-output-{audited_account}-{output_file_timestamp}" expected = [ @@ -111,12 +110,6 @@ def test_fill_file_descriptors(self): "a", ) }, - { - "json": open_file( - f"{output_directory}/{output_filename}{json_file_suffix}", - "a", - ) - }, { "json-asff": open_file( f"{output_directory}/{output_filename}{json_asff_file_suffix}", @@ -124,21 +117,17 @@ def test_fill_file_descriptors(self): ) }, { - "csv": open_file( - f"{output_directory}/{output_filename}{csv_file_suffix}", - "a", - ), - "json": open_file( - f"{output_directory}/{output_filename}{json_file_suffix}", + "json-ocsf": open_file( + f"{output_directory}/{output_filename}{json_asff_file_suffix}", "a", - ), + ) }, { "csv": open_file( f"{output_directory}/{output_filename}{csv_file_suffix}", "a", ), - "json": open_file( + "json-ocsf": open_file( f"{output_directory}/{output_filename}{json_file_suffix}", "a", ), diff --git a/tests/providers/common/common_outputs_test.py b/tests/providers/common/common_outputs_test.py index 37d64bc87e..8893ca209d 100644 --- a/tests/providers/common/common_outputs_test.py +++ b/tests/providers/common/common_outputs_test.py @@ -69,7 +69,7 @@ def test_set_provider_output_options_aws(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.output_filename = "output_test_filename" @@ -89,7 +89,7 @@ def test_set_provider_output_options_aws(self): assert output_options.security_hub_enabled assert output_options.send_sh_only_fails assert output_options.is_quiet - assert output_options.output_modes == ["csv", "json", "json-asff"] + assert output_options.output_modes == ["csv", "json-asff"] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == "" assert output_options.bulk_checks_metadata == {} @@ -105,7 +105,7 @@ def test_set_provider_output_options_gcp(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.output_filename = "output_test_filename" @@ -120,7 +120,7 @@ def test_set_provider_output_options_gcp(self): ) assert isinstance(output_options, Gcp_Output_Options) assert output_options.is_quiet - assert output_options.output_modes == ["csv", "json"] + assert output_options.output_modes == ["csv"] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == "" assert output_options.bulk_checks_metadata == {} @@ -136,7 +136,7 @@ def test_set_provider_output_options_kubernetes(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.output_filename = "output_test_filename" @@ -151,7 +151,7 @@ def test_set_provider_output_options_kubernetes(self): ) assert isinstance(output_options, Kubernetes_Output_Options) assert output_options.is_quiet - assert output_options.output_modes == ["csv", "json"] + assert output_options.output_modes == ["csv"] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == "" assert output_options.bulk_checks_metadata == {} @@ -167,7 +167,7 @@ def test_set_provider_output_options_aws_no_output_filename(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.security_hub = True @@ -188,7 +188,7 @@ def test_set_provider_output_options_aws_no_output_filename(self): assert output_options.security_hub_enabled assert output_options.send_sh_only_fails assert output_options.is_quiet - assert output_options.output_modes == ["csv", "json", "json-asff"] + assert output_options.output_modes == ["csv", "json-asff"] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == "" assert output_options.bulk_checks_metadata == {} @@ -207,7 +207,7 @@ def test_set_provider_output_options_azure_domain(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.only_logs = False @@ -227,7 +227,6 @@ def test_set_provider_output_options_azure_domain(self): assert output_options.is_quiet assert output_options.output_modes == [ "csv", - "json", ] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == "" @@ -247,7 +246,7 @@ def test_set_provider_output_options_azure_tenant_ids(self): # Set the arguments passed arguments = Namespace() arguments.quiet = True - arguments.output_modes = ["csv", "json"] + arguments.output_modes = ["csv"] arguments.output_directory = "output_test_directory" arguments.verbose = True arguments.only_logs = False @@ -268,7 +267,6 @@ def test_set_provider_output_options_azure_tenant_ids(self): assert output_options.is_quiet assert output_options.output_modes == [ "csv", - "json", ] assert output_options.output_directory == arguments.output_directory assert output_options.mutelist_file == ""