From bf7e363415ecdf218c10932154312c4e0fd0651a Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 6 Oct 2025 15:28:27 +0200 Subject: [PATCH] fix(compliance): generate file extension correctly (#8845) Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Co-authored-by: Daniel Barranquero --- prowler/CHANGELOG.md | 32 +----------- .../outputs/compliance/compliance_output.py | 5 +- .../lib/outputs/compliance/compliance_test.py | 51 +++++++++++++++++++ 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 6ba03f03c9..e641cf7c27 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -2,41 +2,11 @@ All notable changes to the **Prowler SDK** are documented in this file. -## [v5.13.0] (Prowler UNRELEASED) - -### Added -- Support for AdditionalURLs in outputs [(#8651)](https://github.com/prowler-cloud/prowler/pull/8651) -- Support for markdown metadata fields in Dashboard [(#8667)](https://github.com/prowler-cloud/prowler/pull/8667) -- `ec2_instance_with_outdated_ami` check for AWS provider [(#6910)](https://github.com/prowler-cloud/prowler/pull/6910) -- LLM provider using `promptfoo` [(#8555)](https://github.com/prowler-cloud/prowler/pull/8555) -- Documentation for renaming checks [(#8717)](https://github.com/prowler-cloud/prowler/pull/8717) -- Add explicit "name" field for each compliance framework and include "FRAMEWORK" and "NAME" in CSV output [(#7920)](https://github.com/prowler-cloud/prowler/pull/7920) -- Equality validation for CheckID, filename and classname [(#8690)](https://github.com/prowler-cloud/prowler/pull/8690) -- Improve logging for Security Hub integration [(#8608)](https://github.com/prowler-cloud/prowler/pull/8608) - -### Changed - -- Update AWS Neptune service metadata to new format [(#8494)](https://github.com/prowler-cloud/prowler/pull/8494) -- Update AWS Config service metadata to new format [(#8641)](https://github.com/prowler-cloud/prowler/pull/8641) -- Update AWS AccessAnalyzer service metadata to new format [(#8688)](https://github.com/prowler-cloud/prowler/pull/8688) -- Update AWS Api Gateway V2 service metadata to new format [(#8719)](https://github.com/prowler-cloud/prowler/pull/8719) -- Update AWS AppSync service metadata to new format [(#8721)](https://github.com/prowler-cloud/prowler/pull/8721) -- Update AWS ACM service metadata to new format [(#8716)](https://github.com/prowler-cloud/prowler/pull/8716) -- HTML output now properly renders markdown syntax in Risk and Recommendation fields [(#8727)](https://github.com/prowler-cloud/prowler/pull/8727) -- Update `moto` dependency from 5.0.28 to 5.1.11 [(#7100)](https://github.com/prowler-cloud/prowler/pull/7100) -- Update AWS Athena service metadata to new format [(#8790)](https://github.com/prowler-cloud/prowler/pull/8790) - - -### Fixed -- Fix SNS topics showing empty AWS_ResourceID in Quick Inventory output [(#8762)](https://github.com/prowler-cloud/prowler/issues/8762) -- Fix HTML Markdown output for long strings [(#8803)](https://github.com/prowler-cloud/prowler/pull/8803) - ---- - ## [v5.12.4] (Prowler UNRELEASED) ### Fixed - Fix KeyError in `elb_ssl_listeners_use_acm_certificate` check and handle None cluster version in `eks_cluster_uses_a_supported_version` check [(#8791)](https://github.com/prowler-cloud/prowler/pull/8791) +- Fix file extension parsing for compliance reports [(#8791)](https://github.com/prowler-cloud/prowler/pull/8791) --- diff --git a/prowler/lib/outputs/compliance/compliance_output.py b/prowler/lib/outputs/compliance/compliance_output.py index d3b855521e..f4f84561f4 100644 --- a/prowler/lib/outputs/compliance/compliance_output.py +++ b/prowler/lib/outputs/compliance/compliance_output.py @@ -42,7 +42,10 @@ class ComplianceOutput(Output): self._from_cli = from_cli if not file_extension and file_path: - self._file_extension = "".join(Path(file_path).suffixes) + # Compliance reports are always CSV, so just use the last suffix + # e.g., "cis_5.0_aws.csv" should have extension ".csv", not ".0_aws.csv" + path_obj = Path(file_path) + self._file_extension = path_obj.suffix if path_obj.suffix else "" if file_extension: self._file_extension = file_extension self.file_path = f"{file_path}{self.file_extension}" diff --git a/tests/lib/outputs/compliance/compliance_test.py b/tests/lib/outputs/compliance/compliance_test.py index b2fc94488f..a310231776 100644 --- a/tests/lib/outputs/compliance/compliance_test.py +++ b/tests/lib/outputs/compliance/compliance_test.py @@ -382,3 +382,54 @@ class TestCompliance: assert get_check_compliance(finding, "github", bulk_checks_metadata) == { "CIS-1.0": ["1.1.11"], } + + +class TestComplianceOutput: + """Test ComplianceOutput file extension parsing fix.""" + + def test_compliance_output_file_extension_with_dots(self): + """Test that ComplianceOutput correctly parses file extensions when framework names contain dots.""" + from prowler.lib.outputs.compliance.generic.generic import GenericCompliance + + compliance = Compliance( + Framework="CIS", + Version="5.0", + Provider="AWS", + Name="CIS Amazon Web Services Foundations Benchmark v5.0", + Description="Test compliance framework", + Requirements=[], + ) + + # Test with problematic file path that contains dots in framework name + # This simulates the real scenario from Prowler App S3 integration + problematic_file_path = "output/compliance/prowler-output-123456789012-20250101120000_cis_5.0_aws.csv" + + # Create GenericCompliance object with file_path (no explicit file_extension) + compliance_output = GenericCompliance( + findings=[], compliance=compliance, file_path=problematic_file_path + ) + + assert compliance_output.file_extension == ".csv" + assert compliance_output.file_extension != ".0_aws.csv" + + def test_compliance_output_file_extension_explicit(self): + """Test that ComplianceOutput uses explicit file_extension when provided.""" + from prowler.lib.outputs.compliance.generic.generic import GenericCompliance + + compliance = Compliance( + Framework="CIS", + Version="5.0", + Provider="AWS", + Name="CIS Amazon Web Services Foundations Benchmark v5.0", + Description="Test compliance framework", + Requirements=[], + ) + + compliance_output = GenericCompliance( + findings=[], + compliance=compliance, + file_path="output/compliance/test", + file_extension=".csv", + ) + + assert compliance_output.file_extension == ".csv"