From d61e999b8fec380940a2c04114b8f0f02851a6a8 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Mon, 26 Aug 2024 15:25:19 +0200 Subject: [PATCH] chore(check_metadata): Rename to CheckMetadata (#4864) --- prowler/lib/check/check.py | 12 ++- prowler/lib/check/models.py | 82 ++++++++++++++++--- tests/lib/check/check_loader_test.py | 9 +- tests/lib/check/compliance_check_test.py | 6 +- .../lib/check/custom_checks_metadata_test.py | 9 +- .../check/fixtures/bulk_checks_metadata.py | 17 ++-- 6 files changed, 93 insertions(+), 42 deletions(-) diff --git a/prowler/lib/check/check.py b/prowler/lib/check/check.py index 9f3773daa2..c45399045d 100644 --- a/prowler/lib/check/check.py +++ b/prowler/lib/check/check.py @@ -17,7 +17,7 @@ import prowler from prowler.config.config import orange_color from prowler.lib.check.compliance_models import load_compliance_framework from prowler.lib.check.custom_checks_metadata import update_check_metadata -from prowler.lib.check.models import Check, load_check_metadata +from prowler.lib.check.models import Check, CheckMetadata, load_check_metadata from prowler.lib.logger import logger from prowler.lib.outputs.outputs import report from prowler.lib.utils.utils import open_file, parse_json_file, print_boxes @@ -25,7 +25,15 @@ from prowler.providers.common.models import Audit_Metadata # Load all checks metadata -def bulk_load_checks_metadata(provider: str) -> dict: +def bulk_load_checks_metadata(provider: str) -> dict[str, CheckMetadata]: + """ + Load the metadata of all checks for a given provider reading the check's metadata files. + Args: + provider (str): The name of the provider. + Returns: + dict[str, CheckMetadata]: A dictionary containing the metadata of all checks, with the CheckID as the key. + """ + bulk_check_metadata = {} checks = recover_checks_from_provider(provider) # Build list of check's metadata files diff --git a/prowler/lib/check/models.py b/prowler/lib/check/models.py index e11cebf237..daf828e362 100644 --- a/prowler/lib/check/models.py +++ b/prowler/lib/check/models.py @@ -11,7 +11,15 @@ from prowler.lib.logger import logger class Code(BaseModel): - """Check's remediation information using IaC like CloudFormation, Terraform or the native CLI""" + """ + Represents the remediation code using IaC like CloudFormation, Terraform or the native CLI. + + Attributes: + NativeIaC (str): The NativeIaC code. + Terraform (str): The Terraform code. + CLI (str): The CLI code. + Other (str): Other code. + """ NativeIaC: str Terraform: str @@ -20,21 +28,61 @@ class Code(BaseModel): class Recommendation(BaseModel): - """Check's recommendation information""" + """ + Represents a recommendation. + + Attributes: + Text (str): The text of the recommendation. + Url (str): The URL associated with the recommendation. + """ Text: str Url: str class Remediation(BaseModel): - """Check's remediation: Code and Recommendation""" + """ + Represents a remediation action for a specific . + + Attributes: + Code (Code): The code associated with the remediation action. + Recommendation (Recommendation): The recommendation for the remediation action. + """ Code: Code Recommendation: Recommendation -class Check_Metadata_Model(BaseModel): - """Check Metadata Model""" +class CheckMetadata(BaseModel): + """ + Model representing the metadata of a check. + + Attributes: + Provider (str): The provider of the check. + CheckID (str): The ID of the check. + CheckTitle (str): The title of the check. + CheckType (list[str]): The type of the check. + CheckAliases (list[str], optional): The aliases of the check. Defaults to an empty list. + ServiceName (str): The name of the service. + SubServiceName (str): The name of the sub-service. + ResourceIdTemplate (str): The template for the resource ID. + Severity (str): The severity of the check. + ResourceType (str): The type of the resource. + Description (str): The description of the check. + Risk (str): The risk associated with the check. + RelatedUrl (str): The URL related to the check. + Remediation (Remediation): The remediation steps for the check. + Categories (list[str]): The categories of the check. + DependsOn (list[str]): The dependencies of the check. + RelatedTo (list[str]): The related checks. + Notes (str): Additional notes for the check. + Compliance (list, optional): The compliance information for the check. Defaults to None. + + Validators: + valid_category(value): Validator function to validate the categories of the check. + severity_to_lower(severity): Validator function to convert the severity to lowercase. + valid_severity(severity): Validator function to validate the severity of the check. + """ Provider: str CheckID: str @@ -82,7 +130,7 @@ class Check_Metadata_Model(BaseModel): return severity -class Check(ABC, Check_Metadata_Model): +class Check(ABC, CheckMetadata): """Prowler Check""" def __init__(self, **data): @@ -93,7 +141,7 @@ class Check(ABC, Check_Metadata_Model): + ".metadata.json" ) # Store it to validate them with Pydantic - data = Check_Metadata_Model.parse_file(metadata_file).dict() + data = CheckMetadata.parse_file(metadata_file).dict() # Calls parents init function super().__init__(**data) # TODO: verify that the CheckID is the same as the filename and classname @@ -114,14 +162,14 @@ class Check_Report: status: str status_extended: str - check_metadata: Check_Metadata_Model + check_metadata: CheckMetadata resource_details: str resource_tags: list muted: bool def __init__(self, metadata): self.status = "" - self.check_metadata = Check_Metadata_Model.parse_raw(metadata) + self.check_metadata = CheckMetadata.parse_raw(metadata) self.status_extended = "" self.resource_details = "" self.resource_tags = [] @@ -194,12 +242,22 @@ class Check_Report_Kubernetes(Check_Report): # Testing Pending -def load_check_metadata(metadata_file: str) -> Check_Metadata_Model: - """load_check_metadata loads and parse a Check's metadata file""" +def load_check_metadata(metadata_file: str) -> CheckMetadata: + """ + Load check metadata from a file. + Args: + metadata_file (str): The path to the metadata file. + Returns: + CheckMetadata: The loaded check metadata. + Raises: + ValidationError: If the metadata file is not valid. + """ + try: - check_metadata = Check_Metadata_Model.parse_file(metadata_file) + check_metadata = CheckMetadata.parse_file(metadata_file) except ValidationError as error: logger.critical(f"Metadata from {metadata_file} is not valid: {error}") + # TODO: remove this exit and raise an exception sys.exit(1) else: return check_metadata diff --git a/tests/lib/check/check_loader_test.py b/tests/lib/check/check_loader_test.py index c562a6465e..829004a201 100644 --- a/tests/lib/check/check_loader_test.py +++ b/tests/lib/check/check_loader_test.py @@ -4,12 +4,7 @@ from prowler.lib.check.checks_loader import ( load_checks_to_execute, update_checks_to_execute_with_aliases, ) -from prowler.lib.check.models import ( - Check_Metadata_Model, - Code, - Recommendation, - Remediation, -) +from prowler.lib.check.models import CheckMetadata, Code, Recommendation, Remediation S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME = "s3_bucket_level_public_access_block" S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME_CUSTOM_ALIAS = ( @@ -23,7 +18,7 @@ class TestCheckLoader: provider = "aws" def get_custom_check_metadata(self): - return Check_Metadata_Model( + return CheckMetadata( Provider="aws", CheckID=S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME, CheckTitle="Check S3 Bucket Level Public Access Block.", diff --git a/tests/lib/check/compliance_check_test.py b/tests/lib/check/compliance_check_test.py index e51ae97a14..b563c14b7b 100644 --- a/tests/lib/check/compliance_check_test.py +++ b/tests/lib/check/compliance_check_test.py @@ -6,7 +6,7 @@ from prowler.lib.check.compliance_models import ( Compliance_Requirement, ComplianceBaseModel, ) -from prowler.lib.check.models import Check_Metadata_Model +from prowler.lib.check.models import CheckMetadata class TestCompliance: @@ -69,7 +69,7 @@ class TestCompliance: def get_custom_check_metadata(self): return { - "check1": Check_Metadata_Model( + "check1": CheckMetadata( Provider="aws", CheckID="check1", CheckTitle="Check 1", @@ -97,7 +97,7 @@ class TestCompliance: Notes="notes1", Compliance=[], ), - "check2": Check_Metadata_Model( + "check2": CheckMetadata( Provider="aws", CheckID="check2", CheckTitle="Check 2", diff --git a/tests/lib/check/custom_checks_metadata_test.py b/tests/lib/check/custom_checks_metadata_test.py index c1ea743f8e..a1974eeace 100644 --- a/tests/lib/check/custom_checks_metadata_test.py +++ b/tests/lib/check/custom_checks_metadata_test.py @@ -8,12 +8,7 @@ from prowler.lib.check.custom_checks_metadata import ( update_check_metadata, update_checks_metadata, ) -from prowler.lib.check.models import ( - Check_Metadata_Model, - Code, - Recommendation, - Remediation, -) +from prowler.lib.check.models import CheckMetadata, Code, Recommendation, Remediation CUSTOM_CHECKS_METADATA_FIXTURE_FILE = f"{os.path.dirname(os.path.realpath(__file__))}/fixtures/custom_checks_metadata_example.yaml" CUSTOM_CHECKS_METADATA_FIXTURE_FILE_NOT_VALID = f"{os.path.dirname(os.path.realpath(__file__))}/fixtures/custom_checks_metadata_example_not_valid.yaml" @@ -37,7 +32,7 @@ S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_REMEDIATION_URL = "https://docs.aws.amazon.c class TestCustomChecksMetadata: def get_custom_check_metadata(self): - return Check_Metadata_Model( + return CheckMetadata( Provider="aws", CheckID=S3_BUCKET_LEVEL_PUBLIC_ACCESS_BLOCK_NAME, CheckTitle="Check S3 Bucket Level Public Access Block.", diff --git a/tests/lib/check/fixtures/bulk_checks_metadata.py b/tests/lib/check/fixtures/bulk_checks_metadata.py index 977f40bbb1..f32d8a406f 100644 --- a/tests/lib/check/fixtures/bulk_checks_metadata.py +++ b/tests/lib/check/fixtures/bulk_checks_metadata.py @@ -1,12 +1,7 @@ -from prowler.lib.check.models import ( - Check_Metadata_Model, - Code, - Recommendation, - Remediation, -) +from prowler.lib.check.models import CheckMetadata, Code, Recommendation, Remediation test_bulk_checks_metadata = { - "vpc_peering_routing_tables_with_least_privilege": Check_Metadata_Model( + "vpc_peering_routing_tables_with_least_privilege": CheckMetadata( Provider="aws", CheckID="vpc_peering_routing_tables_with_least_privilege", CheckTitle="Ensure routing tables for VPC peering are least access.", @@ -37,7 +32,7 @@ test_bulk_checks_metadata = { Notes="", Compliance=None, ), - "vpc_subnet_different_az": Check_Metadata_Model( + "vpc_subnet_different_az": CheckMetadata( Provider="aws", CheckID="vpc_subnet_different_az", CheckTitle="Ensure all vpc has subnets in more than one availability zone", @@ -65,7 +60,7 @@ test_bulk_checks_metadata = { Notes="", Compliance=None, ), - "vpc_subnet_separate_private_public": Check_Metadata_Model( + "vpc_subnet_separate_private_public": CheckMetadata( Provider="aws", CheckID="vpc_subnet_separate_private_public", CheckTitle="Ensure all vpc has public and private subnets defined", @@ -92,7 +87,7 @@ test_bulk_checks_metadata = { Notes="", Compliance=None, ), - "workspaces_volume_encryption_enabled": Check_Metadata_Model( + "workspaces_volume_encryption_enabled": CheckMetadata( Provider="aws", CheckID="workspaces_volume_encryption_enabled", CheckTitle="Ensure that your Amazon WorkSpaces storage volumes are encrypted in order to meet security and compliance requirements", @@ -123,7 +118,7 @@ test_bulk_checks_metadata = { Notes="", Compliance=None, ), - "workspaces_vpc_2private_1public_subnets_nat": Check_Metadata_Model( + "workspaces_vpc_2private_1public_subnets_nat": CheckMetadata( Provider="aws", CheckID="workspaces_vpc_2private_1public_subnets_nat", CheckTitle="Ensure that the Workspaces VPC are deployed following the best practices using 1 public subnet and 2 private subnets with a NAT Gateway attached",