diff --git a/Makefile b/Makefile index 03b4bdb3ba..b9084260bf 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ func-test: smoke-test: # Smoke tests run in parallel - pytest -n 4 tests/functional + SAM_CLI_DEV=1 pytest -n 4 tests/smoke lint: # Linter performs static analysis to catch latent bugs diff --git a/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py b/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py index 005b61e89a..f9a7720ca4 100644 --- a/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py +++ b/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py @@ -164,7 +164,7 @@ def set_conditional_function_map(self, function_map): """ self.conditional_key_function_map = function_map - def intrinsic_property_resolver(self, intrinsic, parent_function="template"): + def intrinsic_property_resolver(self, intrinsic, ignore_errors, parent_function="template"): """ This resolves the intrinsic of the format { @@ -193,7 +193,7 @@ def intrinsic_property_resolver(self, intrinsic, parent_function="template"): if intrinsic is None: raise InvalidIntrinsicException("Missing Intrinsic property in {}".format(parent_function)) if isinstance(intrinsic, list): - return [self.intrinsic_property_resolver(item) for item in intrinsic] + return [self.intrinsic_property_resolver(item, ignore_errors) for item in intrinsic] if not isinstance(intrinsic, dict) or intrinsic == {}: return intrinsic @@ -204,24 +204,33 @@ def intrinsic_property_resolver(self, intrinsic, parent_function="template"): if key in self.intrinsic_key_function_map: intrinsic_value = intrinsic.get(key) - return self.intrinsic_key_function_map.get(key)(intrinsic_value) + return self.intrinsic_key_function_map.get(key)(intrinsic_value, ignore_errors) elif key in self.conditional_key_function_map: intrinsic_value = intrinsic.get(key) - return self.conditional_key_function_map.get(key)(intrinsic_value) + return self.conditional_key_function_map.get(key)(intrinsic_value, ignore_errors) # In this case, it is a dictionary that doesn't directly contain an intrinsic resolver, we must recursively # resolve each of it's sub properties. sanitized_dict = {} for key, val in intrinsic.items(): - sanitized_key = self.intrinsic_property_resolver(key, parent_function=parent_function) - sanitized_val = self.intrinsic_property_resolver(val, parent_function=parent_function) - verify_intrinsic_type_str( - sanitized_key, - message="The keys of the dictionary {} in {} must all resolve to a string".format( - sanitized_key, parent_function - ), - ) - sanitized_dict[sanitized_key] = sanitized_val + try: + sanitized_key = self.intrinsic_property_resolver(key, ignore_errors, parent_function=parent_function) + sanitized_val = self.intrinsic_property_resolver(val, ignore_errors, parent_function=parent_function) + verify_intrinsic_type_str( + sanitized_key, + message="The keys of the dictionary {} in {} must all resolve to a string".format( + sanitized_key, parent_function + ), + ) + sanitized_dict[sanitized_key] = sanitized_val + # On any exception, leave the key:val of the orginal intact and continue on. https://github.com/awslabs/aws-sam-cli/issues/1386 + except Exception: + if ignore_errors: + LOG.debug("Unable to resolve property %s: %s. Leaving as is.", key, val) + sanitized_dict[key] = val + else: + raise + return sanitized_dict def resolve_template(self, ignore_errors=False): @@ -261,7 +270,7 @@ def resolve_attribute(self, cloud_formation_property, ignore_errors=False): for key, val in cloud_formation_property.items(): processed_key = self._symbol_resolver.get_translation(key) or key try: - processed_resource = self.intrinsic_property_resolver(val, parent_function=processed_key) + processed_resource = self.intrinsic_property_resolver(val, ignore_errors, parent_function=processed_key) processed_dict[processed_key] = processed_resource except (InvalidIntrinsicException, InvalidSymbolException) as e: resource_type = val.get("Type", "") @@ -274,7 +283,7 @@ def resolve_attribute(self, cloud_formation_property, ignore_errors=False): ) return processed_dict - def handle_fn_join(self, intrinsic_value): + def handle_fn_join(self, intrinsic_value, ignore_errors): """ { "Fn::Join" : [ "delimiter", [ comma-delimited list of values ] ] } This function will join the items in the list together based on the string using the python join. @@ -290,7 +299,9 @@ def handle_fn_join(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_JOIN) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_JOIN + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_JOIN) @@ -298,7 +309,9 @@ def handle_fn_join(self, intrinsic_value): verify_intrinsic_type_str(delimiter, IntrinsicResolver.FN_JOIN, position_in_list="first") - value_list = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_JOIN) + value_list = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_JOIN + ) verify_intrinsic_type_list( value_list, @@ -307,7 +320,8 @@ def handle_fn_join(self, intrinsic_value): ) sanitized_value_list = [ - self.intrinsic_property_resolver(item, parent_function=IntrinsicResolver.FN_JOIN) for item in value_list + self.intrinsic_property_resolver(item, ignore_errors, parent_function=IntrinsicResolver.FN_JOIN) + for item in value_list ] verify_all_list_intrinsic_type( sanitized_value_list, verification_func=verify_intrinsic_type_str, property_type=IntrinsicResolver.FN_JOIN @@ -315,7 +329,7 @@ def handle_fn_join(self, intrinsic_value): return delimiter.join(sanitized_value_list) - def handle_fn_split(self, intrinsic_value): + def handle_fn_split(self, intrinsic_value, ignore_errors): """ { "Fn::Split" : [ "delimiter", "source string" ] } This function will then split the source_string based on the delimiter @@ -330,7 +344,9 @@ def handle_fn_split(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_SPLIT) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_SPLIT + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_SPLIT) @@ -338,13 +354,15 @@ def handle_fn_split(self, intrinsic_value): verify_intrinsic_type_str(delimiter, IntrinsicResolver.FN_SPLIT, position_in_list="first") - source_string = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_SPLIT) + source_string = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_SPLIT + ) verify_intrinsic_type_str(source_string, IntrinsicResolver.FN_SPLIT, position_in_list="second") return source_string.split(delimiter) - def handle_fn_base64(self, intrinsic_value): + def handle_fn_base64(self, intrinsic_value, ignore_errors): """ { "Fn::Base64" : valueToEncode } This intrinsic function will then base64 encode the string using python's base64. @@ -359,13 +377,15 @@ def handle_fn_base64(self, intrinsic_value): ------- A string with the resolved attributes """ - data = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_BASE64) + data = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_BASE64 + ) verify_intrinsic_type_str(data, IntrinsicResolver.FN_BASE64) # Encoding then decoding is required to return a string of the data return base64.b64encode(data.encode()).decode() - def handle_fn_select(self, intrinsic_value): + def handle_fn_select(self, intrinsic_value, ignore_errors): """ { "Fn::Select" : [ index, listOfObjects ] } It will select the item in the listOfObjects using python's base64. @@ -379,19 +399,25 @@ def handle_fn_select(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_SELECT) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_SELECT + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_SELECT) - index = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_SELECT) + index = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_SELECT + ) verify_intrinsic_type_int(index, IntrinsicResolver.FN_SELECT) - list_of_objects = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_SELECT) + list_of_objects = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_SELECT + ) verify_intrinsic_type_list(list_of_objects, IntrinsicResolver.FN_SELECT) sanitized_objects = [ - self.intrinsic_property_resolver(item, parent_function=IntrinsicResolver.FN_SELECT) + self.intrinsic_property_resolver(item, ignore_errors, parent_function=IntrinsicResolver.FN_SELECT) for item in list_of_objects ] @@ -399,7 +425,7 @@ def handle_fn_select(self, intrinsic_value): return sanitized_objects[index] - def handle_find_in_map(self, intrinsic_value): + def handle_find_in_map(self, intrinsic_value, ignore_errors): """ { "Fn::FindInMap" : [ "MapName", "TopLevelKey", "SecondLevelKey"] } This function will then lookup the specified dictionary in the Mappings dictionary as mappings[map_name][top_level_key][second_level_key]. @@ -424,16 +450,22 @@ def handle_find_in_map(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_FIND_IN_MAP) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_FIND_IN_MAP + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_FIND_IN_MAP) verify_number_arguments(arguments, num=3, property_type=IntrinsicResolver.FN_FIND_IN_MAP) - map_name = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_FIND_IN_MAP) - top_level_key = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_FIND_IN_MAP) + map_name = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_FIND_IN_MAP + ) + top_level_key = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_FIND_IN_MAP + ) second_level_key = self.intrinsic_property_resolver( - arguments[2], parent_function=IntrinsicResolver.FN_FIND_IN_MAP + arguments[2], ignore_errors, parent_function=IntrinsicResolver.FN_FIND_IN_MAP ) verify_intrinsic_type_str(map_name, IntrinsicResolver.FN_FIND_IN_MAP, position_in_list="first") @@ -466,7 +498,7 @@ def handle_find_in_map(self, intrinsic_value): return second_level_value - def handle_fn_get_azs(self, intrinsic_value): + def handle_fn_get_azs(self, intrinsic_value, ignore_errors): """ { "Fn::GetAZs" : "" } { "Fn::GetAZs" : { "Ref" : "AWS::Region" } } @@ -485,7 +517,7 @@ def handle_fn_get_azs(self, intrinsic_value): A string with the resolved attributes """ intrinsic_value = self.intrinsic_property_resolver( - intrinsic_value, parent_function=IntrinsicResolver.FN_GET_AZS + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_GET_AZS ) verify_intrinsic_type_str(intrinsic_value, IntrinsicResolver.FN_GET_AZS) @@ -499,7 +531,7 @@ def handle_fn_get_azs(self, intrinsic_value): return self._symbol_resolver.REGIONS.get(intrinsic_value) - def handle_fn_transform(self, intrinsic_value): + def handle_fn_transform(self, intrinsic_value, ignore_errors): """ { "Fn::Transform" : { "Name" : macro name, "Parameters" : {key : value, ... } } } This intrinsic function will transform the data with the body provided @@ -515,7 +547,9 @@ def handle_fn_transform(self, intrinsic_value): A string with the resolved attributes """ macro_name = intrinsic_value.get("Name") - name = self.intrinsic_property_resolver(macro_name, parent_function=IntrinsicResolver.FN_TRANSFORM) + name = self.intrinsic_property_resolver( + macro_name, ignore_errors, parent_function=IntrinsicResolver.FN_TRANSFORM + ) if name not in IntrinsicResolver.SUPPORTED_MACRO_TRANSFORMATIONS: raise InvalidIntrinsicException( @@ -527,10 +561,10 @@ def handle_fn_transform(self, intrinsic_value): parameters, IntrinsicResolver.FN_TRANSFORM, message=" Fn::Transform requires parameters section" ) - location = self.intrinsic_property_resolver(parameters.get("Location")) + location = self.intrinsic_property_resolver(parameters.get("Location"), ignore_errors) return location - def handle_fn_import_value(self, intrinsic_value): + def handle_fn_import_value(self, intrinsic_value, ignore_errors): """ { "Fn::ImportValue" : sharedValueToImport } This intrinsic function requires handling multiple stacks, which is not currently supported by SAM-CLI. @@ -542,7 +576,7 @@ def handle_fn_import_value(self, intrinsic_value): """ raise InvalidIntrinsicException("Fn::ImportValue is currently not supported by IntrinsicResolver") - def handle_fn_getatt(self, intrinsic_value): + def handle_fn_getatt(self, intrinsic_value, ignore_errors): """ { "Fn::GetAtt" : [ "logicalNameOfResource", "attributeName" ] } This intrinsic function gets the attribute for logical_resource specified. Each attribute might have a different @@ -559,19 +593,25 @@ def handle_fn_getatt(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_GET_ATT) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_GET_ATT + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_GET_ATT) verify_number_arguments(arguments, IntrinsicResolver.FN_GET_ATT, num=2) - logical_id = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_GET_ATT) - resource_type = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_GET_ATT) + logical_id = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_GET_ATT + ) + resource_type = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_GET_ATT + ) verify_intrinsic_type_str(logical_id, IntrinsicResolver.FN_GET_ATT) verify_intrinsic_type_str(resource_type, IntrinsicResolver.FN_GET_ATT) return self._symbol_resolver.resolve_symbols(logical_id, resource_type) - def handle_fn_ref(self, intrinsic_value): + def handle_fn_ref(self, intrinsic_value, ignore_errors): """ {"Ref": "Logical ID"} This intrinsic function gets the reference to a certain attribute. Some Ref's have different functionality with @@ -588,12 +628,14 @@ def handle_fn_ref(self, intrinsic_value): ------- A string with the resolved attributes """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.REF) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.REF + ) verify_intrinsic_type_str(arguments, IntrinsicResolver.REF) return self._symbol_resolver.resolve_symbols(arguments, IntrinsicResolver.REF) - def handle_fn_sub(self, intrinsic_value): + def handle_fn_sub(self, intrinsic_value, ignore_errors): """ { "Fn::Sub" : [ String, { Var1Name: Var1Value, Var2Name: Var2Value } ] } or { "Fn::Sub" : String } This intrinsic function will substitute the variables specified in the list into the string provided. The string @@ -626,13 +668,17 @@ def resolve_sub_attribute(intrinsic_item, symbol_resolver): verify_number_arguments(intrinsic_value, IntrinsicResolver.FN_SUB, num=2) - sub_str = self.intrinsic_property_resolver(intrinsic_value[0], parent_function=IntrinsicResolver.FN_SUB) + sub_str = self.intrinsic_property_resolver( + intrinsic_value[0], ignore_errors, parent_function=IntrinsicResolver.FN_SUB + ) verify_intrinsic_type_str(sub_str, IntrinsicResolver.FN_SUB, position_in_list="first") variables = intrinsic_value[1] verify_intrinsic_type_dict(variables, IntrinsicResolver.FN_SUB, position_in_list="second") - sanitized_variables = self.intrinsic_property_resolver(variables, parent_function=IntrinsicResolver.FN_SUB) + sanitized_variables = self.intrinsic_property_resolver( + variables, ignore_errors, parent_function=IntrinsicResolver.FN_SUB + ) subable_props = re.findall(string=sub_str, pattern=IntrinsicResolver._REGEX_SUB_FUNCTION) for sub_item in subable_props: @@ -641,7 +687,7 @@ def resolve_sub_attribute(intrinsic_item, symbol_resolver): sub_str = re.sub(pattern=r"\$\{" + sub_item + r"\}", string=sub_str, repl=str(result)) return sub_str - def handle_fn_if(self, intrinsic_value): + def handle_fn_if(self, intrinsic_value, ignore_errors): """ {"Fn::If": [condition_name, value_if_true, value_if_false]} This intrinsic function will evaluate the condition from the Conditions dictionary and then return value_if_true @@ -664,15 +710,23 @@ def handle_fn_if(self, intrinsic_value): ------- This will return value_if_true and value_if_false depending on how the condition is evaluated """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_IF) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_IF + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_IF) verify_number_arguments(arguments, IntrinsicResolver.FN_IF, num=3) - condition_name = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_IF) + condition_name = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_IF + ) verify_intrinsic_type_str(condition_name, IntrinsicResolver.FN_IF) - value_if_true = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_IF) - value_if_false = self.intrinsic_property_resolver(arguments[2], parent_function=IntrinsicResolver.FN_IF) + value_if_true = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_IF + ) + value_if_false = self.intrinsic_property_resolver( + arguments[2], ignore_errors, parent_function=IntrinsicResolver.FN_IF + ) condition = self._conditions.get(condition_name) verify_intrinsic_type_dict( @@ -681,7 +735,9 @@ def handle_fn_if(self, intrinsic_value): message="The condition is missing in the Conditions dictionary for {}".format(IntrinsicResolver.FN_IF), ) - condition_evaluated = self.intrinsic_property_resolver(condition, parent_function=IntrinsicResolver.FN_IF) + condition_evaluated = self.intrinsic_property_resolver( + condition, ignore_errors, parent_function=IntrinsicResolver.FN_IF + ) verify_intrinsic_type_bool( condition_evaluated, IntrinsicResolver.FN_IF, @@ -690,7 +746,7 @@ def handle_fn_if(self, intrinsic_value): return value_if_true if condition_evaluated else value_if_false - def handle_fn_equals(self, intrinsic_value): + def handle_fn_equals(self, intrinsic_value, ignore_errors): """ {"Fn::Equals" : ["value_1", "value_2"]} This intrinsic function will verify that both items in the intrinsic function are equal after resolving them. @@ -705,15 +761,21 @@ def handle_fn_equals(self, intrinsic_value): ------- A boolean depending on if both arguments is equal """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_EQUALS) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_EQUALS + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_EQUALS) verify_number_arguments(arguments, IntrinsicResolver.FN_EQUALS, num=2) - value_1 = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_EQUALS) - value_2 = self.intrinsic_property_resolver(arguments[1], parent_function=IntrinsicResolver.FN_EQUALS) + value_1 = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_EQUALS + ) + value_2 = self.intrinsic_property_resolver( + arguments[1], ignore_errors, parent_function=IntrinsicResolver.FN_EQUALS + ) return value_1 == value_2 - def handle_fn_not(self, intrinsic_value): + def handle_fn_not(self, intrinsic_value, ignore_errors): """ {"Fn::Not": [{condition}]} This intrinsic function will negate the evaluation of the condition specified. @@ -728,10 +790,14 @@ def handle_fn_not(self, intrinsic_value): ------- A boolean that is the opposite of the condition evaluated """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_NOT) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_NOT + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_NOT) verify_number_arguments(arguments, IntrinsicResolver.FN_NOT, num=1) - argument_sanitised = self.intrinsic_property_resolver(arguments[0], parent_function=IntrinsicResolver.FN_NOT) + argument_sanitised = self.intrinsic_property_resolver( + arguments[0], ignore_errors, parent_function=IntrinsicResolver.FN_NOT + ) if isinstance(argument_sanitised, dict) and "Condition" in arguments[0]: condition_name = argument_sanitised.get("Condition") verify_intrinsic_type_str(condition_name, IntrinsicResolver.FN_NOT) @@ -739,7 +805,9 @@ def handle_fn_not(self, intrinsic_value): condition = self._conditions.get(condition_name) verify_non_null(condition, IntrinsicResolver.FN_NOT, position_in_list="first") - argument_sanitised = self.intrinsic_property_resolver(condition, parent_function=IntrinsicResolver.FN_NOT) + argument_sanitised = self.intrinsic_property_resolver( + condition, ignore_errors, parent_function=IntrinsicResolver.FN_NOT + ) verify_intrinsic_type_bool( argument_sanitised, @@ -764,7 +832,7 @@ def get_prefix_position_in_list(i): prefix = "third " return prefix - def handle_fn_and(self, intrinsic_value): + def handle_fn_and(self, intrinsic_value, ignore_errors): """ {"Fn::And": [{condition}, {...}]} This intrinsic checks that every item in the list evaluates to a boolean. The items in the list can either @@ -788,7 +856,9 @@ def handle_fn_and(self, intrinsic_value): ------- A boolean depending on if all of the properties in Fn::And evaluate to True """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_AND) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_AND + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_AND) for i, argument in enumerate(arguments): @@ -802,14 +872,16 @@ def handle_fn_and(self, intrinsic_value): ) condition_evaluated = self.intrinsic_property_resolver( - condition, parent_function=IntrinsicResolver.FN_AND + condition, ignore_errors, parent_function=IntrinsicResolver.FN_AND ) verify_intrinsic_type_bool(condition_evaluated, IntrinsicResolver.FN_AND) if not condition_evaluated: return False else: - condition = self.intrinsic_property_resolver(argument, parent_function=IntrinsicResolver.FN_AND) + condition = self.intrinsic_property_resolver( + argument, ignore_errors, parent_function=IntrinsicResolver.FN_AND + ) verify_intrinsic_type_bool(condition, IntrinsicResolver.FN_AND) if not condition: @@ -817,7 +889,7 @@ def handle_fn_and(self, intrinsic_value): return True - def handle_fn_or(self, intrinsic_value): + def handle_fn_or(self, intrinsic_value, ignore_errors): """ {"Fn::Or": [{condition}, {...}]} This intrinsic checks that a single item in the list evaluates to a boolean. The items in the list can either @@ -841,7 +913,9 @@ def handle_fn_or(self, intrinsic_value): ------- A boolean depending on if any of the properties in Fn::And evaluate to True """ - arguments = self.intrinsic_property_resolver(intrinsic_value, parent_function=IntrinsicResolver.FN_OR) + arguments = self.intrinsic_property_resolver( + intrinsic_value, ignore_errors, parent_function=IntrinsicResolver.FN_OR + ) verify_intrinsic_type_list(arguments, IntrinsicResolver.FN_OR) for i, argument in enumerate(arguments): if isinstance(argument, dict) and "Condition" in argument: @@ -854,13 +928,15 @@ def handle_fn_or(self, intrinsic_value): ) condition_evaluated = self.intrinsic_property_resolver( - condition, parent_function=IntrinsicResolver.FN_OR + condition, ignore_errors, parent_function=IntrinsicResolver.FN_OR ) verify_intrinsic_type_bool(condition_evaluated, IntrinsicResolver.FN_OR) if condition_evaluated: return True else: - condition = self.intrinsic_property_resolver(argument, parent_function=IntrinsicResolver.FN_OR) + condition = self.intrinsic_property_resolver( + argument, ignore_errors, parent_function=IntrinsicResolver.FN_OR + ) verify_intrinsic_type_bool(condition, IntrinsicResolver.FN_OR) if condition: return True diff --git a/tests/smoke/templates/sar/getatt-custom-resource.yaml b/tests/smoke/templates/sar/getatt-custom-resource.yaml new file mode 100644 index 0000000000..7837d31d8b --- /dev/null +++ b/tests/smoke/templates/sar/getatt-custom-resource.yaml @@ -0,0 +1,37 @@ + +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 + +Resources: + MyCustomResource: + Type: AWS::CloudFormation::CustomResource + Properties: + ServiceToken: String + + APIGetFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: + Bucket: <%REPO_BUCKET%> + Key: 7d354083-39c1-4a33-a435-fbf3dbab85b7 + Handler: main + Environment: + Variables: + SAFE_ENVIRONMENT_VARIABLE_1: + !Ref TemplateParameterOne + OFFENDING_ENVIRONMENT_VARIABLE: + !GetAtt MyCustomResource.Parameter.Value + SAFE_ENVIRONMENT_VARIABLE_2: + !Ref MyCustomResource + Events: + PostEvent: + Type: Api + Properties: + Path: / + Method: post + GetEvent: + Type: Api + Properties: + Path: / + Method: get + Runtime: go1.x diff --git a/tests/smoke/templates/sar/vpc-import-value.yaml b/tests/smoke/templates/sar/vpc-import-value.yaml new file mode 100644 index 0000000000..af9aaebdff --- /dev/null +++ b/tests/smoke/templates/sar/vpc-import-value.yaml @@ -0,0 +1,25 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Layer Test +Parameters: + LayerArn: + Default: 'arn:aws:lambda:us-east-1:764866452798:layer:chrome-aws-lambda:4' + Description: Layer Arn + Type: String +Resources: + FunctionWithLayer: + Type: AWS::Serverless::Function + Properties: + CodeUri: + Bucket: <%REPO_BUCKET%> + Key: a44a03c9-ccb1-4ddc-b196-8e2c9fdeec35 + Handler: app.lambda_handler + Runtime: python3.7 + Layers: + - Ref: LayerArn + VpcConfig: + SecurityGroupIds: + - Fn::ImportValue: !Sub ${VpcStackName}-AppSG + SubnetIds: + - Fn::ImportValue: !Sub ${VpcStackName}-AppSubnet1 + - Fn::ImportValue: !Sub ${VpcStackName}-AppSubnet2 diff --git a/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py b/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py index f826632ea0..991fa1cb20 100644 --- a/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py +++ b/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py @@ -21,14 +21,14 @@ def setUp(self): def test_basic_fn_join(self): intrinsic = {"Fn::Join": [",", ["a", "b", "c", "d"]]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "a,b,c,d") def test_nested_fn_join(self): intrinsic_base_1 = {"Fn::Join": [",", ["a", "b", "c", "d"]]} intrinsic_base_2 = {"Fn::Join": [";", ["g", "h", "i", intrinsic_base_1]]} intrinsic = {"Fn::Join": [":", [intrinsic_base_1, "e", "f", intrinsic_base_2]]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "a,b,c,d:e:f:g;h;i;a,b,c,d") @parameterized.expand( @@ -39,7 +39,7 @@ def test_nested_fn_join(self): ) def test_fn_join_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Join": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Join": intrinsic}, True) @parameterized.expand( [ @@ -49,7 +49,7 @@ def test_fn_join_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_join_delimiter_invalid_type(self, name, delimiter): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Join": [delimiter, []]}) + self.resolver.intrinsic_property_resolver({"Fn::Join": [delimiter, []]}, True) @parameterized.expand( [ @@ -59,7 +59,7 @@ def test_fn_join_delimiter_invalid_type(self, name, delimiter): ) def test_fn_list_of_objects_invalid_type(self, name, list_of_objects): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Join": ["", list_of_objects]}) + self.resolver.intrinsic_property_resolver({"Fn::Join": ["", list_of_objects]}, True) @parameterized.expand( [ @@ -69,7 +69,7 @@ def test_fn_list_of_objects_invalid_type(self, name, list_of_objects): ) def test_fn_join_items_all_str(self, name, single_obj): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Join": ["", ["test", single_obj, "abcd"]]}) + self.resolver.intrinsic_property_resolver({"Fn::Join": ["", ["test", single_obj, "abcd"]]}, True) class TestIntrinsicFnSplitResolver(TestCase): @@ -78,7 +78,7 @@ def setUp(self): def test_basic_fn_split(self): intrinsic = {"Fn::Split": ["|", "a|b|c"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, ["a", "b", "c"]) def test_nested_fn_split(self): @@ -86,7 +86,7 @@ def test_nested_fn_split(self): intrinsic_base_2 = {"Fn::Join": [",", intrinsic_base_1]} intrinsic = {"Fn::Split": [",", {"Fn::Join": [",", [intrinsic_base_2, ",e", ",f,", intrinsic_base_2]]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, ["a", "b", "c", "", "e", "", "f", "", "a", "b", "c"]) @parameterized.expand( @@ -97,7 +97,7 @@ def test_nested_fn_split(self): ) def test_fn_split_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Split": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Split": intrinsic}, True) @parameterized.expand( [ @@ -107,7 +107,7 @@ def test_fn_split_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_split_delimiter_invalid_type(self, name, delimiter): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Split": [delimiter, []]}) + self.resolver.intrinsic_property_resolver({"Fn::Split": [delimiter, []]}, True) @parameterized.expand( [ @@ -117,7 +117,7 @@ def test_fn_split_delimiter_invalid_type(self, name, delimiter): ) def test_fn_split_source_string_invalid_type(self, name, source_string): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Split": ["", source_string]}) + self.resolver.intrinsic_property_resolver({"Fn::Split": ["", source_string]}, True) class TestIntrinsicFnBase64Resolver(TestCase): @@ -126,7 +126,7 @@ def setUp(self): def test_basic_fn_split(self): intrinsic = {"Fn::Base64": "AWS CloudFormation"} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "QVdTIENsb3VkRm9ybWF0aW9u") def test_nested_fn_base64(self): @@ -134,7 +134,7 @@ def test_nested_fn_base64(self): intrinsic_base_2 = {"Fn::Base64": intrinsic_base_1} intrinsic = {"Fn::Base64": {"Fn::Join": [",", [intrinsic_base_2, ",e", ",f,", intrinsic_base_2]]}} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual( result, "VVZaa1ZFbEZUbk5pTTFaclVtMDVlV0pYUmpCaFZ6bDEsLGUsLGYsLFVWWmtWRWxGVG5OaU0xWnJ" "VbTA1ZVdKWFJqQmhWemwx", @@ -148,7 +148,7 @@ def test_nested_fn_base64(self): ) def test_fn_base64_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Base64": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Base64": intrinsic}, True) class TestIntrinsicFnSelectResolver(TestCase): @@ -157,14 +157,14 @@ def setUp(self): def test_basic_fn_select(self): intrinsic = {"Fn::Select": [2, ["a", "b", "c", "d"]]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "c") def test_nested_fn_select(self): intrinsic_base_1 = {"Fn::Select": [0, ["a", "b", "c", "d"]]} intrinsic_base_2 = {"Fn::Join": [";", ["g", "h", "i", intrinsic_base_1]]} intrinsic = {"Fn::Select": [3, [intrinsic_base_2, "e", "f", intrinsic_base_2]]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "g;h;i;a") @parameterized.expand( @@ -175,7 +175,7 @@ def test_nested_fn_select(self): ) def test_fn_select_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Select": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Select": intrinsic}, True) @parameterized.expand( [ @@ -185,14 +185,14 @@ def test_fn_select_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_select_index_invalid_index_type(self, name, index): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Select": [index, [0]]}) + self.resolver.intrinsic_property_resolver({"Fn::Select": [index, [0]]}, True) @parameterized.expand( [("Fn::Select should fail if the index is out of bounds: {}".format(number), number) for number in [-2, 7]] ) def test_fn_select_out_of_bounds(self, name, index): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Select": [index, []]}) + self.resolver.intrinsic_property_resolver({"Fn::Select": [index, []]}, True) @parameterized.expand( [ @@ -202,7 +202,7 @@ def test_fn_select_out_of_bounds(self, name, index): ) def test_fn_select_second_argument_invalid_type(self, name, argument): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Select": [0, argument]}) + self.resolver.intrinsic_property_resolver({"Fn::Select": [0, argument]}, True) class TestIntrinsicFnFindInMapResolver(TestCase): @@ -218,14 +218,14 @@ def setUp(self): def test_basic_find_in_map(self): intrinsic = {"Fn::FindInMap": ["Basic", "Test", "key"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "value") def test_nested_find_in_map(self): intrinsic_base_1 = {"Fn::FindInMap": ["Basic", "Test", "key"]} intrinsic_base_2 = {"Fn::FindInMap": [intrinsic_base_1, "anotherkey", "key"]} intrinsic = {"Fn::FindInMap": [intrinsic_base_2, intrinsic_base_1, "key"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "final") @parameterized.expand( @@ -236,7 +236,7 @@ def test_nested_find_in_map(self): ) def test_fn_find_in_map_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}, True) @parameterized.expand( [ @@ -246,7 +246,7 @@ def test_fn_find_in_map_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_find_in_map_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}, True) @parameterized.expand( [ @@ -260,7 +260,7 @@ def test_fn_find_in_map_invalid_number_arguments(self, name, intrinsic): ) def test_fn_find_in_map_invalid_key_entries(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::FindInMap": intrinsic}, True) class TestIntrinsicFnAzsResolver(TestCase): @@ -272,11 +272,11 @@ def setUp(self): def test_basic_azs(self): intrinsic = {"Ref": "AWS::Region"} - result = self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}) + result = self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}, True) self.assertEqual(result, ["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d", "us-east-1e", "us-east-1f"]) def test_default_get_azs(self): - result = self.resolver.intrinsic_property_resolver({"Fn::GetAZs": ""}) + result = self.resolver.intrinsic_property_resolver({"Fn::GetAZs": ""}, True) self.assertEqual(result, ["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d", "us-east-1e", "us-east-1f"]) @parameterized.expand( @@ -287,12 +287,12 @@ def test_default_get_azs(self): ) def test_fn_azs_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}, True) def test_fn_azs_invalid_region(self): intrinsic = "UNKOWN REGION" with self.assertRaises(InvalidIntrinsicException, msg="FN::GetAzs should fail for unknown region"): - self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::GetAZs": intrinsic}, True) class TestFnTransform(TestCase): @@ -304,12 +304,12 @@ def setUp(self): def test_basic_fn_transform(self): intrinsic = {"Fn::Transform": {"Name": "AWS::Include", "Parameters": {"Location": "test"}}} - self.resolver.intrinsic_property_resolver(intrinsic) + self.resolver.intrinsic_property_resolver(intrinsic, True) def test_fn_transform_unsupported_macro(self): intrinsic = {"Fn::Transform": {"Name": "UNKNOWN", "Parameters": {"Location": "test"}}} with self.assertRaises(InvalidIntrinsicException, msg="FN::Transform should fail for unknown region"): - self.resolver.intrinsic_property_resolver(intrinsic) + self.resolver.intrinsic_property_resolver(intrinsic, True) class TestIntrinsicFnRefResolver(TestCase): @@ -324,12 +324,12 @@ def setUp(self): def test_basic_ref_translation(self): intrinsic = {"Ref": "RestApi"} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "NewRestApi") def test_default_ref_translation(self): intrinsic = {"Ref": "UnknownApi"} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "UnknownApi") @parameterized.expand( @@ -340,7 +340,7 @@ def test_default_ref_translation(self): ) def test_ref_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Ref": intrinsic}) + self.resolver.intrinsic_property_resolver({"Ref": intrinsic}, True) class TestIntrinsicFnGetAttResolver(TestCase): @@ -385,12 +385,12 @@ def setUp(self): def test_fn_getatt_basic_translation(self): intrinsic = {"Fn::GetAtt": ["RestApi", "RootResourceId"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual(result, "/") def test_fn_getatt_logical_id_translated(self): intrinsic = {"Fn::GetAtt": ["LambdaFunction", "Arn"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual( result, "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east" @@ -399,7 +399,7 @@ def test_fn_getatt_logical_id_translated(self): def test_fn_getatt_with_fn_join(self): intrinsic = self.resources.get("LambdaFunction").get("Properties").get("Uri") - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual( result, "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us" @@ -414,7 +414,7 @@ def test_fn_getatt_with_fn_join(self): ) def test_fn_getatt_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::GetAtt": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::GetAtt": intrinsic}, True) @parameterized.expand( [ @@ -424,7 +424,7 @@ def test_fn_getatt_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_getatt_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::GetAtt": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::GetAtt": intrinsic}, True) @parameterized.expand( [ @@ -434,7 +434,7 @@ def test_fn_getatt_invalid_number_arguments(self, name, intrinsic): ) def test_fn_getatt_first_arguments_invalid(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::GetAtt": [intrinsic, IntrinsicResolver.REF]}) + self.resolver.intrinsic_property_resolver({"Fn::GetAtt": [intrinsic, IntrinsicResolver.REF]}, True) @parameterized.expand( [ @@ -444,7 +444,7 @@ def test_fn_getatt_first_arguments_invalid(self, name, intrinsic): ) def test_fn_getatt_second_arguments_invalid(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::GetAtt": ["some logical Id", intrinsic]}) + self.resolver.intrinsic_property_resolver({"Fn::GetAtt": ["some logical Id", intrinsic]}, True) class TestIntrinsicFnSubResolver(TestCase): @@ -461,7 +461,7 @@ def test_fn_sub_basic_uri(self): intrinsic = { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations" } - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual( result, "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1" @@ -475,7 +475,7 @@ def test_fn_sub_uri_arguments(self): {"MyItem": {"Ref": "AWS::Region"}, "MyOtherItem": "LambdaFunction.Arn"}, ] } - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertEqual( result, "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east" @@ -490,7 +490,7 @@ def test_fn_sub_uri_arguments(self): ) def test_fn_sub_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Sub": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Sub": intrinsic}, True) @parameterized.expand( [ @@ -500,7 +500,7 @@ def test_fn_sub_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_sub_first_argument_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Sub": [intrinsic, {}]}) + self.resolver.intrinsic_property_resolver({"Fn::Sub": [intrinsic, {}]}, True) @parameterized.expand( [ @@ -510,7 +510,7 @@ def test_fn_sub_first_argument_invalid_formats(self, name, intrinsic): ) def test_fn_sub_second_argument_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Sub": ["some str", intrinsic]}) + self.resolver.intrinsic_property_resolver({"Fn::Sub": ["some str", intrinsic]}, True) @parameterized.expand( [ @@ -520,7 +520,7 @@ def test_fn_sub_second_argument_invalid_formats(self, name, intrinsic): ) def test_fn_sub_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Sub": ["test"] + intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Sub": ["test"] + intrinsic}, True) class TestIntrinsicFnImportValueResolver(TestCase): @@ -529,7 +529,7 @@ def setUp(self): def test_fn_import_value_unsupported(self): with self.assertRaises(InvalidIntrinsicException, msg="Fn::ImportValue should be unsupported"): - self.resolver.intrinsic_property_resolver({"Fn::ImportValue": ""}) + self.resolver.intrinsic_property_resolver({"Fn::ImportValue": ""}, True) class TestIntrinsicFnEqualsResolver(TestCase): @@ -541,12 +541,12 @@ def setUp(self): def test_fn_equals_basic_true(self): intrinsic = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "prod"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_equals_basic_false(self): intrinsic = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "NotProd"]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_equals_nested_true(self): @@ -554,7 +554,7 @@ def test_fn_equals_nested_true(self): intrinsic_base_2 = {"Fn::Equals": [{"Ref": "AWS::AccountId"}, "123456789012"]} intrinsic = {"Fn::Equals": [intrinsic_base_1, intrinsic_base_2]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_equals_nested_false(self): @@ -562,7 +562,7 @@ def test_fn_equals_nested_false(self): intrinsic_base_2 = {"Fn::Equals": [{"Ref": "AWS::AccountId"}, "NOT_A_VALID_ACCOUNT_ID"]} intrinsic = {"Fn::Equals": [intrinsic_base_1, intrinsic_base_2]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) @parameterized.expand( @@ -573,7 +573,7 @@ def test_fn_equals_nested_false(self): ) def test_fn_equals_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Equals": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Equals": intrinsic}, True) @parameterized.expand( [ @@ -583,7 +583,7 @@ def test_fn_equals_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_equals_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Equals": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Equals": intrinsic}, True) class TestIntrinsicFnNotResolver(TestCase): @@ -599,12 +599,12 @@ def setUp(self): def test_fn_not_basic_false(self): intrinsic = {"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvironmentType"}, "prod"]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_not_basic_true(self): intrinsic = {"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvironmentType"}, "NotProd"]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_not_nested_true(self): @@ -612,7 +612,7 @@ def test_fn_not_nested_true(self): intrinsic_base_2 = {"Fn::Equals": [{"Ref": "AWS::AccountId"}, "123456789012"]} # !(True && True) intrinsic = {"Fn::Not": [{"Fn::Equals": [intrinsic_base_1, intrinsic_base_2]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_not_nested_false(self): @@ -620,17 +620,17 @@ def test_fn_not_nested_false(self): intrinsic_base_2 = {"Fn::Not": [{"Fn::Equals": [{"Ref": "AWS::AccountId"}, "123456789012"]}]} intrinsic = {"Fn::Not": [{"Fn::Equals": [intrinsic_base_1, intrinsic_base_2]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_not_condition_false(self): intrinsic = {"Fn::Not": [{"Condition": "TestCondition"}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_not_condition_true(self): intrinsic = {"Fn::Not": [{"Condition": "NotTestCondition"}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) @parameterized.expand( @@ -641,7 +641,7 @@ def test_fn_not_condition_true(self): ) def test_fn_not_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Not": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Not": intrinsic}, True) @parameterized.expand( [ @@ -651,7 +651,7 @@ def test_fn_not_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_not_first_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Not": [intrinsic]}) + self.resolver.intrinsic_property_resolver({"Fn::Not": [intrinsic]}, True) @parameterized.expand( [ @@ -661,11 +661,11 @@ def test_fn_not_first_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_not_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Not": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Not": intrinsic}, True) def test_fn_not_invalid_condition(self): with self.assertRaises(InvalidIntrinsicException, msg="Invalid Condition"): - self.resolver.intrinsic_property_resolver({"Fn::Not": [{"Condition": "NOT_VALID_CONDITION"}]}) + self.resolver.intrinsic_property_resolver({"Fn::Not": [{"Condition": "NOT_VALID_CONDITION"}]}, True) class TestIntrinsicFnAndResolver(TestCase): @@ -682,13 +682,13 @@ def setUp(self): def test_fn_and_basic_true(self): prod_fn_equals = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "prod"]} intrinsic = {"Fn::And": [prod_fn_equals, {"Condition": "TestCondition"}, prod_fn_equals]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_and_basic_false(self): prod_fn_equals = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "prod"]} intrinsic = {"Fn::And": [prod_fn_equals, {"Condition": "NotTestCondition"}, prod_fn_equals]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_and_nested_true(self): @@ -696,7 +696,7 @@ def test_fn_and_nested_true(self): intrinsic_base = {"Fn::And": [prod_fn_equals, {"Condition": "TestCondition"}, prod_fn_equals]} fn_not_intrinsic = {"Fn::Not": [{"Condition": "NotTestCondition"}]} intrinsic = {"Fn::And": [intrinsic_base, fn_not_intrinsic, prod_fn_equals]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_and_nested_false(self): @@ -704,7 +704,7 @@ def test_fn_and_nested_false(self): prod_fn_not_equals = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "NOT_EQUAL"]} intrinsic_base = {"Fn::And": [prod_fn_equals, {"Condition": "NotTestCondition"}, prod_fn_equals]} intrinsic = {"Fn::And": [{"Fn::Not": [intrinsic_base]}, prod_fn_not_equals]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) @parameterized.expand( @@ -715,7 +715,7 @@ def test_fn_and_nested_false(self): ) def test_fn_and_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::And": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::And": intrinsic}, True) @parameterized.expand( [ @@ -725,11 +725,11 @@ def test_fn_and_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_and_all_arguments_bool(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::And": [intrinsic, intrinsic, intrinsic]}) + self.resolver.intrinsic_property_resolver({"Fn::And": [intrinsic, intrinsic, intrinsic]}, True) def test_fn_and_invalid_condition(self): with self.assertRaises(InvalidIntrinsicException, msg="Invalid Condition"): - self.resolver.intrinsic_property_resolver({"Fn::And": [{"Condition": "NOT_VALID_CONDITION"}]}) + self.resolver.intrinsic_property_resolver({"Fn::And": [{"Condition": "NOT_VALID_CONDITION"}]}, True) class TestIntrinsicFnOrResolver(TestCase): @@ -747,12 +747,12 @@ def setUp(self): def test_fn_or_basic_true(self): prod_fn_equals = {"Fn::Equals": [{"Ref": "EnvironmentType"}, "prod"]} intrinsic = {"Fn::Or": [prod_fn_equals, {"Condition": "TestCondition"}, prod_fn_equals]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_or_basic_single_true(self): intrinsic = {"Fn::Or": [False, False, {"Condition": "TestCondition"}, False]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_or_basic_false(self): @@ -760,7 +760,7 @@ def test_fn_or_basic_false(self): intrinsic = { "Fn::Or": [{"Fn::Not": [prod_fn_equals]}, {"Condition": "NotTestCondition"}, {"Fn::Not": [prod_fn_equals]}] } - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_fn_or_nested_true(self): @@ -771,7 +771,7 @@ def test_fn_or_nested_true(self): intrinsic_base = {"Fn::Or": [prod_fn_equals, {"Condition": "TestCondition"}, prod_fn_equals]} fn_not_intrinsic = {"Fn::Not": [{"Condition": "NotTestCondition"}]} intrinsic = {"Fn::Or": [failed_intrinsic_or, intrinsic_base, fn_not_intrinsic, fn_not_intrinsic]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_or_nested_false(self): @@ -781,7 +781,7 @@ def test_fn_or_nested_false(self): } intrinsic_base = {"Fn::Or": [prod_fn_equals, {"Condition": "TestCondition"}, prod_fn_equals]} intrinsic = {"Fn::Or": [failed_intrinsic_or, {"Fn::Not": [intrinsic_base]}]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) @parameterized.expand( @@ -792,7 +792,7 @@ def test_fn_or_nested_false(self): ) def test_fn_or_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Or": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Or": intrinsic}, True) @parameterized.expand( [ @@ -802,11 +802,11 @@ def test_fn_or_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_or_all_arguments_bool(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Or": [intrinsic, intrinsic, intrinsic]}) + self.resolver.intrinsic_property_resolver({"Fn::Or": [intrinsic, intrinsic, intrinsic]}, True) def test_fn_or_invalid_condition(self): with self.assertRaises(InvalidIntrinsicException, msg="Invalid Condition"): - self.resolver.intrinsic_property_resolver({"Fn::Or": [{"Condition": "NOT_VALID_CONDITION"}]}) + self.resolver.intrinsic_property_resolver({"Fn::Or": [{"Condition": "NOT_VALID_CONDITION"}]}, True) class TestIntrinsicFnIfResolver(TestCase): @@ -824,13 +824,13 @@ def setUp(self): def test_fn_if_basic_true(self): intrinsic = {"Fn::If": ["TestCondition", True, False]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_fn_if_basic_false(self): intrinsic = {"Fn::If": ["NotTestCondition", True, False]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) def test_nested_fn_if_true(self): @@ -838,7 +838,7 @@ def test_nested_fn_if_true(self): intrinsic_base_2 = {"Fn::If": ["TestCondition", True, False]} intrinsic = {"Fn::If": ["TestCondition", intrinsic_base_2, intrinsic_base_1]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertTrue(result) def test_nested_fn_if_false(self): @@ -846,7 +846,7 @@ def test_nested_fn_if_false(self): intrinsic_base_2 = {"Fn::If": ["TestCondition", True, False]} intrinsic = {"Fn::If": ["TestCondition", intrinsic_base_1, intrinsic_base_2]} - result = self.resolver.intrinsic_property_resolver(intrinsic) + result = self.resolver.intrinsic_property_resolver(intrinsic, True) self.assertFalse(result) @parameterized.expand( @@ -857,7 +857,7 @@ def test_nested_fn_if_false(self): ) def test_fn_if_arguments_invalid_formats(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::If": intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::If": intrinsic}, True) @parameterized.expand( [ @@ -867,11 +867,11 @@ def test_fn_if_arguments_invalid_formats(self, name, intrinsic): ) def test_fn_if_condition_arguments_invalid_type(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::If": [intrinsic, True, False]}) + self.resolver.intrinsic_property_resolver({"Fn::If": [intrinsic, True, False]}, True) def test_fn_if_invalid_condition(self): with self.assertRaises(InvalidIntrinsicException, msg="Invalid Condition"): - self.resolver.intrinsic_property_resolver({"Fn::If": ["NOT_VALID_CONDITION", "test", "test"]}) + self.resolver.intrinsic_property_resolver({"Fn::If": ["NOT_VALID_CONDITION", "test", "test"]}, True) @parameterized.expand( [ @@ -881,11 +881,11 @@ def test_fn_if_invalid_condition(self): ) def test_fn_if_invalid_number_arguments(self, name, intrinsic): with self.assertRaises(InvalidIntrinsicException, msg=name): - self.resolver.intrinsic_property_resolver({"Fn::Not": ["TestCondition"] + intrinsic}) + self.resolver.intrinsic_property_resolver({"Fn::Not": ["TestCondition"] + intrinsic}, True) def test_fn_if_condition_not_bool_fail(self): with self.assertRaises(InvalidIntrinsicException, msg="Invalid Condition"): - self.resolver.intrinsic_property_resolver({"Fn::If": ["InvalidCondition", "test", "test"]}) + self.resolver.intrinsic_property_resolver({"Fn::If": ["InvalidCondition", "test", "test"]}, True) class TestIntrinsicAttribteResolution(TestCase): @@ -986,15 +986,8 @@ def test_template_ignore_errors(self): }, "Type": "AWS::Lambda::Function", }, - "RestApi.Deployment": { - "Properties": { - "Body": { - "Fn::Base64": { - "Fn::Join": [";", {"Fn::Split": [",", {"Fn::Join": [",", ["a", "e", "f", "d"]]}]}] # NOQA - } - }, - "BodyS3Location": {"Fn::FindInMap": []}, - }, + "RestApi": { + "Properties": {"Body": "YTtlO2Y7ZA==", "BodyS3Location": {"Fn::FindInMap": []}}, "Type": "AWS::ApiGateway::RestApi", }, "RestApiResource": {"Properties": {"PathPart": "{proxy+}", "RestApiId": "RestApi", "parentId": "/"}},