diff --git a/prowler/lib/scan/exceptions/exceptions.py b/prowler/lib/scan/exceptions/exceptions.py index 07f89e2b3e..0cca901b13 100644 --- a/prowler/lib/scan/exceptions/exceptions.py +++ b/prowler/lib/scan/exceptions/exceptions.py @@ -1,31 +1,32 @@ from prowler.exceptions.exceptions import ProwlerException +# Exceptions codes from 5000 to 5999 are reserved for Scan exceptions class ScanBaseException(ProwlerException): """Base class for Scan errors.""" SCAN_ERROR_CODES = { - (2000, "ScanInvalidSeverityError"): { + (5000, "ScanInvalidSeverityError"): { "message": "Invalid severity level provided.", "remediation": "Please provide a valid severity level. Valid severities are: critical, high, medium, low, informational.", }, - (2001, "ScanInvalidCheckError"): { + (5001, "ScanInvalidCheckError"): { "message": "Invalid check provided.", "remediation": "Please provide a valid check name.", }, - (2002, "ScanInvalidServiceError"): { + (5002, "ScanInvalidServiceError"): { "message": "Invalid service provided.", "remediation": "Please provide a valid service name.", }, - (2003, "ScanInvalidComplianceFrameworkError"): { + (5003, "ScanInvalidComplianceFrameworkError"): { "message": "Invalid compliance framework provided.", "remediation": "Please provide a valid compliance framework name for the chosen provider.", }, - (2004, "ScanInvalidCategoryError"): { + (5004, "ScanInvalidCategoryError"): { "message": "Invalid category provided.", "remediation": "Please provide a valid category name.", }, - (2005, "ScanInvalidStatusError"): { + (5005, "ScanInvalidStatusError"): { "message": "Invalid status provided.", "remediation": "Please provide a valid status: FAIL, PASS, MANUAL.", }, @@ -48,40 +49,40 @@ class ScanBaseException(ProwlerException): class ScanInvalidSeverityError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2000, file=file, original_exception=original_exception, message=message + 5000, file=file, original_exception=original_exception, message=message ) class ScanInvalidCheckError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2001, file=file, original_exception=original_exception, message=message + 5001, file=file, original_exception=original_exception, message=message ) class ScanInvalidServiceError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2002, file=file, original_exception=original_exception, message=message + 5002, file=file, original_exception=original_exception, message=message ) class ScanInvalidComplianceFrameworkError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2003, file=file, original_exception=original_exception, message=message + 5003, file=file, original_exception=original_exception, message=message ) class ScanInvalidCategoryError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2004, file=file, original_exception=original_exception, message=message + 5004, file=file, original_exception=original_exception, message=message ) class ScanInvalidStatusError(ScanBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 2005, file=file, original_exception=original_exception, message=message + 5005, file=file, original_exception=original_exception, message=message ) diff --git a/prowler/providers/aws/aws_provider.py b/prowler/providers/aws/aws_provider.py index 72769ccfa0..80dea448ba 100644 --- a/prowler/providers/aws/aws_provider.py +++ b/prowler/providers/aws/aws_provider.py @@ -24,21 +24,21 @@ from prowler.providers.aws.config import ( ROLE_SESSION_NAME, ) from prowler.providers.aws.exceptions.exceptions import ( - AWSAccessKeyIDInvalid, + AWSAccessKeyIDInvalidError, AWSArgumentTypeValidationError, AWSAssumeRoleError, AWSClientError, - AWSIAMRoleARNEmptyResource, - AWSIAMRoleARNInvalidAccountID, - AWSIAMRoleARNInvalidResourceType, - AWSIAMRoleARNPartitionEmpty, - AWSIAMRoleARNRegionNotEmtpy, - AWSIAMRoleARNServiceNotIAMnorSTS, - AWSInvalidAccountCredentials, + AWSIAMRoleARNEmptyResourceError, + AWSIAMRoleARNInvalidAccountIDError, + AWSIAMRoleARNInvalidResourceTypeError, + AWSIAMRoleARNPartitionEmptyError, + AWSIAMRoleARNRegionNotEmtpyError, + AWSIAMRoleARNServiceNotIAMnorSTSError, + AWSInvalidProviderIdError, AWSNoCredentialsError, AWSProfileNotFoundError, - AWSSecretAccessKeyInvalid, - AWSSessionTokenExpired, + AWSSecretAccessKeyInvalidError, + AWSSessionTokenExpiredError, AWSSetUpSessionError, ) from prowler.providers.aws.lib.arn.arn import parse_iam_credentials_arn @@ -974,17 +974,17 @@ class AwsProvider(Provider): f"{client_error.__class__.__name__}[{client_error.__traceback__.tb_lineno}]: {client_error}" ) if client_error.response["Error"]["Code"] == "InvalidClientTokenId": - raise AWSAccessKeyIDInvalid( + raise AWSAccessKeyIDInvalidError( original_exception=client_error, file=pathlib.Path(__file__).name, ) elif client_error.response["Error"]["Code"] == "SignatureDoesNotMatch": - raise AWSSecretAccessKeyInvalid( + raise AWSSecretAccessKeyInvalidError( original_exception=client_error, file=pathlib.Path(__file__).name, ) elif client_error.response["Error"]["Code"] == "ExpiredToken": - raise AWSSessionTokenExpired( + raise AWSSessionTokenExpiredError( original_exception=client_error, file=pathlib.Path(__file__).name, ) @@ -1097,62 +1097,80 @@ class AwsProvider(Provider): caller_identity = AwsProvider.validate_credentials(session, aws_region) # Do an extra validation if the AWS account ID is provided if provider_id and caller_identity.account != provider_id: - raise AWSInvalidAccountCredentials(file=pathlib.Path(__file__).name) + raise AWSInvalidProviderIdError(file=pathlib.Path(__file__).name) return Connection( is_connected=True, ) except AWSSetUpSessionError as setup_session_error: - logger.error(str(setup_session_error)) + logger.error( + f"{setup_session_error.__class__.__name__}[{setup_session_error.__traceback__.tb_lineno}]: {setup_session_error}" + ) if raise_on_exception: raise setup_session_error return Connection(error=setup_session_error) except AWSArgumentTypeValidationError as validation_error: - logger.error(str(validation_error)) + logger.error( + f"{validation_error.__class__.__name__}[{validation_error.__traceback__.tb_lineno}]: {validation_error}" + ) if raise_on_exception: raise validation_error return Connection(error=validation_error) - except AWSIAMRoleARNRegionNotEmtpy as arn_region_not_empty_error: - logger.error(str(arn_region_not_empty_error)) + except AWSIAMRoleARNRegionNotEmtpyError as arn_region_not_empty_error: + logger.error( + f"{arn_region_not_empty_error.__class__.__name__}[{arn_region_not_empty_error.__traceback__.tb_lineno}]: {arn_region_not_empty_error}" + ) if raise_on_exception: raise arn_region_not_empty_error return Connection(error=arn_region_not_empty_error) - except AWSIAMRoleARNPartitionEmpty as arn_partition_empty_error: - logger.error(str(arn_partition_empty_error)) + except AWSIAMRoleARNPartitionEmptyError as arn_partition_empty_error: + logger.error( + f"{arn_partition_empty_error.__class__.__name__}[{arn_partition_empty_error.__traceback__.tb_lineno}]: {arn_partition_empty_error}" + ) if raise_on_exception: raise arn_partition_empty_error return Connection(error=arn_partition_empty_error) - except AWSIAMRoleARNServiceNotIAMnorSTS as arn_service_not_iam_sts_error: - logger.error(str(arn_service_not_iam_sts_error)) + except AWSIAMRoleARNServiceNotIAMnorSTSError as arn_service_not_iam_sts_error: + logger.error( + f"{arn_service_not_iam_sts_error.__class__.__name__}[{arn_service_not_iam_sts_error.__traceback__.tb_lineno}]: {arn_service_not_iam_sts_error}" + ) if raise_on_exception: raise arn_service_not_iam_sts_error return Connection(error=arn_service_not_iam_sts_error) - except AWSIAMRoleARNInvalidAccountID as arn_invalid_account_id_error: - logger.error(str(arn_invalid_account_id_error)) + except AWSIAMRoleARNInvalidAccountIDError as arn_invalid_account_id_error: + logger.error( + f"{arn_invalid_account_id_error.__class__.__name__}[{arn_invalid_account_id_error.__traceback__.tb_lineno}]: {arn_invalid_account_id_error}" + ) if raise_on_exception: raise arn_invalid_account_id_error return Connection(error=arn_invalid_account_id_error) - except AWSIAMRoleARNInvalidResourceType as arn_invalid_resource_type_error: - logger.error(str(arn_invalid_resource_type_error)) + except AWSIAMRoleARNInvalidResourceTypeError as arn_invalid_resource_type_error: + logger.error( + f"{arn_invalid_resource_type_error.__class__.__name__}[{arn_invalid_resource_type_error.__traceback__.tb_lineno}]: {arn_invalid_resource_type_error}" + ) if raise_on_exception: raise arn_invalid_resource_type_error return Connection(error=arn_invalid_resource_type_error) - except AWSIAMRoleARNEmptyResource as arn_empty_resource_error: - logger.error(str(arn_empty_resource_error)) + except AWSIAMRoleARNEmptyResourceError as arn_empty_resource_error: + logger.error( + f"{arn_empty_resource_error.__class__.__name__}[{arn_empty_resource_error.__traceback__.tb_lineno}]: {arn_empty_resource_error}" + ) if raise_on_exception: raise arn_empty_resource_error return Connection(error=arn_empty_resource_error) except AWSAssumeRoleError as assume_role_error: - logger.error(str(assume_role_error)) + logger.error( + f"{assume_role_error.__class__.__name__}[{assume_role_error.__traceback__.tb_lineno}]: {assume_role_error}" + ) if raise_on_exception: raise assume_role_error return Connection(error=assume_role_error) @@ -1189,26 +1207,34 @@ class AwsProvider(Provider): ) from no_credentials_error return Connection(error=no_credentials_error) - except AWSAccessKeyIDInvalid as access_key_id_invalid_error: - logger.error(str(access_key_id_invalid_error)) + except AWSAccessKeyIDInvalidError as access_key_id_invalid_error: + logger.error( + f"{access_key_id_invalid_error.__class__.__name__}[{access_key_id_invalid_error.__traceback__.tb_lineno}]: {access_key_id_invalid_error}" + ) if raise_on_exception: raise access_key_id_invalid_error return Connection(error=access_key_id_invalid_error) - except AWSSecretAccessKeyInvalid as secret_access_key_invalid_error: - logger.error(str(secret_access_key_invalid_error)) + except AWSSecretAccessKeyInvalidError as secret_access_key_invalid_error: + logger.error( + f"{secret_access_key_invalid_error.__class__.__name__}[{secret_access_key_invalid_error.__traceback__.tb_lineno}]: {secret_access_key_invalid_error}" + ) if raise_on_exception: raise secret_access_key_invalid_error return Connection(error=secret_access_key_invalid_error) - except AWSInvalidAccountCredentials as invalid_account_credentials_error: - logger.error(str(invalid_account_credentials_error)) + except AWSInvalidProviderIdError as invalid_account_credentials_error: + logger.error( + f"{invalid_account_credentials_error.__class__.__name__}[{invalid_account_credentials_error.__traceback__.tb_lineno}]: {invalid_account_credentials_error}" + ) if raise_on_exception: raise invalid_account_credentials_error return Connection(error=invalid_account_credentials_error) - except AWSSessionTokenExpired as session_token_expired: - logger.error(str(session_token_expired)) + except AWSSessionTokenExpiredError as session_token_expired: + logger.error( + f"{session_token_expired.__class__.__name__}[{session_token_expired.__traceback__.tb_lineno}]: {session_token_expired}" + ) if raise_on_exception: raise session_token_expired return Connection(error=session_token_expired) diff --git a/prowler/providers/aws/exceptions/exceptions.py b/prowler/providers/aws/exceptions/exceptions.py index b4773e8667..236fc8dc55 100644 --- a/prowler/providers/aws/exceptions/exceptions.py +++ b/prowler/providers/aws/exceptions/exceptions.py @@ -1,75 +1,76 @@ from prowler.exceptions.exceptions import ProwlerException +# Exceptions codes from 1000 to 1999 are reserved for AWS exceptions class AWSBaseException(ProwlerException): """Base class for AWS errors.""" AWS_ERROR_CODES = { - (1902, "AWSClientError"): { + (1000, "AWSClientError"): { "message": "AWS ClientError occurred", "remediation": "Check your AWS client configuration and permissions.", }, - (1903, "AWSProfileNotFoundError"): { + (1001, "AWSProfileNotFoundError"): { "message": "AWS Profile not found", "remediation": "Ensure the AWS profile is correctly configured, please visit https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html", }, - (1904, "AWSNoCredentialsError"): { + (1002, "AWSNoCredentialsError"): { "message": "No AWS credentials found", "remediation": "Verify that AWS credentials are properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/authentication/ and https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-configure.html", }, - (1905, "AWSArgumentTypeValidationError"): { + (1003, "AWSArgumentTypeValidationError"): { "message": "AWS argument type validation error", "remediation": "Check the provided argument types specific to AWS and ensure they meet the required format. For session duration check: https://docs.aws.amazon.com/singlesignon/latest/userguide/howtosessionduration.html and for role session name check: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name", }, - (1906, "AWSSetUpSessionError"): { + (1004, "AWSSetUpSessionError"): { "message": "AWS session setup error", "remediation": "Check the AWS session setup and ensure it is properly configured, please visit https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html and check if the provided profile has the necessary permissions.", }, - (1907, "AWSIAMRoleARNRegionNotEmtpy"): { + (1005, "AWSIAMRoleARNRegionNotEmtpyError"): { "message": "AWS IAM Role ARN region is not empty", "remediation": "Check the AWS IAM Role ARN region and ensure it is empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1908, "AWSIAMRoleARNPartitionEmpty"): { + (1006, "AWSIAMRoleARNPartitionEmptyError"): { "message": "AWS IAM Role ARN partition is empty", "remediation": "Check the AWS IAM Role ARN partition and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1909, "AWSIAMRoleARNMissingFields"): { + (1007, "AWSIAMRoleARNMissingFieldsError"): { "message": "AWS IAM Role ARN missing fields", "remediation": "Check the AWS IAM Role ARN and ensure all required fields are present, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1910, "AWSIAMRoleARNServiceNotIAMnorSTS"): { + (1008, "AWSIAMRoleARNServiceNotIAMnorSTSError"): { "message": "AWS IAM Role ARN service is not IAM nor STS", "remediation": "Check the AWS IAM Role ARN service and ensure it is either IAM or STS, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1911, "AWSIAMRoleARNInvalidAccountID"): { + (1009, "AWSIAMRoleARNInvalidAccountIDError"): { "message": "AWS IAM Role ARN account ID is invalid", "remediation": "Check the AWS IAM Role ARN account ID and ensure it is a valid 12-digit number, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1912, "AWSIAMRoleARNInvalidResourceType"): { + (1010, "AWSIAMRoleARNInvalidResourceTypeError"): { "message": "AWS IAM Role ARN resource type is invalid", "remediation": "Check the AWS IAM Role ARN resource type and ensure it is valid, resources types are: role, user, assumed-role, root, federated-user, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1913, "AWSIAMRoleARNEmptyResource"): { + (1011, "AWSIAMRoleARNEmptyResourceError"): { "message": "AWS IAM Role ARN resource is empty", "remediation": "Check the AWS IAM Role ARN resource and ensure it is not empty, visit https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns for more information.", }, - (1914, "AWSAssumeRoleError"): { + (1012, "AWSAssumeRoleError"): { "message": "AWS assume role error", "remediation": "Check the AWS assume role configuration and ensure it is properly set up, please visit https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/aws/role-assumption/ and https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-role-session-name", }, - (1915, "AWSAccessKeyIDInvalid"): { + (1013, "AWSAccessKeyIDInvalidError"): { "message": "AWS Access Key ID or Session Token is invalid", "remediation": "Check your AWS Access Key ID or Session Token and ensure it is valid.", }, - (1916, "AWSSecretAccessKeyInvalid"): { + (1014, "AWSSecretAccessKeyInvalidError"): { "message": "AWS Secret Access Key is invalid", "remediation": "Check your AWS Secret Access Key and signing method and ensure it is valid.", }, - (1917, "AWSInvalidAccountCredentials"): { + (1015, "AWSInvalidProviderIdError"): { "message": "The provided AWS credentials belong to a different account", "remediation": "Check the provided AWS credentials and review if belong to the account you want to use.", }, - (1918, "AWSSessionTokenExpired"): { + (1016, "AWSSessionTokenExpiredError"): { "message": "The provided AWS Session Token is expired", "remediation": "Get a new AWS Session Token and configure it for the provider.", }, @@ -98,35 +99,35 @@ class AWSCredentialsError(AWSBaseException): class AWSClientError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1902, file=file, original_exception=original_exception, message=message + 1000, file=file, original_exception=original_exception, message=message ) class AWSProfileNotFoundError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1903, file=file, original_exception=original_exception, message=message + 1001, file=file, original_exception=original_exception, message=message ) class AWSNoCredentialsError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1904, file=file, original_exception=original_exception, message=message + 1002, file=file, original_exception=original_exception, message=message ) class AWSArgumentTypeValidationError(AWSBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1905, file=file, original_exception=original_exception, message=message + 1003, file=file, original_exception=original_exception, message=message ) class AWSSetUpSessionError(AWSBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1906, file=file, original_exception=original_exception, message=message + 1004, file=file, original_exception=original_exception, message=message ) @@ -137,85 +138,85 @@ class AWSRoleArnError(AWSBaseException): super().__init__(code, file, original_exception, message) -class AWSIAMRoleARNRegionNotEmtpy(AWSRoleArnError): +class AWSIAMRoleARNRegionNotEmtpyError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1907, file=file, original_exception=original_exception, message=message + 1005, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNPartitionEmpty(AWSRoleArnError): +class AWSIAMRoleARNPartitionEmptyError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1908, file=file, original_exception=original_exception, message=message + 1006, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNMissingFields(AWSRoleArnError): +class AWSIAMRoleARNMissingFieldsError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1909, file=file, original_exception=original_exception, message=message + 1007, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNServiceNotIAMnorSTS(AWSRoleArnError): +class AWSIAMRoleARNServiceNotIAMnorSTSError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1910, file=file, original_exception=original_exception, message=message + 1008, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNInvalidAccountID(AWSRoleArnError): +class AWSIAMRoleARNInvalidAccountIDError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1911, file=file, original_exception=original_exception, message=message + 1009, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNInvalidResourceType(AWSRoleArnError): +class AWSIAMRoleARNInvalidResourceTypeError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1912, file=file, original_exception=original_exception, message=message + 1010, file=file, original_exception=original_exception, message=message ) -class AWSIAMRoleARNEmptyResource(AWSRoleArnError): +class AWSIAMRoleARNEmptyResourceError(AWSRoleArnError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1913, file=file, original_exception=original_exception, message=message + 1011, file=file, original_exception=original_exception, message=message ) class AWSAssumeRoleError(AWSBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1914, file=file, original_exception=original_exception, message=message + 1012, file=file, original_exception=original_exception, message=message ) -class AWSAccessKeyIDInvalid(AWSCredentialsError): +class AWSAccessKeyIDInvalidError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1915, file=file, original_exception=original_exception, message=message + 1013, file=file, original_exception=original_exception, message=message ) -class AWSSecretAccessKeyInvalid(AWSCredentialsError): +class AWSSecretAccessKeyInvalidError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1916, file=file, original_exception=original_exception, message=message + 1014, file=file, original_exception=original_exception, message=message ) -class AWSInvalidAccountCredentials(AWSCredentialsError): +class AWSInvalidProviderIdError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1917, file=file, original_exception=original_exception, message=message + 1015, file=file, original_exception=original_exception, message=message ) -class AWSSessionTokenExpired(AWSCredentialsError): +class AWSSessionTokenExpiredError(AWSCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1918, file=file, original_exception=original_exception, message=message + 1016, file=file, original_exception=original_exception, message=message ) diff --git a/prowler/providers/aws/lib/arn/arn.py b/prowler/providers/aws/lib/arn/arn.py index 3084f61629..c31e788531 100644 --- a/prowler/providers/aws/lib/arn/arn.py +++ b/prowler/providers/aws/lib/arn/arn.py @@ -3,12 +3,12 @@ import re from argparse import ArgumentTypeError from prowler.providers.aws.exceptions.exceptions import ( - AWSIAMRoleARNEmptyResource, - AWSIAMRoleARNInvalidAccountID, - AWSIAMRoleARNInvalidResourceType, - AWSIAMRoleARNPartitionEmpty, - AWSIAMRoleARNRegionNotEmtpy, - AWSIAMRoleARNServiceNotIAMnorSTS, + AWSIAMRoleARNEmptyResourceError, + AWSIAMRoleARNInvalidAccountIDError, + AWSIAMRoleARNInvalidResourceTypeError, + AWSIAMRoleARNPartitionEmptyError, + AWSIAMRoleARNRegionNotEmtpyError, + AWSIAMRoleARNServiceNotIAMnorSTSError, ) from prowler.providers.aws.lib.arn.models import ARN @@ -25,7 +25,7 @@ def parse_iam_credentials_arn(arn: str) -> ARN: arn_parsed = ARN(arn) # First check if region is empty (in IAM ARN's region is always empty) if arn_parsed.region: - raise AWSIAMRoleARNRegionNotEmtpy(file=os.path.basename(__file__)) + raise AWSIAMRoleARNRegionNotEmtpyError(file=os.path.basename(__file__)) else: # check if needed fields are filled: # - partition @@ -34,15 +34,15 @@ def parse_iam_credentials_arn(arn: str) -> ARN: # - resource_type # - resource if arn_parsed.partition is None or arn_parsed.partition == "": - raise AWSIAMRoleARNPartitionEmpty(file=os.path.basename(__file__)) + raise AWSIAMRoleARNPartitionEmptyError(file=os.path.basename(__file__)) elif arn_parsed.service != "iam" and arn_parsed.service != "sts": - raise AWSIAMRoleARNServiceNotIAMnorSTS(file=os.path.basename(__file__)) + raise AWSIAMRoleARNServiceNotIAMnorSTSError(file=os.path.basename(__file__)) elif ( arn_parsed.account_id is None or len(arn_parsed.account_id) != 12 or not arn_parsed.account_id.isnumeric() ): - raise AWSIAMRoleARNInvalidAccountID(file=os.path.basename(__file__)) + raise AWSIAMRoleARNInvalidAccountIDError(file=os.path.basename(__file__)) elif ( arn_parsed.resource_type != "role" and arn_parsed.resource_type != "user" @@ -50,9 +50,9 @@ def parse_iam_credentials_arn(arn: str) -> ARN: and arn_parsed.resource_type != "root" and arn_parsed.resource_type != "federated-user" ): - raise AWSIAMRoleARNInvalidResourceType(file=os.path.basename(__file__)) + raise AWSIAMRoleARNInvalidResourceTypeError(file=os.path.basename(__file__)) elif arn_parsed.resource == "": - raise AWSIAMRoleARNEmptyResource(file=os.path.basename(__file__)) + raise AWSIAMRoleARNEmptyResourceError(file=os.path.basename(__file__)) else: return arn_parsed diff --git a/prowler/providers/aws/lib/arn/models.py b/prowler/providers/aws/lib/arn/models.py index f34b53ab32..ba0be84452 100644 --- a/prowler/providers/aws/lib/arn/models.py +++ b/prowler/providers/aws/lib/arn/models.py @@ -3,7 +3,7 @@ from typing import Optional from pydantic import BaseModel -from prowler.providers.aws.exceptions.exceptions import AWSIAMRoleARNMissingFields +from prowler.providers.aws.exceptions.exceptions import AWSIAMRoleARNMissingFieldsError class ARN(BaseModel): @@ -19,7 +19,7 @@ class ARN(BaseModel): # Validate the ARN ## Check that arn starts with arn if not arn.startswith("arn:"): - raise AWSIAMRoleARNMissingFields(file=os.path.basename(__file__)) + raise AWSIAMRoleARNMissingFieldsError(file=os.path.basename(__file__)) ## Retrieve fields arn_elements = arn.split(":", 5) data = { diff --git a/prowler/providers/azure/azure_provider.py b/prowler/providers/azure/azure_provider.py index 40272f3bda..574df54e5b 100644 --- a/prowler/providers/azure/azure_provider.py +++ b/prowler/providers/azure/azure_provider.py @@ -32,10 +32,10 @@ from prowler.providers.azure.exceptions.exceptions import ( AzureGetTokenIdentityError, AzureHTTPResponseError, AzureInteractiveBrowserCredentialError, - AzureInvalidAccountCredentialsError, + AzureInvalidProviderIdError, AzureNoAuthenticationMethodError, AzureNoSubscriptionsError, - AzureNotTenantIdButClientIdAndClienSecret, + AzureNotTenantIdButClientIdAndClienSecretError, AzureNotValidClientIdError, AzureNotValidClientSecretError, AzureNotValidTenantIdError, @@ -320,7 +320,7 @@ class AzureProvider(Provider): ) else: if not tenant_id: - raise AzureNotTenantIdButClientIdAndClienSecret( + raise AzureNotTenantIdButClientIdAndClienSecretError( file=os.path.basename(__file__), message="Tenant Id is required for Azure static credentials. Make sure you are using the correct credentials.", ) @@ -621,7 +621,7 @@ class AzureProvider(Provider): if provider_id and provider_id not in [ sub.subscription_id for sub in available_subscriptions ]: - raise AzureInvalidAccountCredentialsError( + raise AzureInvalidProviderIdError( file=os.path.basename(__file__), message="The provided credentials are not valid for the specified Azure subscription.", ) @@ -631,88 +631,120 @@ class AzureProvider(Provider): return Connection(is_connected=True) # Exceptions from validate_arguments except AzureNoAuthenticationMethodError as no_auth_method_error: - logger.error(str(no_auth_method_error)) + logger.error( + f"{no_auth_method_error.__class__.__name__}[{no_auth_method_error.__traceback__.tb_lineno}]: {no_auth_method_error}" + ) if raise_on_exception: raise no_auth_method_error return Connection(error=no_auth_method_error) except AzureBrowserAuthNoTenantIDError as browser_no_tenant_error: - logger.error(str(browser_no_tenant_error)) + logger.error( + f"{browser_no_tenant_error.__class__.__name__}[{browser_no_tenant_error.__traceback__.tb_lineno}]: {browser_no_tenant_error}" + ) if raise_on_exception: raise browser_no_tenant_error return Connection(error=browser_no_tenant_error) except AzureTenantIDNoBrowserAuthError as tenant_no_browser_error: - logger.error(str(tenant_no_browser_error)) + logger.error( + f"{tenant_no_browser_error.__class__.__name__}[{tenant_no_browser_error.__traceback__.tb_lineno}]: {tenant_no_browser_error}" + ) # Exceptions from setup_region_config except AzureArgumentTypeValidationError as type_validation_error: - logger.error(str(type_validation_error)) + logger.error( + f"{type_validation_error.__class__.__name__}[{type_validation_error.__traceback__.tb_lineno}]: {type_validation_error}" + ) if raise_on_exception: raise type_validation_error return Connection(error=type_validation_error) except AzureSetUpRegionConfigError as region_config_error: - logger.error(str(region_config_error)) + logger.error( + f"{region_config_error.__class__.__name__}[{region_config_error.__traceback__.tb_lineno}]: {region_config_error}" + ) if raise_on_exception: raise region_config_error return Connection(error=region_config_error) # Exceptions from setup_session except AzureEnvironmentVariableError as environment_credentials_error: - logger.error(str(environment_credentials_error)) + logger.error( + f"{environment_credentials_error.__class__.__name__}[{environment_credentials_error.__traceback__.tb_lineno}]: {environment_credentials_error}" + ) if raise_on_exception: raise environment_credentials_error return Connection(error=environment_credentials_error) except AzureDefaultAzureCredentialError as default_credentials_error: - logger.error(str(default_credentials_error)) + logger.error( + f"{default_credentials_error.__class__.__name__}[{default_credentials_error.__traceback__.tb_lineno}]: {default_credentials_error}" + ) if raise_on_exception: raise default_credentials_error return Connection(error=default_credentials_error) except AzureInteractiveBrowserCredentialError as interactive_browser_error: - logger.error(str(interactive_browser_error)) + logger.error( + f"{interactive_browser_error.__class__.__name__}[{interactive_browser_error.__traceback__.tb_lineno}]: {interactive_browser_error}" + ) if raise_on_exception: raise interactive_browser_error return Connection(error=interactive_browser_error) except AzureConfigCredentialsError as config_credentials_error: - logger.error(str(config_credentials_error)) + logger.error( + f"{config_credentials_error.__class__.__name__}[{config_credentials_error.__traceback__.tb_lineno}]: {config_credentials_error}" + ) if raise_on_exception: raise config_credentials_error return Connection(error=config_credentials_error) except AzureClientAuthenticationError as client_auth_error: - logger.error(str(client_auth_error)) + logger.error( + f"{client_auth_error.__class__.__name__}[{client_auth_error.__traceback__.tb_lineno}]: {client_auth_error}" + ) if raise_on_exception: raise client_auth_error return Connection(error=client_auth_error) except AzureCredentialsUnavailableError as credential_unavailable_error: - logger.error(str(credential_unavailable_error)) + logger.error( + f"{credential_unavailable_error.__class__.__name__}[{credential_unavailable_error.__traceback__.tb_lineno}]: {credential_unavailable_error}" + ) if raise_on_exception: raise credential_unavailable_error return Connection(error=credential_unavailable_error) except AzureDefaultAzureCredentialError as default_credentials_error: - logger.error(str(default_credentials_error)) + logger.error( + f"{default_credentials_error.__class__.__name__}[{default_credentials_error.__traceback__.tb_lineno}]: {default_credentials_error}" + ) if raise_on_exception: raise default_credentials_error return Connection(error=default_credentials_error) except ( AzureClientIdAndClientSecretNotBelongingToTenantIdError ) as tenant_id_error: - logger.error(str(tenant_id_error)) + logger.error( + f"{tenant_id_error.__class__.__name__}[{tenant_id_error.__traceback__.tb_lineno}]: {tenant_id_error}" + ) if raise_on_exception: raise tenant_id_error return Connection(error=tenant_id_error) except ( AzureTenantIdAndClientSecretNotBelongingToClientIdError ) as client_id_error: - logger.error(str(client_id_error)) + logger.error( + f"{client_id_error.__class__.__name__}[{client_id_error.__traceback__.tb_lineno}]: {client_id_error}" + ) if raise_on_exception: raise client_id_error return Connection(error=client_id_error) except ( AzureTenantIdAndClientIdNotBelongingToClientSecretError ) as client_secret_error: - logger.error(str(client_secret_error)) + logger.error( + f"{client_secret_error.__class__.__name__}[{client_secret_error.__traceback__.tb_lineno}]: {client_secret_error}" + ) if raise_on_exception: raise client_secret_error return Connection(error=client_secret_error) # Exceptions from provider_id validation - except AzureInvalidAccountCredentialsError as invalid_credentials_error: - logger.error(str(invalid_credentials_error)) + except AzureInvalidProviderIdError as invalid_credentials_error: + logger.error( + f"{invalid_credentials_error.__class__.__name__}[{invalid_credentials_error.__traceback__.tb_lineno}]: {invalid_credentials_error}" + ) if raise_on_exception: raise invalid_credentials_error return Connection(error=invalid_credentials_error) @@ -998,19 +1030,25 @@ class AzureProvider(Provider): "client_secret": client_secret, } except AzureNotValidTenantIdError as tenant_id_error: - logger.error(str(tenant_id_error)) + logger.error( + f"{tenant_id_error.__class__.__name__}[{tenant_id_error.__traceback__.tb_lineno}]: {tenant_id_error}" + ) raise AzureClientIdAndClientSecretNotBelongingToTenantIdError( file=os.path.basename(__file__), message="The provided Azure Client ID and Client Secret do not belong to the specified Tenant ID.", ) except AzureNotValidClientIdError as client_id_error: - logger.error(str(client_id_error)) + logger.error( + f"{client_id_error.__class__.__name__}[{client_id_error.__traceback__.tb_lineno}]: {client_id_error}" + ) raise AzureTenantIdAndClientSecretNotBelongingToClientIdError( file=os.path.basename(__file__), message="The provided Azure Tenant ID and Client Secret do not belong to the specified Client ID.", ) except AzureNotValidClientSecretError as client_secret_error: - logger.error(str(client_secret_error)) + logger.error( + f"{client_secret_error.__class__.__name__}[{client_secret_error.__traceback__.tb_lineno}]: {client_secret_error}" + ) raise AzureTenantIdAndClientIdNotBelongingToClientSecretError( file=os.path.basename(__file__), message="The provided Azure Tenant ID and Client ID do not belong to the specified Client Secret.", diff --git a/prowler/providers/azure/exceptions/exceptions.py b/prowler/providers/azure/exceptions/exceptions.py index 9b4d0e443b..5114c867a4 100644 --- a/prowler/providers/azure/exceptions/exceptions.py +++ b/prowler/providers/azure/exceptions/exceptions.py @@ -1,103 +1,104 @@ from prowler.exceptions.exceptions import ProwlerException +# Exceptions codes from 2000 to 2999 are reserved for Azure exceptions class AzureBaseException(ProwlerException): """Base class for Azure Errors.""" AZURE_ERROR_CODES = { - (1914, "AzureEnvironmentVariableError"): { + (2000, "AzureEnvironmentVariableError"): { "message": "Azure environment variable error", "remediation": "Check the Azure environment variables and ensure they are properly set.", }, - (1915, "AzureNoSubscriptionsError"): { + (2001, "AzureNoSubscriptionsError"): { "message": "No Azure subscriptions found", "remediation": "Check the Azure subscriptions and ensure they are properly set up.", }, - (1916, "AzureSetUpIdentityError"): { + (2002, "AzureSetUpIdentityError"): { "message": "Azure identity setup error related with credentials", "remediation": "Check credentials and ensure they are properly set up for Azure and the identity provider.", }, - (1917, "AzureNoAuthenticationMethodError"): { + (2003, "AzureNoAuthenticationMethodError"): { "message": "No Azure authentication method found", "remediation": "Check that any authentication method is properly set up for Azure.", }, - (1918, "AzureBrowserAuthNoTenantIDError"): { + (2004, "AzureBrowserAuthNoTenantIDError"): { "message": "Azure browser authentication error: no tenant ID found", "remediation": "To use browser authentication, ensure the tenant ID is properly set.", }, - (1919, "AzureTenantIDNoBrowserAuthError"): { + (2005, "AzureTenantIDNoBrowserAuthError"): { "message": "Azure tenant ID error: browser authentication not found", "remediation": "To use browser authentication, both the tenant ID and browser authentication must be properly set.", }, - (1920, "AzureArgumentTypeValidationError"): { + (2006, "AzureArgumentTypeValidationError"): { "message": "Azure argument type validation error", "remediation": "Check the provided argument types specific to Azure and ensure they meet the required format.", }, - (1921, "AzureSetUpRegionConfigError"): { + (2007, "AzureSetUpRegionConfigError"): { "message": "Azure region configuration setup error", "remediation": "Check the Azure region configuration and ensure it is properly set up.", }, - (1922, "AzureDefaultAzureCredentialError"): { + (2008, "AzureDefaultAzureCredentialError"): { "message": "Error in DefaultAzureCredential", "remediation": "Check that all the attributes are properly set up for the DefaultAzureCredential.", }, - (1923, "AzureInteractiveBrowserCredentialError"): { + (2009, "AzureInteractiveBrowserCredentialError"): { "message": "Error retrieving InteractiveBrowserCredential", "remediation": "Check your browser and ensure that the tenant ID and browser authentication are properly set.", }, - (1924, "AzureHTTPResponseError"): { + (2010, "AzureHTTPResponseError"): { "message": "Error in HTTP response from Azure", "remediation": "", }, - (1925, "AzureCredentialsUnavailableError"): { + (2011, "AzureCredentialsUnavailableError"): { "message": "Error trying to configure Azure credentials because they are unavailable", "remediation": "Check the dictionary and ensure it is properly set up for Azure credentials. TENANT_ID, CLIENT_ID and CLIENT_SECRET are required.", }, - (1926, "AzureGetTokenIdentityError"): { + (2012, "AzureGetTokenIdentityError"): { "message": "Error trying to get token from Azure Identity", "remediation": "Check the Azure Identity and ensure it is properly set up.", }, - (1927, "AzureNotTenantIdButClientIdAndClienSecret"): { + (2013, "AzureNotTenantIdButClientIdAndClienSecretError"): { "message": "The provided credentials are not a tenant ID but a client ID and client secret", "remediation": "Tenant Id, Client Id and Client Secret are required for Azure credentials. Make sure you are using the correct credentials.", }, - (1928, "AzureClientAuthenticationError"): { + (2014, "AzureClientAuthenticationError"): { "message": "Error in client authentication", "remediation": "Check the client authentication and ensure it is properly set up.", }, - (1929, "AzureSetUpSessionError"): { + (2015, "AzureSetUpSessionError"): { "message": "Error setting up session", "remediation": "Check the session setup and ensure it is properly set up.", }, - (1930, "AzureNotValidTenantIdError"): { + (2016, "AzureNotValidTenantIdError"): { "message": "The provided tenant ID is not valid", "remediation": "Check the tenant ID and ensure it is a valid ID.", }, - (1931, "AzureNotValidClientIdError"): { + (2017, "AzureNotValidClientIdError"): { "message": "The provided client ID is not valid", "remediation": "Check the client ID and ensure it is a valid ID.", }, - (1932, "AzureNotValidClientSecretError"): { + (2018, "AzureNotValidClientSecretError"): { "message": "The provided client secret is not valid", "remediation": "Check the client secret and ensure it is a valid secret.", }, - (1933, "AzureConfigCredentialsError"): { + (2019, "AzureConfigCredentialsError"): { "message": "Error in configuration of Azure credentials", "remediation": "Check the configuration of Azure credentials and ensure it is properly set up.", }, - (1934, "AzureClientIdAndClientSecretNotBelongingToTenantIdError"): { + (2020, "AzureClientIdAndClientSecretNotBelongingToTenantIdError"): { "message": "The provided client ID and client secret do not belong to the provided tenant ID", "remediation": "Check the client ID and client secret and ensure they belong to the provided tenant ID.", }, - (1935, "AzureTenantIdAndClientSecretNotBelongingToClientIdError"): { + (2021, "AzureTenantIdAndClientSecretNotBelongingToClientIdError"): { "message": "The provided tenant ID and client secret do not belong to the provided client ID", "remediation": "Check the tenant ID and client secret and ensure they belong to the provided client ID.", }, - (1936, "AzureTenantIdAndClientIdNotBelongingToClientSecretError"): { + (2022, "AzureTenantIdAndClientIdNotBelongingToClientSecretError"): { "message": "The provided tenant ID and client ID do not belong to the provided client secret", "remediation": "Check the tenant ID and client ID and ensure they belong to the provided client secret.", }, - (1937, "AzureInvalidAccountCredentialsError"): { + (2023, "AzureInvalidProviderIdError"): { "message": "The provided provider_id does not match with the available subscriptions", "remediation": "Check the provider_id and ensure it is a valid subscription for the given credentials.", }, @@ -127,166 +128,166 @@ class AzureCredentialsError(AzureBaseException): class AzureEnvironmentVariableError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1914, file=file, original_exception=original_exception, message=message + 2000, file=file, original_exception=original_exception, message=message ) class AzureNoSubscriptionsError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1915, file=file, original_exception=original_exception, message=message + 2001, file=file, original_exception=original_exception, message=message ) class AzureSetUpIdentityError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1916, file=file, original_exception=original_exception, message=message + 2002, file=file, original_exception=original_exception, message=message ) class AzureNoAuthenticationMethodError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1917, file=file, original_exception=original_exception, message=message + 2003, file=file, original_exception=original_exception, message=message ) class AzureBrowserAuthNoTenantIDError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1918, file=file, original_exception=original_exception, message=message + 2004, file=file, original_exception=original_exception, message=message ) class AzureTenantIDNoBrowserAuthError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1919, file=file, original_exception=original_exception, message=message + 2005, file=file, original_exception=original_exception, message=message ) class AzureArgumentTypeValidationError(AzureBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1920, file=file, original_exception=original_exception, message=message + 2006, file=file, original_exception=original_exception, message=message ) class AzureSetUpRegionConfigError(AzureBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1921, file=file, original_exception=original_exception, message=message + 2007, file=file, original_exception=original_exception, message=message ) class AzureDefaultAzureCredentialError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1922, file=file, original_exception=original_exception, message=message + 2008, file=file, original_exception=original_exception, message=message ) class AzureInteractiveBrowserCredentialError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1923, file=file, original_exception=original_exception, message=message + 2009, file=file, original_exception=original_exception, message=message ) class AzureHTTPResponseError(AzureBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1924, file=file, original_exception=original_exception, message=message + 2010, file=file, original_exception=original_exception, message=message ) class AzureCredentialsUnavailableError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1925, file=file, original_exception=original_exception, message=message + 2011, file=file, original_exception=original_exception, message=message ) class AzureGetTokenIdentityError(AzureBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1926, file=file, original_exception=original_exception, message=message + 2012, file=file, original_exception=original_exception, message=message ) -class AzureNotTenantIdButClientIdAndClienSecret(AzureCredentialsError): +class AzureNotTenantIdButClientIdAndClienSecretError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1927, file=file, original_exception=original_exception, message=message + 2013, file=file, original_exception=original_exception, message=message ) class AzureClientAuthenticationError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1928, file=file, original_exception=original_exception, message=message + 2014, file=file, original_exception=original_exception, message=message ) class AzureSetUpSessionError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1929, file=file, original_exception=original_exception, message=message + 2015, file=file, original_exception=original_exception, message=message ) class AzureNotValidTenantIdError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1930, file=file, original_exception=original_exception, message=message + 2016, file=file, original_exception=original_exception, message=message ) class AzureNotValidClientIdError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1931, file=file, original_exception=original_exception, message=message + 2017, file=file, original_exception=original_exception, message=message ) class AzureNotValidClientSecretError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1932, file=file, original_exception=original_exception, message=message + 2018, file=file, original_exception=original_exception, message=message ) class AzureConfigCredentialsError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1933, file=file, original_exception=original_exception, message=message + 2019, file=file, original_exception=original_exception, message=message ) class AzureClientIdAndClientSecretNotBelongingToTenantIdError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1934, file=file, original_exception=original_exception, message=message + 2020, file=file, original_exception=original_exception, message=message ) class AzureTenantIdAndClientSecretNotBelongingToClientIdError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1935, file=file, original_exception=original_exception, message=message + 2021, file=file, original_exception=original_exception, message=message ) class AzureTenantIdAndClientIdNotBelongingToClientSecretError(AzureCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1936, file=file, original_exception=original_exception, message=message + 2022, file=file, original_exception=original_exception, message=message ) -class AzureInvalidAccountCredentialsError(AzureBaseException): +class AzureInvalidProviderIdError(AzureBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1937, file=file, original_exception=original_exception, message=message + 2023, file=file, original_exception=original_exception, message=message ) diff --git a/prowler/providers/gcp/exceptions/exceptions.py b/prowler/providers/gcp/exceptions/exceptions.py index c4dc7883be..03a2281258 100644 --- a/prowler/providers/gcp/exceptions/exceptions.py +++ b/prowler/providers/gcp/exceptions/exceptions.py @@ -1,43 +1,44 @@ from prowler.exceptions.exceptions import ProwlerException +# Exceptions codes from 3000 to 3999 are reserved for GCP exceptions class GCPBaseException(ProwlerException): """Base class for GCP Errors.""" GCP_ERROR_CODES = { - (1925, "GCPCloudResourceManagerAPINotUsedError"): { + (3000, "GCPCloudResourceManagerAPINotUsedError"): { "message": "Cloud Resource Manager API not used", "remediation": "Enable the Cloud Resource Manager API for the project.", }, - (1926, "GCPHTTPError"): { + (3001, "GCPHTTPError"): { "message": "HTTP error", "remediation": "Check the HTTP error and ensure the request is properly formatted.", }, - (1927, "GCPNoAccesibleProjectsError"): { + (3002, "GCPNoAccesibleProjectsError"): { "message": "No Project IDs can be accessed via Google Credentials", "remediation": "Ensure the project is accessible and properly set up.", }, - (1928, "GCPSetUpSessionError"): { + (3003, "GCPSetUpSessionError"): { "message": "Error setting up session", "remediation": "Check the session setup and ensure it is properly set up.", }, - (1929, "GCPGetProjectError"): { + (3004, "GCPGetProjectError"): { "message": "Error getting project", "remediation": "Check the project and ensure it is properly set up.", }, - (1930, "GCPTestConnectionError"): { + (3005, "GCPTestConnectionError"): { "message": "Error testing connection to GCP", "remediation": "Check the connection and ensure it is properly set up.", }, - (1931, "GCPLoadCredentialsFromDictError"): { + (3006, "GCPLoadCredentialsFromDictError"): { "message": "Error loading credentials from dictionary", "remediation": "Check the credentials and ensure they are properly set up. client_id, client_secret and refresh_token are required.", }, - (1932, "GCPStaticCredentialsError"): { + (3007, "GCPStaticCredentialsError"): { "message": "Error loading static credentials", "remediation": "Check the credentials and ensure they are properly set up. client_id, client_secret and refresh_token are required.", }, - (1933, "GCPInvalidAccountCredentials"): { + (3008, "GCPInvalidProviderIdError"): { "message": "Provider does not match with the expected project_id", "remediation": "Check the provider and ensure it matches the expected project_id.", }, @@ -67,61 +68,61 @@ class GCPCredentialsError(GCPBaseException): class GCPCloudResourceManagerAPINotUsedError(GCPBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1925, file=file, original_exception=original_exception, message=message + 3000, file=file, original_exception=original_exception, message=message ) class GCPHTTPError(GCPBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1926, file=file, original_exception=original_exception, message=message + 3001, file=file, original_exception=original_exception, message=message ) class GCPNoAccesibleProjectsError(GCPCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1927, file=file, original_exception=original_exception, message=message + 3002, file=file, original_exception=original_exception, message=message ) class GCPSetUpSessionError(GCPCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1928, file=file, original_exception=original_exception, message=message + 3003, file=file, original_exception=original_exception, message=message ) class GCPGetProjectError(GCPCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1929, file=file, original_exception=original_exception, message=message + 3004, file=file, original_exception=original_exception, message=message ) class GCPTestConnectionError(GCPBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1930, file=file, original_exception=original_exception, message=message + 3005, file=file, original_exception=original_exception, message=message ) class GCPLoadCredentialsFromDictError(GCPCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1931, file=file, original_exception=original_exception, message=message + 3006, file=file, original_exception=original_exception, message=message ) class GCPStaticCredentialsError(GCPCredentialsError): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1932, file=file, original_exception=original_exception, message=message + 3007, file=file, original_exception=original_exception, message=message ) -class GCPInvalidAccountCredentials(GCPBaseException): +class GCPInvalidProviderIdError(GCPBaseException): def __init__(self, file=None, original_exception=None, message=None): super().__init__( - 1933, file=file, original_exception=original_exception, message=message + 3008, file=file, original_exception=original_exception, message=message ) diff --git a/prowler/providers/gcp/gcp_provider.py b/prowler/providers/gcp/gcp_provider.py index d56d281647..0409c43c51 100644 --- a/prowler/providers/gcp/gcp_provider.py +++ b/prowler/providers/gcp/gcp_provider.py @@ -19,7 +19,7 @@ from prowler.providers.gcp.exceptions.exceptions import ( GCPCloudResourceManagerAPINotUsedError, GCPGetProjectError, GCPHTTPError, - GCPInvalidAccountCredentials, + GCPInvalidProviderIdError, GCPLoadCredentialsFromDictError, GCPNoAccesibleProjectsError, GCPSetUpSessionError, @@ -340,12 +340,16 @@ class GcpProvider(Provider): # Errors from setup_session except GCPLoadCredentialsFromDictError as load_credentials_error: - logger.critical(str(load_credentials_error)) + logger.critical( + f"{load_credentials_error.__class__.__name__}[{load_credentials_error.__traceback__.tb_lineno}]: {load_credentials_error}" + ) if raise_on_exception: raise load_credentials_error return Connection(error=load_credentials_error) except GCPSetUpSessionError as setup_session_error: - logger.critical(str(setup_session_error)) + logger.critical( + f"{setup_session_error.__class__.__name__}[{setup_session_error.__traceback__.tb_lineno}]: {setup_session_error}" + ) if raise_on_exception: raise setup_session_error return Connection(error=setup_session_error) @@ -366,8 +370,10 @@ class GcpProvider(Provider): raise http_error return Connection(error=http_error) # Exceptions from validating Provider ID - except GCPInvalidAccountCredentials as not_valid_provider_id_error: - logger.critical(str(not_valid_provider_id_error)) + except GCPInvalidProviderIdError as not_valid_provider_id_error: + logger.critical( + f"{not_valid_provider_id_error.__class__.__name__}[{not_valid_provider_id_error.__traceback__.tb_lineno}]: {not_valid_provider_id_error}" + ) if raise_on_exception: raise not_valid_provider_id_error return Connection(error=not_valid_provider_id_error) @@ -563,7 +569,7 @@ class GcpProvider(Provider): None Raises: - GCPInvalidAccountCredentials if the provider ID does not match with the expected project_id + GCPInvalidProviderIdError if the provider ID does not match with the expected project_id """ available_projects = list( @@ -576,7 +582,7 @@ class GcpProvider(Provider): message="No Project IDs can be accessed via Google Credentials.", ) elif provider_id not in available_projects: - raise GCPInvalidAccountCredentials( + raise GCPInvalidProviderIdError( file=__file__, message="The provider ID does not match with the expected project_id.", ) diff --git a/prowler/providers/kubernetes/exceptions/exceptions.py b/prowler/providers/kubernetes/exceptions/exceptions.py index a8138d64cf..33048764b7 100644 --- a/prowler/providers/kubernetes/exceptions/exceptions.py +++ b/prowler/providers/kubernetes/exceptions/exceptions.py @@ -1,35 +1,36 @@ from prowler.exceptions.exceptions import ProwlerException +# Exceptions codes from 4000 to 4999 are reserved for Kubernetes exceptions class KubernetesBaseException(ProwlerException): """Base class for Kubernetes errors.""" KUBERNETES_ERROR_CODES = { - (1931, "KubernetesCloudResourceManagerAPINotUsedError"): { + (4000, "KubernetesCloudResourceManagerAPINotUsedError"): { "message": "Cloud Resource Manager API is not enabled, blocking access to necessary resources.", "remediation": "Refer to the Kubernetes documentation to enable the Cloud Resource Manager API: https://kubernetes.io/docs/reference/access-authn-authz/rbac/", }, - (1932, "KubernetesSetUpSessionError"): { + (4001, "KubernetesSetUpSessionError"): { "message": "Failed to establish a Kubernetes session, preventing further actions.", "remediation": "Verify your session setup, including credentials and Kubernetes cluster configuration. Refer to this guide for proper setup: https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/", }, - (1933, "KubernetesAPIError"): { + (4002, "KubernetesAPIError"): { "message": "An error occurred while interacting with the Kubernetes API.", "remediation": "Check the API request and ensure it is properly formatted. Refer to the Kubernetes API documentation for guidance: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/", }, - (1934, "KubernetesTimeoutError"): { + (4003, "KubernetesTimeoutError"): { "message": "The request to the Kubernetes API timed out.", "remediation": "Check the network connection and the Kubernetes API server status. For information on troubleshooting timeouts, refer to the Kubernetes documentation: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#-strong-timeout-strong-", }, - (1935, "KubernetesError"): { + (4004, "KubernetesError"): { "message": "An error occurred in the Kubernetes provider.", "remediation": "Check the provider code and configuration to identify the issue. For more information on troubleshooting Kubernetes providers, refer to the Kubernetes documentation: https://kubernetes.io/docs/reference/", }, - (1936, "KubernetesInvalidProviderIdError"): { + (4005, "KubernetesInvalidProviderIdError"): { "message": "The provider ID is invalid.", "remediation": "Check the provider ID and ensure it is correctly formatted. Refer to the Kubernetes documentation for guidance on provider IDs: https://kubernetes.io/docs/reference/access-authn-authz/rbac/", }, - (1937, "KubernetesInvalidKubeConfigFileError"): { + (4006, "KubernetesInvalidKubeConfigFileError"): { "message": "The provided kube-config is invalid.", "remediation": "Review the kube-config and the attached error to get more details. Please, refer to the Kubernetes config documentation: https://kubernetes.io/docs/reference/config-api/kubeconfig.v1/#Config", }, @@ -57,34 +58,34 @@ class KubernetesBaseException(ProwlerException): class KubernetesError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1935, file, original_exception, message) + super().__init__(4004, file, original_exception, message) class KubernetesCloudResourceManagerAPINotUsedError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1931, file, original_exception, message) + super().__init__(4000, file, original_exception, message) class KubernetesSetUpSessionError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1932, file, original_exception, message) + super().__init__(4001, file, original_exception, message) class KubernetesAPIError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1933, file, original_exception, message) + super().__init__(4002, file, original_exception, message) class KubernetesTimeoutError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1934, file, original_exception, message) + super().__init__(4003, file, original_exception, message) class KubernetesInvalidProviderIdError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1936, file, original_exception, message) + super().__init__(4005, file, original_exception, message) class KubernetesInvalidKubeConfigFileError(KubernetesBaseException): def __init__(self, file=None, original_exception=None, message=None): - super().__init__(1937, file, original_exception, message) + super().__init__(4006, file, original_exception, message) diff --git a/tests/providers/aws/aws_provider_test.py b/tests/providers/aws/aws_provider_test.py index 0824babd93..d41a33aeec 100644 --- a/tests/providers/aws/aws_provider_test.py +++ b/tests/providers/aws/aws_provider_test.py @@ -28,8 +28,8 @@ from prowler.providers.aws.config import ( ) from prowler.providers.aws.exceptions.exceptions import ( AWSArgumentTypeValidationError, - AWSIAMRoleARNInvalidResourceType, - AWSInvalidAccountCredentials, + AWSIAMRoleARNInvalidResourceTypeError, + AWSInvalidProviderIdError, AWSNoCredentialsError, ) from prowler.providers.aws.lib.arn.models import ARN @@ -1265,7 +1265,7 @@ aws: ) # No profile to avoid ProfileNotFound error assert exception.type == AWSNoCredentialsError - assert "AWSNoCredentialsError[1904]: No AWS credentials found" in str( + assert "AWSNoCredentialsError[1002]: No AWS credentials found" in str( exception.value ) @@ -1307,7 +1307,7 @@ aws: assert exception.type == AWSArgumentTypeValidationError assert ( exception.value.args[0] - == "[1905] Session Duration must be between 900 and 43200 seconds." + == "[1003] Session Duration must be between 900 and 43200 seconds." ) @mock_aws @@ -1327,7 +1327,7 @@ aws: assert isinstance(connection.error, AWSArgumentTypeValidationError) assert ( connection.error.args[0] - == "[1905] Session Duration must be between 900 and 43200 seconds." + == "[1003] Session Duration must be between 900 and 43200 seconds." ) @mock_aws @@ -1343,7 +1343,7 @@ aws: assert exception.type == AWSArgumentTypeValidationError assert ( exception.value.args[0] - == "[1905] Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores." + == "[1003] Role Session Name must be between 2 and 64 characters and may contain alphanumeric characters, periods, hyphens, and underscores." ) @mock_aws @@ -1351,13 +1351,13 @@ aws: role_name = "test-role" role_arn = f"arn:{AWS_COMMERCIAL_PARTITION}:iam::{AWS_ACCOUNT_NUMBER}:not-role/{role_name}" - with raises(AWSIAMRoleARNInvalidResourceType) as exception: + with raises(AWSIAMRoleARNInvalidResourceTypeError) as exception: AwsProvider.test_connection(role_arn=role_arn) - assert exception.type == AWSIAMRoleARNInvalidResourceType + assert exception.type == AWSIAMRoleARNInvalidResourceTypeError assert ( exception.value.args[0] - == "[1912] AWS IAM Role ARN resource type is invalid" + == "[1010] AWS IAM Role ARN resource type is invalid" ) @mock_aws @@ -1429,13 +1429,13 @@ aws: "provider_id": "111122223333", } - with raises(AWSInvalidAccountCredentials) as exception: + with raises(AWSInvalidProviderIdError) as exception: AwsProvider.test_connection(**session_credentials) - assert exception.type == AWSInvalidAccountCredentials + assert exception.type == AWSInvalidProviderIdError assert ( exception.value.args[0] - == "[1917] The provided AWS credentials belong to a different account" + == "[1015] The provided AWS credentials belong to a different account" ) @mock_aws @@ -1456,12 +1456,12 @@ aws: assert isinstance(connection, Connection) assert not connection.is_connected - assert isinstance(connection.error, AWSInvalidAccountCredentials) + assert isinstance(connection.error, AWSInvalidProviderIdError) assert ( connection.error.message == "The provided AWS credentials belong to a different account" ) - assert connection.error.code == 1917 + assert connection.error.code == 1015 @mock_aws def test_create_sts_session(self): diff --git a/tests/providers/aws/lib/arn/arn_test.py b/tests/providers/aws/lib/arn/arn_test.py index 13645d4ee0..83b999843d 100644 --- a/tests/providers/aws/lib/arn/arn_test.py +++ b/tests/providers/aws/lib/arn/arn_test.py @@ -1,13 +1,13 @@ from pytest import raises from prowler.providers.aws.exceptions.exceptions import ( - AWSIAMRoleARNEmptyResource, - AWSIAMRoleARNInvalidAccountID, - AWSIAMRoleARNInvalidResourceType, - AWSIAMRoleARNMissingFields, - AWSIAMRoleARNPartitionEmpty, - AWSIAMRoleARNRegionNotEmtpy, - AWSIAMRoleARNServiceNotIAMnorSTS, + AWSIAMRoleARNEmptyResourceError, + AWSIAMRoleARNInvalidAccountIDError, + AWSIAMRoleARNInvalidResourceTypeError, + AWSIAMRoleARNMissingFieldsError, + AWSIAMRoleARNPartitionEmptyError, + AWSIAMRoleARNRegionNotEmtpyError, + AWSIAMRoleARNServiceNotIAMnorSTSError, ) from prowler.providers.aws.lib.arn.arn import is_valid_arn, parse_iam_credentials_arn from prowler.providers.aws.lib.arn.models import ARN @@ -327,54 +327,54 @@ class Test_ARN_Parsing: self, ): input_arn = "" - with raises(AWSIAMRoleARNMissingFields) as error: + with raises(AWSIAMRoleARNMissingFieldsError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNMissingFields + assert error._excinfo[0] == AWSIAMRoleARNMissingFieldsError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNRegionNotEmtpy(self): input_arn = "arn:aws:iam:eu-west-1:111111111111:user/prowler" - with raises(AWSIAMRoleARNRegionNotEmtpy) as error: + with raises(AWSIAMRoleARNRegionNotEmtpyError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNRegionNotEmtpy + assert error._excinfo[0] == AWSIAMRoleARNRegionNotEmtpyError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNPartitionEmpty(self): input_arn = "arn::iam::111111111111:user/prowler" - with raises(AWSIAMRoleARNPartitionEmpty) as error: + with raises(AWSIAMRoleARNPartitionEmptyError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNPartitionEmpty + assert error._excinfo[0] == AWSIAMRoleARNPartitionEmptyError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNServiceNotIAMnorSTS(self): input_arn = "arn:aws:s3::111111111111:user/prowler" - with raises(AWSIAMRoleARNServiceNotIAMnorSTS) as error: + with raises(AWSIAMRoleARNServiceNotIAMnorSTSError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNServiceNotIAMnorSTS + assert error._excinfo[0] == AWSIAMRoleARNServiceNotIAMnorSTSError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNInvalidAccountID(self): input_arn = "arn:aws:iam::AWS_ACCOUNT_ID:user/prowler" - with raises(AWSIAMRoleARNInvalidAccountID) as error: + with raises(AWSIAMRoleARNInvalidAccountIDError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNInvalidAccountID + assert error._excinfo[0] == AWSIAMRoleARNInvalidAccountIDError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNInvalidResourceType( self, ): input_arn = "arn:aws:iam::111111111111:account/prowler" - with raises(AWSIAMRoleARNInvalidResourceType) as error: + with raises(AWSIAMRoleARNInvalidResourceTypeError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNInvalidResourceType + assert error._excinfo[0] == AWSIAMRoleARNInvalidResourceTypeError def test_iam_credentials_arn_parsing_raising_AWSIAMRoleARNEmptyResource(self): input_arn = "arn:aws:iam::111111111111:role/" - with raises(AWSIAMRoleARNEmptyResource) as error: + with raises(AWSIAMRoleARNEmptyResourceError) as error: parse_iam_credentials_arn(input_arn) - assert error._excinfo[0] == AWSIAMRoleARNEmptyResource + assert error._excinfo[0] == AWSIAMRoleARNEmptyResourceError def test_is_valid_arn(self): assert is_valid_arn("arn:aws:iam::012345678910:user/test") diff --git a/tests/providers/azure/azure_provider_test.py b/tests/providers/azure/azure_provider_test.py index cfe24049be..8698371330 100644 --- a/tests/providers/azure/azure_provider_test.py +++ b/tests/providers/azure/azure_provider_test.py @@ -15,7 +15,7 @@ from prowler.providers.azure.azure_provider import AzureProvider from prowler.providers.azure.exceptions.exceptions import ( AzureBrowserAuthNoTenantIDError, AzureHTTPResponseError, - AzureInvalidAccountCredentialsError, + AzureInvalidProviderIdError, AzureNoAuthenticationMethodError, AzureTenantIDNoBrowserAuthError, ) @@ -158,7 +158,7 @@ class TestAzureProvider: assert exception.type == AzureBrowserAuthNoTenantIDError assert ( exception.value.args[0] - == "[1918] Azure Tenant ID (--tenant-id) is required for browser authentication mode" + == "[2004] Azure Tenant ID (--tenant-id) is required for browser authentication mode" ) def test_azure_provider_not_browser_auth_but_tenant_id(self): @@ -197,7 +197,7 @@ class TestAzureProvider: assert exception.type == AzureTenantIDNoBrowserAuthError assert ( exception.value.args[0] - == "[1919] Azure Tenant ID (--tenant-id) is required for browser authentication mode" + == "[2005] Azure Tenant ID (--tenant-id) is required for browser authentication mode" ) def test_test_connection_browser_auth(self): @@ -370,9 +370,7 @@ class TestAzureProvider: ) assert test_connection.error is not None - assert isinstance( - test_connection.error, AzureInvalidAccountCredentialsError - ) + assert isinstance(test_connection.error, AzureInvalidProviderIdError) assert ( "The provided credentials are not valid for the specified Azure subscription." in test_connection.error.args[0] @@ -390,7 +388,7 @@ class TestAzureProvider: assert exception.type == AzureHTTPResponseError assert ( exception.value.args[0] - == f"[1924] Error in HTTP response from Azure - Authentication failed: Unable to get authority configuration for https://login.microsoftonline.com/{tenant_id}. Authority would typically be in a format of https://login.microsoftonline.com/your_tenant or https://tenant_name.ciamlogin.com or https://tenant_name.b2clogin.com/tenant.onmicrosoft.com/policy. Also please double check your tenant name or GUID is correct." + == f"[2010] Error in HTTP response from Azure - Authentication failed: Unable to get authority configuration for https://login.microsoftonline.com/{tenant_id}. Authority would typically be in a format of https://login.microsoftonline.com/your_tenant or https://tenant_name.ciamlogin.com or https://tenant_name.b2clogin.com/tenant.onmicrosoft.com/policy. Also please double check your tenant name or GUID is correct." ) def test_test_connection_without_any_method(self): @@ -399,7 +397,7 @@ class TestAzureProvider: assert exception.type == AzureNoAuthenticationMethodError assert ( - "[1917] Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]" + "[2003] Azure provider requires at least one authentication method set: [--az-cli-auth | --sp-env-auth | --browser-auth | --managed-identity-auth]" in exception.value.args[0] ) @@ -424,7 +422,7 @@ class TestAzureProvider: assert exception.type == AzureHTTPResponseError assert ( exception.value.args[0] - == "[1924] Error in HTTP response from Azure - Simulated HttpResponseError" + == "[2010] Error in HTTP response from Azure - Simulated HttpResponseError" ) def test_test_connection_with_exception(self): diff --git a/tests/providers/gcp/gcp_provider_test.py b/tests/providers/gcp/gcp_provider_test.py index e84ab6fba5..b160dcb64a 100644 --- a/tests/providers/gcp/gcp_provider_test.py +++ b/tests/providers/gcp/gcp_provider_test.py @@ -13,7 +13,7 @@ from prowler.config.config import ( ) from prowler.providers.common.models import Connection from prowler.providers.gcp.exceptions.exceptions import ( - GCPInvalidAccountCredentials, + GCPInvalidProviderIdError, GCPTestConnectionError, ) from prowler.providers.gcp.gcp_provider import GcpProvider @@ -593,7 +593,7 @@ class TestGCPProvider: "prowler.providers.gcp.gcp_provider.GcpProvider.validate_project_id" ) as mock_validate_project_id: - mock_validate_project_id.side_effect = GCPInvalidAccountCredentials( + mock_validate_project_id.side_effect = GCPInvalidProviderIdError( "Invalid project ID" ) @@ -605,4 +605,4 @@ class TestGCPProvider: provider_id="test-invalid-project", ) - assert e.type == GCPInvalidAccountCredentials + assert e.type == GCPInvalidProviderIdError