import pytest

from prowler.providers.aws.services.iam.lib.policy import (
    _get_patterns_from_standard_value,
    check_admin_access,
    check_full_service_access,
    get_effective_actions,
    has_codebuild_trusted_principal,
    has_public_principal,
    has_restrictive_source_arn_condition,
    is_codebuild_using_allowed_github_org,
    is_condition_block_restrictive,
    is_condition_block_restrictive_organization,
    is_condition_block_restrictive_sns_endpoint,
    is_condition_restricting_from_private_ip,
    is_condition_restricting_to_trusted_ips,
    is_policy_public,
    policy_allows_marketplace_subscribe_on_all_resources,
)

TRUSTED_AWS_ACCOUNT_NUMBER = "123456789012"
NON_TRUSTED_AWS_ACCOUNT_NUMBER = "111222333444"
TRUSTED_AWS_ACCOUNT_NUMBER_LIST = ["123456789012", "123456789013", "123456789014"]

TRUSTED_ORGANIZATION_ID = "o-123456789012"
NON_TRUSTED_ORGANIZATION_ID = "o-111222333444"

ALL_ORGS = "*"


class Test_Policy:
    def test_get_patterns_from_standard_value_string(self):
        """Test _get_patterns_from_standard_value with a string input"""
        result = _get_patterns_from_standard_value("s3:GetObject")
        assert result == {"s3:GetObject"}

        result = _get_patterns_from_standard_value("")
        assert result == {""}

    def test_get_patterns_from_standard_value_list(self):
        """Test _get_patterns_from_standard_value with a list input"""
        result = _get_patterns_from_standard_value(["s3:GetObject", "s3:PutObject"])
        assert result == {"s3:GetObject", "s3:PutObject"}

        result = _get_patterns_from_standard_value([])
        assert result == set()

        result = _get_patterns_from_standard_value(["s3:GetObject", 123, None])
        assert result == {"s3:GetObject"}

    def test_get_patterns_from_standard_value_invalid_input(self):
        """Test _get_patterns_from_standard_value with invalid inputs"""
        result = _get_patterns_from_standard_value(None)
        assert result == set()

        result = _get_patterns_from_standard_value(123)
        assert result == set()

    def test_get_effective_actions_empty_policy(self):
        """Test get_effective_actions with an empty policy"""
        result = get_effective_actions({})
        assert result == set()

        result = get_effective_actions({"Version": "2012-10-17"})
        assert result == set()

    def test_get_effective_actions_simple_allow(self):
        """Test get_effective_actions with a simple Allow statement"""
        policy = {
            "Version": "2012-10-17",
            "Statement": {"Effect": "Allow", "Action": "s3:GetObject"},
        }
        result = get_effective_actions(policy)
        assert result == {"s3:GetObject"}

    def test_get_effective_actions_simple_deny(self):
        """Test get_effective_actions with a simple Deny statement"""
        policy = {
            "Version": "2012-10-17",
            "Statement": {"Effect": "Deny", "Action": "s3:GetObject"},
        }
        result = get_effective_actions(policy)
        assert result == set()

    def test_get_effective_actions_allow_and_deny(self):
        """Test get_effective_actions with both Allow and Deny statements"""
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {"Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"]},
                {"Effect": "Deny", "Action": "s3:GetObject"},
            ],
        }
        result = get_effective_actions(policy)
        assert result == {"s3:PutObject"}

    def test_get_effective_actions_with_not_action(self):
        """Test get_effective_actions with NotAction statements"""
        policy = {
            "Version": "2012-10-17",
            "Statement": {"Effect": "Allow", "NotAction": "s3:GetObject"},
        }
        result = get_effective_actions(policy)
        assert "s3:GetObject" not in result
        assert "s3:PutObject" in result

    def test_get_effective_actions_with_wildcards(self):
        """Test get_effective_actions with wildcard actions"""
        policy = {
            "Version": "2012-10-17",
            "Statement": {"Effect": "Allow", "Action": "s3:*"},
        }
        result = get_effective_actions(policy)
        assert "s3:GetObject" in result
        assert "s3:PutObject" in result
        assert "s3:ListBucket" in result

    def test_get_effective_actions_with_invalid_effect(self):
        """Test get_effective_actions with invalid Effect value"""
        policy = {
            "Version": "2012-10-17",
            "Statement": {"Effect": "Invalid", "Action": "s3:GetObject"},
        }
        result = get_effective_actions(policy)
        assert result == set()

    def test_get_effective_actions_with_multiple_statements(self):
        """Test get_effective_actions with multiple statements"""
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {"Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"]},
                {"Effect": "Allow", "Action": "s3:ListBucket"},
                {"Effect": "Deny", "Action": "s3:PutObject"},
            ],
        }
        result = get_effective_actions(policy)
        assert result == {"s3:GetObject", "s3:ListBucket"}
        assert "s3:PutObject" not in result

    def test_policy_allows_marketplace_subscribe_conditional_deny_does_not_cancel(self):
        """Conditional deny should not globally cancel a wildcard marketplace allow."""
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "aws-marketplace:Subscribe",
                    "Resource": "*",
                },
                {
                    "Effect": "Deny",
                    "Action": "aws-marketplace:Subscribe",
                    "Resource": "*",
                    "Condition": {"StringEquals": {"aws:RequestedRegion": "us-east-1"}},
                },
            ],
        }

        assert policy_allows_marketplace_subscribe_on_all_resources(policy)

    def test_policy_allows_marketplace_subscribe_unconditional_deny_cancels(self):
        """Unconditional deny on Resource:* should cancel the wildcard marketplace allow."""
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "aws-marketplace:Subscribe",
                    "Resource": "*",
                },
                {
                    "Effect": "Deny",
                    "Action": "aws-marketplace:Subscribe",
                    "Resource": "*",
                },
            ],
        }

        assert not policy_allows_marketplace_subscribe_on_all_resources(policy)

    # Test lowercase context key name --> aws
    def test_condition_parser_string_equals_aws_SourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "aws:SourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceAccount_list(self):
        condition_statement = {
            "StringLike": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceAccount_str(self):
        condition_statement = {
            "StringLike": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceOwner_str(self):
        condition_statement = {
            "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceOwner_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceOwner_list(self):
        condition_statement = {
            "StringEquals": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceOwner_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "aws:SourceOwner": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceOwner_list(self):
        condition_statement = {
            "StringLike": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceOwner_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceOwner": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceOwner_str(self):
        condition_statement = {
            "StringLike": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceOwner_str_not_valid(self):
        condition_statement = {
            "StringLike": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_s3_ResourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"s3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_s3_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "s3:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_s3_ResourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"s3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_s3_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"s3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_PrincipalAccount_list(self):
        condition_statement = {
            "StringEquals": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_PrincipalAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "aws:PrincipalAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_PrincipalAccount_str(self):
        condition_statement = {
            "StringEquals": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_PrincipalAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceArn_str(self):
        condition_statement = {
            "StringEquals": {
                "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_SourceArn_str_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalAccount_list(self):
        condition_statement = {
            "StringLike": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:PrincipalAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalAccount_str(self):
        condition_statement = {
            "StringLike": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_SourceArn_list(self):
        condition_statement = {
            "ArnLike": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_SourceArn_list_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_SourceArn_str(self):
        condition_statement = {
            "ArnLike": {
                "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_SourceArn_str_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_PrincipalArn_list(self):
        condition_statement = {
            "ArnLike": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_PrincipalArn_str(self):
        condition_statement = {
            "ArnLike": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_aws_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_SourceArn_list(self):
        condition_statement = {
            "ArnEquals": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_SourceArn_list_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_SourceArn_str(self):
        condition_statement = {
            "ArnEquals": {
                "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_SourceArn_str_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_PrincipalArn_list(self):
        condition_statement = {
            "ArnEquals": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_PrincipalArn_str(self):
        condition_statement = {
            "ArnEquals": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_aws_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceArn_list(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceArn_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceArn_str(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_SourceArn_str_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalArn_list(self):
        condition_statement = {
            "StringLike": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalArn_str(self):
        condition_statement = {
            "StringLike": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_ResourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "aws:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_ResourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_ResourceAccount_list(self):
        condition_statement = {
            "StringLike": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "aws:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_ResourceAccount_str(self):
        condition_statement = {
            "StringLike": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_aws_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    # Test uppercase context key name --> AWS
    def test_condition_parser_string_equals_AWS_SourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "AWS:SourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceAccount_list(self):
        condition_statement = {
            "StringLike": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceAccount_str(self):
        condition_statement = {
            "StringLike": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceOwner_str(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceOwner_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceOwner_list(self):
        condition_statement = {
            "StringEquals": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_SourceOwner_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "AWS:SourceOwner": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceOwner_list(self):
        condition_statement = {
            "StringLike": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceOwner_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceOwner": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceOwner_str(self):
        condition_statement = {
            "StringLike": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceOwner_str_not_valid(self):
        condition_statement = {
            "StringLike": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_S3_ResourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"S3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_S3_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "S3:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_S3_ResourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"S3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_S3_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"S3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_PrincipalAccount_list(self):
        condition_statement = {
            "StringEquals": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_PrincipalAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "AWS:PrincipalAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_PrincipalAccount_str(self):
        condition_statement = {
            "StringEquals": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_PrincipalAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalAccount_list(self):
        condition_statement = {
            "StringLike": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:PrincipalAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalAccount_str(self):
        condition_statement = {
            "StringLike": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_SourceArn_list(self):
        condition_statement = {
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_SourceArn_list_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_SourceArn_str(self):
        condition_statement = {
            "ArnLike": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_SourceArn_str_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_PrincipalArn_list(self):
        condition_statement = {
            "ArnLike": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_PrincipalArn_str(self):
        condition_statement = {
            "ArnLike": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_like_AWS_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "ArnLike": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_SourceArn_list(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_SourceArn_list_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_SourceArn_str(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_SourceArn_str_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_PrincipalArn_list(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_PrincipalArn_str(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_arn_equals_AWS_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "ArnEquals": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceArn_list(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceArn_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceArn_str(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_SourceArn_str_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalArn_list(self):
        condition_statement = {
            "StringLike": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
                ]
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalArn_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:PrincipalArn": [
                    f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                    f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test",
                ]
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalArn_str(self):
        condition_statement = {
            "StringLike": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_PrincipalArn_str_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test"
            }
        }

        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_ResourceAccount_list(self):
        condition_statement = {
            "StringEquals": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_ResourceAccount_str(self):
        condition_statement = {
            "StringEquals": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_AWS_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_ResourceAccount_list(self):
        condition_statement = {
            "StringLike": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_ResourceAccount_list_not_valid(self):
        condition_statement = {
            "StringLike": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_ResourceAccount_str(self):
        condition_statement = {
            "StringLike": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_AWS_ResourceAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_aws_CalledVia_str(self):
        condition_statement = {
            "StringEquals": {"aws:CalledVia": "cloudformation.amazonaws.com"}
        }
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_string_equals_aws_CalledViaFirst_str(self):
        condition_statement = {
            "StringEquals": {"aws:CalledViaFirst": "cloudformation.amazonaws.com"}
        }
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_string_equals_aws_CalledViaLast_str(self):
        condition_statement = {
            "StringEquals": {"aws:CalledViaLast": "glue.amazonaws.com"}
        }
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_string_like_aws_CalledVia_str(self):
        condition_statement = {"StringLike": {"aws:CalledVia": "*.amazonaws.com"}}
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_string_equals_kms_CallerAccount_str(self):
        condition_statement = {
            "StringEquals": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_kms_CallerAccount_str_not_valid(self):
        condition_statement = {
            "StringEquals": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_kms_CallerAccount_list(self):
        condition_statement = {
            "StringEquals": {"kms:CallerAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_kms_CallerAccount_list_not_valid(self):
        condition_statement = {
            "StringEquals": {
                "kms:CallerAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            }
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_equals_kms_ViaService_str(self):
        condition_statement = {
            "StringEquals": {"kms:ViaService": "glue.eu-central-1.amazonaws.com"}
        }
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_string_like_kms_CallerAccount_str(self):
        condition_statement = {
            "StringLike": {"kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_kms_CallerAccount_str_not_valid(self):
        condition_statement = {
            "StringLike": {"kms:CallerAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER}
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_string_like_kms_ViaService_str(self):
        condition_statement = {"StringLike": {"kms:ViaService": "glue.*.amazonaws.com"}}
        assert is_condition_block_restrictive(
            condition_statement,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=True,
        )

    def test_condition_parser_two_lists_unrestrictive(self):
        condition_statement = {
            "StringLike": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            },
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            },
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_two_lists_both_restrictive(self):
        condition_statement = {
            "StringLike": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            },
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            },
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_two_lists_first_restrictive(self):
        condition_statement = {
            "StringLike": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            },
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                    f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            },
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_two_lists_second_restrictive(self):
        condition_statement = {
            "StringLike": {
                "AWS:ResourceAccount": [
                    TRUSTED_AWS_ACCOUNT_NUMBER,
                    NON_TRUSTED_AWS_ACCOUNT_NUMBER,
                ]
            },
            "ArnLike": {
                "AWS:SourceArn": [
                    f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*",
                ]
            },
        }
        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_condition_parser_allowing_cross_account_with_invalid_block(self):
        condition_statement = {
            "StringLike": {
                "s3:prefix": [
                    "home/",
                ]
            },
        }
        assert not is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True
        )

    def test_condition_parser_string_equals_vpc(self):
        condition_statement = {"StringEquals": {"aws:SourceVpc": "vpc-123456"}}

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True
        )

    def test_condition_parser_string_equals_vpc_list(self):
        condition_statement = {"StringEquals": {"aws:sourcevpc": ["vpc-123456"]}}

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True
        )

    def test_condition_parser_string_equals_vpc_list_not_valid(self):
        condition_statement = {
            "StringEquals": {"aws:SourceVpc": ["vpc-123456", "vpc-654321"]}
        }

        assert is_condition_block_restrictive(
            condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True
        )

    def test_condition_parser_string_equals_aws_PrincipalOrgID_list(self):
        condition_statement = {
            "StringEquals": {"aws:PrincipalOrgID": [TRUSTED_ORGANIZATION_ID]}
        }
        assert is_condition_block_restrictive_organization(condition_statement)

    def test_condition_parser_string_equals_aws_PrincipalOrgID_list_multiple_items(
        self,
    ):
        condition_statement = {
            "StringEquals": {
                "aws:PrincipalOrgID": [
                    TRUSTED_ORGANIZATION_ID,
                    NON_TRUSTED_ORGANIZATION_ID,
                ]
            }
        }
        assert is_condition_block_restrictive_organization(condition_statement)

    def test_condition_parser_string_equals_aws_PrincipalOrgID_str(self):
        condition_statement = {
            "StringEquals": {"aws:PrincipalOrgID": TRUSTED_ORGANIZATION_ID}
        }
        assert is_condition_block_restrictive_organization(condition_statement)

    def test_condition_parser_string_equals_aws_All_Orgs_list_multiple_items(
        self,
    ):
        condition_statement = {
            "StringEquals": {
                "aws:PrincipalOrgID": [
                    TRUSTED_ORGANIZATION_ID,
                    ALL_ORGS,
                ]
            }
        }
        assert not is_condition_block_restrictive_organization(condition_statement)

    def test_condition_parser_string_equals_aws_All_Orgs_str(self):
        condition_statement = {"StringEquals": {"aws:PrincipalOrgID": ALL_ORGS}}
        assert not is_condition_block_restrictive_organization(condition_statement)

    @pytest.mark.parametrize(
        "condition_value,expected",
        [
            ("*@example.com", True),
            ("https://events.pagerduty.com/integration/<api-key>/enqueue", True),
            (
                "arn:aws:sns:eu-west-2:123456789012:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7",
                True,
            ),
            ("*@*.com", False),
            ("*@*", False),
            ("*@example.*", False),
            ("https://events.pagerduty.com/integration/*/enqueue", False),
            ("arn:aws:sns:eu-west-2:123456789012:example-topic:*", False),
            (
                "arn:aws:sns:eu-west-2:*:example-topic:995be20c-a7e3-44ca-8c18-77cb263d15e7",
                False,
            ),
        ],
    )
    def test_condition_parser_string_equals_sns_endpoint_str(
        self, condition_value: str, expected: bool
    ):
        condition_statement = {"StringEquals": {"SNS:Endpoint": condition_value}}
        assert (
            is_condition_block_restrictive_sns_endpoint(condition_statement) == expected
        )

        condition_statement = {"StringLike": {"SNS:Endpoint": condition_value}}
        assert (
            is_condition_block_restrictive_sns_endpoint(condition_statement) == expected
        )

    def test_policy_allows_cross_account_access_with_root_and_wildcard_principal(self):
        policy_allow_root_and_wildcard_principal = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER}:root", "*"]
                    },
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert is_policy_public(
            policy_allow_root_and_wildcard_principal,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=False,
        )

    def test_policy_does_not_allow_cross_account_access_with_specific_root_principal(
        self,
    ):
        policy_allow_specific_root_principal = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER}:root"]
                    },
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert not is_policy_public(
            policy_allow_specific_root_principal,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=False,
        )

    def test_policy_does_not_allow_cross_account_access_with_deny_effect(self):
        policy_deny_specific_root_principal = {
            "Statement": [
                {
                    "Effect": "Deny",
                    "Principal": {
                        "AWS": [f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER}:root"]
                    },
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert not is_policy_public(
            policy_deny_specific_root_principal,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=False,
        )

    def test_cross_account_access_trusted_account_list(self):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER_LIST[0]}:root"
                    },
                    "Action": "*",
                    "Resource": "*",
                }
            ]
        }
        assert not is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=False,
            trusted_account_ids=TRUSTED_AWS_ACCOUNT_NUMBER_LIST,
        )

    def test_cross_account_access_with_principal_list_trusted_account_list(self):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [
                            f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER_LIST[0]}:root",
                            f"arn:aws:iam::{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:root",
                        ]
                    },
                    "Action": "*",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            is_cross_account_allowed=False,
            trusted_account_ids=TRUSTED_AWS_ACCOUNT_NUMBER_LIST,
        )

    def test_policy_allows_public_access_with_wildcard_principal(self):
        policy_allow_wildcard_principal = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert is_policy_public(
            policy_allow_wildcard_principal,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            not_allowed_actions=["s3:*"],
        )

    def test_policy_allows_public_access_with_aws_wildcard_principal(self):
        policy_allow_aws_wildcard_principal = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert is_policy_public(
            policy_allow_aws_wildcard_principal,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            not_allowed_actions=["s3:*"],
        )

    def test_policy_does_not_allow_public_access_with_specific_aws_principal(self):
        policy_allow_specific_aws_principal = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER}:root"
                    },
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                }
            ]
        }
        assert not is_policy_public(
            policy_allow_specific_aws_principal, TRUSTED_AWS_ACCOUNT_NUMBER
        )

    def test_policy_does_not_allow_public_access_with_condition(self):
        policy_allow_aws_wildcard_principal_with_condition = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket/*",
                    "Condition": {"IpAddress": {"aws:SourceIp": "192.0.2.0/24"}},
                }
            ]
        }
        assert not is_policy_public(
            policy_allow_aws_wildcard_principal_with_condition,
            TRUSTED_AWS_ACCOUNT_NUMBER,
        )

    def test_policy_allows_full_service_access_with_wildcard_action_and_resource(self):
        policy_allow_wildcard_action_and_resource = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "s3:*",
                    "Resource": "*",
                }
            ]
        }
        assert check_full_service_access(
            "s3", policy_allow_wildcard_action_and_resource
        )

    def test_policy_allows_full_service_access_with_wildcard_action_and_resource_using_unicode(
        self,
    ):
        policy_allow_wildcard_action_and_resource = {
            "Statement": [
                {
                    "Effect": "\u0041llow",
                    "Action": "\u00733:*",
                    "Resource": "*",
                }
            ]
        }
        assert check_full_service_access(
            "s3", policy_allow_wildcard_action_and_resource
        )

    def test_policy_allows_full_service_access_with_wildcard_action_and_resource_using_double_start(
        self,
    ):
        policy_allow_wildcard_action_and_resource = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "s3:**",
                    "Resource": "*",
                }
            ]
        }
        assert check_full_service_access(
            "s3", policy_allow_wildcard_action_and_resource
        )

    def test_policy_does_not_allow_full_service_access_with_specific_get_action(self):
        policy_allow_specific_get_action = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "s3:Get*",
                    "Resource": "*",
                }
            ]
        }
        assert not check_full_service_access("s3", policy_allow_specific_get_action)

    def test_policy_does_not_allow_full_service_access_with_bucket_wildcard_resource(
        self,
    ):
        policy_allow_bucket_wildcard_resource = {
            "Statement": {
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "arn:aws:s3:::example_bucket/*",
            }
        }
        assert not check_full_service_access(
            "s3", policy_allow_bucket_wildcard_resource
        )

    def test_policy_does_not_allow_full_service_access_with_specific_bucket(self):
        policy_allow_specific_bucket = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": "s3:*",
                    "Resource": "arn:aws:s3:::example_bucket",
                }
            ]
        }
        assert not check_full_service_access("s3", policy_allow_specific_bucket)

    def test_policy_allows_full_service_access_with_not_action_excluding_other_service(
        self,
    ):
        policy_allow_not_action_excluding_other_service = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "NotAction": "ec2:*",
                    "Resource": "*",
                }
            ]
        }
        assert check_full_service_access(
            "s3", policy_allow_not_action_excluding_other_service
        )

    def test_policy_allows_full_service_access_with_invalid_service_as_not_action(
        self,
    ):
        policy_allow_not_action_excluding_other_service = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "NotAction": "prowler:check",
                    "Resource": "*",
                }
            ]
        }
        assert check_full_service_access(
            "s3", policy_allow_not_action_excluding_other_service
        )

    def test_policy_does_not_allow_full_service_access_with_not_action_including_service(
        self,
    ):
        policy_not_action_including_service = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "NotAction": "s3:*",
                    "Resource": "*",
                }
            ]
        }
        assert not check_full_service_access("s3", policy_not_action_including_service)

    def test_is_condition_restricting_from_private_ip_no_condition(self):
        assert not is_condition_restricting_from_private_ip({})

    def test_is_condition_restricting_from_private_ip(self):
        condition_from_private_ip = {
            "IpAddress": {"aws:SourceIp": "10.0.0.22"},
        }
        assert is_condition_restricting_from_private_ip(condition_from_private_ip)

    def test_is_condition_restricting_from_public_ip(self):
        condition_not_from_private_ip = {
            "IpAddress": {"aws:SourceIp": "1.2.3.4"},
        }
        assert not is_condition_restricting_from_private_ip(
            condition_not_from_private_ip
        )

    def test_is_condition_restricting_from_private_ipv6(self):
        condition_from_private_ipv6 = {
            "IpAddress": {"aws:SourceIp": "fd00::1"},
        }
        assert is_condition_restricting_from_private_ip(condition_from_private_ipv6)

    def test_is_condition_restricting_from_public_ipv6(self):
        condition_not_from_private_ipv6 = {
            "IpAddress": {"aws:SourceIp": "2001:0db8::1"},
        }
        assert is_condition_restricting_from_private_ip(condition_not_from_private_ipv6)

    def test_is_condition_restricting_from_private_ip_network(self):
        condition_from_private_ip_network = {
            "IpAddress": {"aws:SourceIp": "10.0.0.0/24"},
        }
        assert is_condition_restricting_from_private_ip(
            condition_from_private_ip_network
        )

    def test_is_condition_restricting_from_public_ip_network(self):
        condition_from_public_ip_network = {
            "IpAddress": {"aws:SourceIp": "1.2.3.0/24"},
        }

        assert not is_condition_restricting_from_private_ip(
            condition_from_public_ip_network
        )

    def test_is_condition_restricting_from_private_ipv6_network(self):
        condition_from_private_ipv6_network = {
            "IpAddress": {"aws:SourceIp": "fd00::/8"},
        }
        assert is_condition_restricting_from_private_ip(
            condition_from_private_ipv6_network
        )

    def test_is_condition_restricting_from_private_ip_array(self):
        condition_from_private_ip_array = {
            "IpAddress": {"aws:SourceIp": ["10.0.0.22", "192.168.1.1"]},
        }
        assert is_condition_restricting_from_private_ip(condition_from_private_ip_array)

    def test_is_condition_restricting_from_private_ipv6_array(self):
        condition_from_private_ipv6_array = {
            "IpAddress": {"aws:SourceIp": ["fd00::1", "fe80::1"]},
        }
        assert is_condition_restricting_from_private_ip(
            condition_from_private_ipv6_array
        )

    def test_is_condition_restricting_from_mixed_ip_array(self):
        condition_from_mixed_ip_array = {
            "IpAddress": {"aws:SourceIp": ["10.0.0.22", "2001:0db8::1"]},
        }
        assert is_condition_restricting_from_private_ip(condition_from_mixed_ip_array)

    def test_is_condition_restricting_from_mixed_ip_array_not_private(self):
        condition_from_mixed_ip_array_not_private = {
            "IpAddress": {"aws:SourceIp": ["1.2.3.4", "2001:0db8::1"]},
        }
        assert not is_condition_restricting_from_private_ip(
            condition_from_mixed_ip_array_not_private
        )

    def test_is_condition_restricting_from_private_ip_from_invalid_ip(self):
        condition_from_invalid_ip = {
            "IpAddress": {"aws:SourceIp": "256.256.256.256"},
        }
        assert not is_condition_restricting_from_private_ip(condition_from_invalid_ip)

    def test_is_condition_restricting_to_trusted_ips_no_trusted_ips(self):
        condition = {"IpAddress": {"aws:SourceIp": "1.2.3.4"}}
        assert not is_condition_restricting_to_trusted_ips(condition)

    def test_is_condition_restricting_to_trusted_ips_empty_trusted_ips(self):
        condition = {"IpAddress": {"aws:SourceIp": "1.2.3.4"}}
        assert not is_condition_restricting_to_trusted_ips(condition, [])

    def test_is_condition_restricting_to_trusted_ips_matching(self):
        condition = {"IpAddress": {"aws:SourceIp": "1.2.3.4"}}
        assert is_condition_restricting_to_trusted_ips(condition, ["1.2.3.4"])

    def test_is_condition_restricting_to_trusted_ips_not_matching(self):
        condition = {"IpAddress": {"aws:SourceIp": "5.6.7.8"}}
        assert not is_condition_restricting_to_trusted_ips(condition, ["1.2.3.4"])

    def test_is_condition_restricting_to_trusted_ips_wildcard(self):
        condition = {"IpAddress": {"aws:SourceIp": "*"}}
        assert not is_condition_restricting_to_trusted_ips(condition, ["1.2.3.4"])

    def test_is_condition_restricting_to_trusted_ips_open_cidr(self):
        condition = {"IpAddress": {"aws:SourceIp": "0.0.0.0/0"}}
        assert not is_condition_restricting_to_trusted_ips(condition, ["1.2.3.4"])

    def test_is_condition_restricting_to_trusted_ips_multiple_ips_all_trusted(self):
        condition = {"IpAddress": {"aws:SourceIp": ["1.2.3.4", "5.6.7.8"]}}
        assert is_condition_restricting_to_trusted_ips(
            condition, ["1.2.3.4", "5.6.7.8"]
        )

    def test_is_condition_restricting_to_trusted_ips_multiple_ips_partial_trusted(self):
        condition = {"IpAddress": {"aws:SourceIp": ["1.2.3.4", "9.9.9.9"]}}
        assert not is_condition_restricting_to_trusted_ips(
            condition, ["1.2.3.4", "5.6.7.8"]
        )

    def test_is_condition_restricting_to_trusted_ips_cidr_range(self):
        condition = {"IpAddress": {"aws:SourceIp": "10.0.0.0/8"}}
        assert is_condition_restricting_to_trusted_ips(condition, ["10.0.0.0/8"])

    def test_is_condition_restricting_to_trusted_ips_no_condition(self):
        assert not is_condition_restricting_to_trusted_ips({}, ["1.2.3.4"])

    def test_is_policy_public_(self):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            not_allowed_actions=["elasticfilesystem:ClientMount"],
        )

    def test_is_policy_public_with_principal_dict(self):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            not_allowed_actions=["elasticfilesystem:ClientMount"],
        )

    def test_is_policy_public_with_secure_conditions_and_allowed_conditions(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                    "Condition": {
                        "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"},
                        "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER},
                    },
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_with_secure_conditions_and_allowed_conditions_nested(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                    "Condition": {
                        "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"},
                        "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER},
                        "StringEqualsIfExists": {
                            "aws:SourceVpce": "vpce-1234567890abcdef0"
                        },
                    },
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_with_secure_conditions_and_allowed_conditions_nested_dict(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                    "Condition": {
                        "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"},
                        "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER},
                        "StringEqualsIfExists": {
                            "aws:SourceVpce": {
                                "vpce-1234567890abcdef0": "vpce-1234567890abcdef0"
                            }
                        },
                    },
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_with_secure_conditions_and_allowed_conditions_nested_dict_key(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:ClientMount",
                    "Resource": "*",
                    "Condition": {
                        "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"},
                        "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER},
                        "StringEqualsIfExists": {
                            "aws:SourceVpce": {
                                "vpce-1234567890abcdef0": "vpce-1234567890abcdef0"
                            }
                        },
                    },
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_with_action_wildcard(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "elasticfilesystem:*",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_allowing_all_actions(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "*",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_allowing_other_account(self):
        policy = {
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": f"arn:aws:iam::{TRUSTED_AWS_ACCOUNT_NUMBER}:root"
                    },
                    "Action": "*",
                    "Resource": "*",
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_secrets_manager(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "secretsmanager.amazonaws.com"},
                    "Action": "lambda:GetFunction",
                    "Resource": "*",
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_eks(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "eks.amazonaws.com"},
                    "Action": "lambda:GetFunction",
                    "Resource": "*",
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_cross_cross_service_confused_deputy(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "ec2.amazonaws.com"},
                    "Action": "lambda:InvokeFunction",
                    "Resource": "*",
                }
            ]
        }
        assert is_policy_public(
            policy, TRUSTED_AWS_ACCOUNT_NUMBER, check_cross_service_confused_deputy=True
        )

    def test_is_policy_public_cross_cross_service_confused_deputy_ignored(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "ec2.amazonaws.com"},
                    "Action": "lambda:InvokeFunction",
                    "Resource": "*",
                }
            ]
        }
        assert not is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            check_cross_service_confused_deputy=False,
        )

    def test_is_policy_public_alexa_condition(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "alexa-connectedhome.amazon.com"},
                    "Action": "lambda:GetFunction",
                    "Resource": "*",
                    "Condition": {"StringEquals": {"lambda:EventSourceToken": "test"}},
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_private_org_s3_bucket(
        self,
    ):
        policy = {
            "Statement": [
                {
                    "Sid": "test",
                    "Effect": "Allow",
                    "Principal": {"Service": "personalize.amazonaws.com"},
                    "Action": "*",
                    "Resource": "*",
                    "Condition": {"StringLike": {"aws:SourceOrgID": "o-123456"}},
                }
            ]
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_ip(
        self,
    ):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": ["*"],
                    "Condition": {"IpAddress": {"aws:SourceIp": ["0.0.0.0/0"]}},
                    "Resource": "*",
                }
            ],
        }
        assert is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_with_trusted_ips(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": ["*"],
                    "Condition": {
                        "IpAddress": {"aws:SourceIp": ["1.2.3.4", "5.6.7.8"]}
                    },
                    "Resource": "*",
                }
            ],
        }
        assert not is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            trusted_ips=["1.2.3.4", "5.6.7.8"],
        )

    def test_is_policy_public_with_trusted_ips_partial_match(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": ["*"],
                    "Condition": {
                        "IpAddress": {"aws:SourceIp": ["1.2.3.4", "9.9.9.9"]}
                    },
                    "Resource": "*",
                }
            ],
        }
        assert is_policy_public(
            policy,
            TRUSTED_AWS_ACCOUNT_NUMBER,
            trusted_ips=["1.2.3.4", "5.6.7.8"],
        )

    def test_is_policy_public_kms_caller_account_and_via_service(self):
        policy = {
            "Version": "2008-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": [
                        "kms:Encrypt",
                        "kms:Decrypt",
                        "kms:ReEncrypt*",
                        "kms:GenerateDataKey*",
                        "kms:CreateGrant",
                        "kms:DescribeKey",
                    ],
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "kms:ViaService": "glue.eu-central-1.amazonaws.com",
                            "kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER,
                        }
                    },
                },
            ],
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_kms_caller_account_only(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": ["kms:Decrypt"],
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "kms:CallerAccount": TRUSTED_AWS_ACCOUNT_NUMBER,
                        }
                    },
                },
            ],
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_is_policy_public_kms_via_service_without_account_restriction(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Action": ["kms:Decrypt"],
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "kms:ViaService": "glue.eu-central-1.amazonaws.com",
                        }
                    },
                },
            ],
        }
        assert not is_policy_public(policy, TRUSTED_AWS_ACCOUNT_NUMBER)

    def test_check_admin_access(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [{"Effect": "Allow", "Action": ["*"], "Resource": "*"}],
        }
        assert check_admin_access(policy)

    def test_check_admin_access_false(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [{"Effect": "Allow", "Action": ["s3:*"], "Resource": "*"}],
        }
        assert not check_admin_access(policy)

    def test_check_admin_access_not_action(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [{"Effect": "Allow", "NotAction": "s3:*", "Resource": "*"}],
        }
        assert check_admin_access(policy)

    def test_check_admin_access_not_action_with_random_action(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {"Effect": "Allow", "NotAction": "prowler:action", "Resource": "*"}
            ],
        }
        assert check_admin_access(policy)

    def test_check_admin_access_not_resource(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [{"Effect": "Allow", "Action": "*", "NotResource": "*"}],
        }
        assert not check_admin_access(policy)

    def test_check_admin_access_not_resource_with_random_resource(self):
        policy = {
            "Version": "2012-10-17",
            "Statement": [
                {"Effect": "Allow", "Action": "*", "NotResource": "prowler:resource"}
            ],
        }
        assert check_admin_access(policy)


def test_is_codebuild_using_allowed_github_org_allows():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "codebuild.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com/allowed-org/repo"
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is True
    assert org_name == "allowed-org"


def test_is_codebuild_using_allowed_github_org_denies():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "codebuild.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com/not-allowed-org/repo"
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is False
    assert org_name == "not-allowed-org"


def test_is_codebuild_using_allowed_github_org_no_codebuild_principal():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "lambda.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com/allowed-org/repo"
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is False
    assert org_name is None


def test_is_codebuild_using_allowed_github_org_invalid_url():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "codebuild.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com//test"  # Malformed, no org
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is False
    assert org_name is None


def test_has_codebuild_trusted_principal_true():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "codebuild.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    assert has_codebuild_trusted_principal(trust_policy) is True


def test_has_codebuild_trusted_principal_false():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {"Service": "lambda.amazonaws.com"},
                "Action": "sts:AssumeRole",
            }
        ],
    }
    assert has_codebuild_trusted_principal(trust_policy) is False


def test_has_codebuild_trusted_principal_empty():
    trust_policy = {}
    assert has_codebuild_trusted_principal(trust_policy) is False


def test_is_codebuild_using_allowed_github_org_principal_string():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": "codebuild.amazonaws.com",
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com/allowed-org/repo"
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is True
    assert org_name == "allowed-org"


def test_is_codebuild_using_allowed_github_org_principal_list():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": ["codebuild.amazonaws.com", "lambda.amazonaws.com"],
                "Action": "sts:AssumeRole",
            }
        ],
    }
    github_repo_url = "https://github.com/allowed-org/repo"
    allowed_organizations = ["allowed-org"]
    is_allowed, org_name = is_codebuild_using_allowed_github_org(
        trust_policy, github_repo_url, allowed_organizations
    )
    assert is_allowed is True
    assert org_name == "allowed-org"


def test_has_codebuild_trusted_principal_string():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": "codebuild.amazonaws.com",
                "Action": "sts:AssumeRole",
            }
        ],
    }
    assert has_codebuild_trusted_principal(trust_policy) is True


def test_has_codebuild_trusted_principal_list():
    trust_policy = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": ["codebuild.amazonaws.com", "lambda.amazonaws.com"],
                "Action": "sts:AssumeRole",
            }
        ],
    }
    assert has_codebuild_trusted_principal(trust_policy) is True


class Test_has_public_principal:
    """Tests for the has_public_principal function"""

    def test_has_public_principal_wildcard_string(self):
        """Test public principal detection with wildcard string"""
        statement = {"Principal": "*"}
        assert has_public_principal(statement) is True

    def test_has_public_principal_root_arn_string(self):
        """Test public principal detection with root ARN string"""
        statement = {"Principal": "arn:aws:iam::*:root"}
        assert has_public_principal(statement) is True

    def test_has_public_principal_aws_dict_wildcard(self):
        """Test public principal detection with AWS dict containing wildcard"""
        statement = {"Principal": {"AWS": "*"}}
        assert has_public_principal(statement) is True

    def test_has_public_principal_aws_dict_root_arn(self):
        """Test public principal detection with AWS dict containing root ARN"""
        statement = {"Principal": {"AWS": "arn:aws:iam::*:root"}}
        assert has_public_principal(statement) is True

    def test_has_public_principal_aws_list_wildcard(self):
        """Test public principal detection with AWS list containing wildcard"""
        statement = {"Principal": {"AWS": ["arn:aws:iam::123456789012:user/test", "*"]}}
        assert has_public_principal(statement) is True

    def test_has_public_principal_aws_list_root_arn(self):
        """Test public principal detection with AWS list containing root ARN"""
        statement = {
            "Principal": {
                "AWS": ["arn:aws:iam::123456789012:user/test", "arn:aws:iam::*:root"]
            }
        }
        assert has_public_principal(statement) is True

    def test_has_public_principal_canonical_user_wildcard(self):
        """Test public principal detection with CanonicalUser wildcard"""
        statement = {"Principal": {"CanonicalUser": "*"}}
        assert has_public_principal(statement) is True

    def test_has_public_principal_canonical_user_root_arn(self):
        """Test public principal detection with CanonicalUser root ARN"""
        statement = {"Principal": {"CanonicalUser": "arn:aws:iam::*:root"}}
        assert has_public_principal(statement) is True

    def test_has_public_principal_no_principal(self):
        """Test with statement that has no Principal field"""
        statement = {"Effect": "Allow", "Action": "s3:GetObject"}
        assert has_public_principal(statement) is False

    def test_has_public_principal_empty_principal(self):
        """Test with empty principal"""
        statement = {"Principal": ""}
        assert has_public_principal(statement) is False

    def test_has_public_principal_specific_account(self):
        """Test with specific account principal (not public)"""
        statement = {"Principal": {"AWS": "arn:aws:iam::123456789012:root"}}
        assert has_public_principal(statement) is False

    def test_has_public_principal_service_principal(self):
        """Test with service principal (not public)"""
        statement = {"Principal": {"Service": "lambda.amazonaws.com"}}
        assert has_public_principal(statement) is False

    def test_has_public_principal_mixed_principals(self):
        """Test with mixed principals including public one"""
        statement = {
            "Principal": {
                "AWS": ["arn:aws:iam::123456789012:user/test"],
                "Service": "lambda.amazonaws.com",
                "CanonicalUser": "*",
            }
        }
        assert has_public_principal(statement) is True


class Test_has_restrictive_source_arn_condition:
    """Tests for the has_restrictive_source_arn_condition function"""

    def test_no_condition_block(self):
        """Test statement without Condition block"""
        statement = {"Effect": "Allow", "Principal": "*", "Action": "s3:GetObject"}
        assert has_restrictive_source_arn_condition(statement) is False

    def test_no_source_arn_condition(self):
        """Test with condition block but no aws:SourceArn"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Condition": {"StringEquals": {"aws:SourceAccount": "123456789012"}},
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_restrictive_source_arn_s3_bucket(self):
        """Test restrictive SourceArn condition with S3 bucket"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": "arn:aws:s3:::my-bucket"}},
        }
        assert has_restrictive_source_arn_condition(statement) is True

    def test_restrictive_source_arn_lambda_function(self):
        """Test restrictive SourceArn condition with Lambda function"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnEquals": {
                    "aws:SourceArn": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction"
                }
            },
        }
        assert has_restrictive_source_arn_condition(statement) is True

    def test_non_restrictive_global_wildcard(self):
        """Test non-restrictive SourceArn with global wildcard"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": "*"}},
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_non_restrictive_service_wildcard(self):
        """Test non-restrictive SourceArn with service wildcard"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": "arn:aws:s3:::*"}},
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_non_restrictive_multi_wildcard(self):
        """Test non-restrictive SourceArn with multiple wildcards"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": "arn:aws:*:*:*:*"}},
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_non_restrictive_resource_wildcard(self):
        """Test non-restrictive SourceArn with resource wildcard"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {"aws:SourceArn": "arn:aws:lambda:us-east-1:123456789012:*"}
            },
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_source_arn_list_with_valid_arn(self):
        """Test SourceArn condition with list containing valid ARN"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {
                    "aws:SourceArn": ["arn:aws:s3:::bucket1", "arn:aws:s3:::bucket2"]
                }
            },
        }
        assert has_restrictive_source_arn_condition(statement) is True

    def test_source_arn_list_with_wildcard(self):
        """Test SourceArn condition with list containing wildcard"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": ["arn:aws:s3:::bucket1", "*"]}},
        }
        assert has_restrictive_source_arn_condition(statement) is False

    def test_source_arn_with_account_validation_match(self):
        """Test SourceArn with account validation - matching account"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction"
                }
            },
        }
        assert has_restrictive_source_arn_condition(statement, "123456789012") is True

    def test_source_arn_with_account_validation_mismatch(self):
        """Test SourceArn with account validation - non-matching account"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction"
                }
            },
        }
        assert has_restrictive_source_arn_condition(statement, "987654321098") is False

    def test_source_arn_with_account_wildcard(self):
        """Test SourceArn with account wildcard"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:lambda:us-east-1:*:function:MyFunction"
                }
            },
        }
        assert has_restrictive_source_arn_condition(statement, "123456789012") is False

    def test_source_arn_s3_bucket_no_account_field(self):
        """Test SourceArn with S3 bucket (no account field) - should be restrictive"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"aws:SourceArn": "arn:aws:s3:::my-bucket"}},
        }
        assert has_restrictive_source_arn_condition(statement, "123456789012") is True

    def test_source_arn_case_insensitive(self):
        """Test SourceArn condition key is case insensitive"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {"ArnLike": {"AWS:SourceArn": "arn:aws:s3:::my-bucket"}},
        }
        assert has_restrictive_source_arn_condition(statement) is True

    def test_source_arn_mixed_operators(self):
        """Test SourceArn with multiple condition operators"""
        statement = {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "sns:Publish",
            "Condition": {
                "ArnLike": {"aws:SourceArn": "arn:aws:s3:::my-bucket"},
                "StringEquals": {"aws:SourceAccount": "123456789012"},
            },
        }
        assert has_restrictive_source_arn_condition(statement) is True
