def try_generate_arn()

in cfn_policy_validator/parsers/utils/arn_generator.py [0:0]


    def try_generate_arn(self, resource_name, resource, attribute_or_ref, visited_values=None):
        if visited_values is None:
            visited_values = []

        cfn_type = resource['Type']
        split_cfn_type = cfn_type.split("::")
        if len(split_cfn_type) != 3:
            if len(split_cfn_type) == 4 and split_cfn_type[3].lower() == 'module':
                raise ApplicationError(f'Unable to resolve {cfn_type}. CloudFormation modules are not yet supported.')

            raise ApplicationError(f'Invalid resource type: {cfn_type}')

        service_name = split_cfn_type[1]
        resource_type = split_cfn_type[2]

        arn_pattern = self.cfn_to_arn_map\
            .get(service_name, {})\
            .get(resource_type, {})\
            .get(attribute_or_ref)

        if arn_pattern is None:
            return None

        arn_pattern = arn_pattern['Value']

        # arn_patterns follow the format: arn:${Partition}:sqs:${Region}:${Account}:${QueueName}
        # where Partition, Account, and Region are standardized variable names
        arn_pattern = arn_pattern.replace("${Partition}", self.account_config.partition)
        arn_pattern = arn_pattern.replace("${Region}", self.account_config.region)
        arn_pattern = arn_pattern.replace("${Account}", self.account_config.account_id)

        # certain CFN types require some additional generation that is specific to the resource type
        # for example, we include the exact path with any roles or users, ALBs and NLBs share the same cfn resource,
        # but have different ARNs
        custom_generator = self.custom_generators.get(cfn_type)
        if custom_generator is not None:
            arn_pattern = custom_generator(arn_pattern, resource_name, resource, visited_values)

        # match any variable (anything not Partition, Account, Region) within brackets and replace with the resource name
        # e.g. arn:aws:..:${SomeResourceName} -> arn:aws:..:ResourceName
        regex = r"(?P<Variable>\${[^}]*})"

        def callback(match):
            return resource_name

        arn_pattern = re.sub(regex, callback, arn_pattern)

        return arn_pattern