@@ -119,6 +119,133 @@ def test_short_circuit_on_empty_parameters(self):
119119        self .assertEqual (resolver .resolve_parameter_refs (input ), expected )
120120        resolver ._try_resolve_parameter_refs .assert_not_called ()
121121
122+     def  test_cloudformation_internal_placeholder_not_resolved (self ):
123+         """Test that CloudFormation internal placeholders are not resolved""" 
124+         parameter_values  =  {
125+             "UserPoolArn" : "{{IntrinsicFunction:debugging-cloudformation-issues4/Cognito.Outputs.UserPoolArn/Fn::GetAtt}}" ,
126+             "NormalParam" : "normal-value" ,
127+         }
128+         resolver  =  IntrinsicsResolver (parameter_values )
129+ 
130+         # CloudFormation placeholder should not be resolved 
131+         input1  =  {"Ref" : "UserPoolArn" }
132+         expected1  =  {"Ref" : "UserPoolArn" }
133+         output1  =  resolver .resolve_parameter_refs (input1 )
134+         self .assertEqual (output1 , expected1 )
135+ 
136+         # Normal parameter should still be resolved 
137+         input2  =  {"Ref" : "NormalParam" }
138+         expected2  =  "normal-value" 
139+         output2  =  resolver .resolve_parameter_refs (input2 )
140+         self .assertEqual (output2 , expected2 )
141+ 
142+     def  test_cloudformation_placeholders_in_nested_structure (self ):
143+         """Test CloudFormation placeholders in nested structures""" 
144+         parameter_values  =  {
145+             "Placeholder1" : "{{IntrinsicFunction:stack/Output1/Fn::GetAtt}}" ,
146+             "Placeholder2" : "{{IntrinsicFunction:stack/Output2/Fn::GetAtt}}" ,
147+             "NormalParam" : "value" ,
148+         }
149+         resolver  =  IntrinsicsResolver (parameter_values )
150+ 
151+         input  =  {
152+             "Resources" : {
153+                 "Resource1" : {
154+                     "Properties" : {
155+                         "Prop1" : {"Ref" : "Placeholder1" },
156+                         "Prop2" : {"Ref" : "NormalParam" },
157+                         "Prop3" : {"Ref" : "Placeholder2" },
158+                     }
159+                 }
160+             }
161+         }
162+ 
163+         expected  =  {
164+             "Resources" : {
165+                 "Resource1" : {
166+                     "Properties" : {
167+                         "Prop1" : {"Ref" : "Placeholder1" },  # Not resolved 
168+                         "Prop2" : "value" ,  # Resolved 
169+                         "Prop3" : {"Ref" : "Placeholder2" },  # Not resolved 
170+                     }
171+                 }
172+             }
173+         }
174+ 
175+         output  =  resolver .resolve_parameter_refs (input )
176+         self .assertEqual (output , expected )
177+ 
178+     def  test_cloudformation_placeholders_in_lists (self ):
179+         """Test CloudFormation placeholders in list structures""" 
180+         parameter_values  =  {
181+             "VpceId" : "{{IntrinsicFunction:stack/VpcEndpoint.Outputs.Id/Fn::GetAtt}}" ,
182+             "Region" : "us-east-1" ,
183+         }
184+         resolver  =  IntrinsicsResolver (parameter_values )
185+ 
186+         input  =  [{"Ref" : "VpceId" }, {"Ref" : "Region" }, "static-value" , {"Ref" : "VpceId" }]
187+ 
188+         expected  =  [
189+             {"Ref" : "VpceId" },  # Not resolved 
190+             "us-east-1" ,  # Resolved 
191+             "static-value" ,
192+             {"Ref" : "VpceId" },  # Not resolved 
193+         ]
194+ 
195+         output  =  resolver .resolve_parameter_refs (input )
196+         self .assertEqual (output , expected )
197+ 
198+     def  test_cloudformation_placeholders_with_sub (self ):
199+         """Test that CloudFormation placeholders inside Fn::Sub are not substituted 
200+ 
201+         Similar to Ref, Fn::Sub should not substitute CloudFormation internal placeholders. 
202+         This prevents the placeholders from being embedded in strings where they can't be 
203+         properly handled by CloudFormation. 
204+         """ 
205+         parameter_values  =  {
206+             "Placeholder" : "{{IntrinsicFunction:stack/Output/Fn::GetAtt}}" ,
207+             "NormalParam" : "normal-value" ,
208+         }
209+         resolver  =  IntrinsicsResolver (parameter_values )
210+ 
211+         # Sub should not substitute CloudFormation placeholders, but should substitute normal params 
212+         input  =  {"Fn::Sub" : "Value is ${Placeholder} and ${NormalParam}" }
213+         expected  =  {"Fn::Sub" : "Value is ${Placeholder} and normal-value" }
214+ 
215+         output  =  resolver .resolve_parameter_refs (input )
216+         self .assertEqual (output , expected )
217+ 
218+     def  test_various_cloudformation_placeholder_formats (self ):
219+         """Test various CloudFormation placeholder formats""" 
220+         parameter_values  =  {
221+             "Valid1" : "{{IntrinsicFunction:stack/Resource.Outputs.Value/Fn::GetAtt}}" ,
222+             "Valid2" : "{{IntrinsicFunction:name-with-dashes/Out/Fn::GetAtt}}" ,
223+             "Valid3" : "{{IntrinsicFunction:stack123/Resource.Out/Fn::GetAtt}}" ,
224+             "NotPlaceholder1" : "{{SomethingElse}}" ,
225+             "NotPlaceholder2" : "{{intrinsicfunction:lowercase}}" ,
226+             "NotPlaceholder3" : "normal-string" ,
227+         }
228+         resolver  =  IntrinsicsResolver (parameter_values )
229+ 
230+         # Valid placeholders should not be resolved 
231+         for  param  in  ["Valid1" , "Valid2" , "Valid3" ]:
232+             input  =  {"Ref" : param }
233+             expected  =  {"Ref" : param }
234+             output  =  resolver .resolve_parameter_refs (input )
235+             self .assertEqual (output , expected , f"Failed for { param }  )
236+ 
237+         # Non-placeholders should be resolved 
238+         test_cases  =  [
239+             ("NotPlaceholder1" , "{{SomethingElse}}" ),
240+             ("NotPlaceholder2" , "{{intrinsicfunction:lowercase}}" ),
241+             ("NotPlaceholder3" , "normal-string" ),
242+         ]
243+ 
244+         for  param , expected_value  in  test_cases :
245+             input  =  {"Ref" : param }
246+             output  =  resolver .resolve_parameter_refs (input )
247+             self .assertEqual (output , expected_value , f"Failed for { param }  )
248+ 
122249
123250class  TestResourceReferenceResolution (TestCase ):
124251    def  setUp (self ):
0 commit comments