Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.

Commit 478dbcf

Browse files
authored
CFN: add validation in GetAtt for conditionally canceled resources (#13213)
1 parent ae41d25 commit 478dbcf

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,21 @@ def _resolve_attribute(self, arguments: str | list[str], select_before: bool) ->
572572
resource_name=logical_name_of_resource,
573573
node_template=self._change_set.update_model.node_template,
574574
)
575+
576+
if not is_nothing(node_resource.condition_reference):
577+
condition = self._get_node_condition_if_exists(node_resource.condition_reference.value)
578+
evaluation_result = self._resolve_condition(condition.name)
579+
580+
if select_before and not evaluation_result.before:
581+
raise ValidationError(
582+
f"Template format error: Unresolved resource dependencies [{logical_name_of_resource}] in the Resources block of the template"
583+
)
584+
585+
if not select_before and not evaluation_result.after:
586+
raise ValidationError(
587+
f"Template format error: Unresolved resource dependencies [{logical_name_of_resource}] in the Resources block of the template"
588+
)
589+
575590
node_property: NodeProperty | None = self._get_node_property_for(
576591
property_name=attribute_name, node_resource=node_resource
577592
)

tests/aws/services/cloudformation/engine/test_conditions.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os.path
22

33
import pytest
4+
from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine
45

56
from localstack.services.cloudformation.v2.utils import is_v2_engine
67
from localstack.testing.aws.util import is_aws_cloud
@@ -125,6 +126,32 @@ def test_dependent_ref(self, aws_client, snapshot):
125126
)
126127
snapshot.match("dependent_ref_exc", e.value.response)
127128

129+
@markers.aws.validated
130+
@skip_if_legacy_engine
131+
def test_dependent_get_att(self, aws_client, snapshot):
132+
"""
133+
Tests behavior of a stack with 2 resources where one depends on the other.
134+
The referenced resource won't be deployed due to its condition evaluating to false, so the GetAtt can't be resolved.
135+
136+
This immediately leads to an error.
137+
"""
138+
139+
stack_name = f"test-condition-ref-stack-{short_uid()}"
140+
changeset_name = "initial"
141+
with pytest.raises(aws_client.cloudformation.exceptions.ClientError) as e:
142+
aws_client.cloudformation.create_change_set(
143+
StackName=stack_name,
144+
ChangeSetName=changeset_name,
145+
ChangeSetType="CREATE",
146+
TemplateBody=load_file(
147+
os.path.join(THIS_DIR, "../../../templates/conditions/get-att-condition.yml")
148+
),
149+
Parameters=[
150+
{"ParameterKey": "OptionParameter", "ParameterValue": "option-b"},
151+
],
152+
)
153+
snapshot.match("dependent_ref_exc", e.value.response)
154+
128155
@markers.aws.validated
129156
@pytest.mark.skipif(condition=not is_aws_cloud(), reason="not supported yet")
130157
def test_dependent_ref_intrinsic_fn_condition(self, aws_client, deploy_cfn_template):

tests/aws/services/cloudformation/engine/test_conditions.snapshot.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,5 +759,21 @@
759759
}
760760
}
761761
}
762+
},
763+
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_get_att": {
764+
"recorded-date": "30-09-2025, 19:25:10",
765+
"recorded-content": {
766+
"dependent_ref_exc": {
767+
"Error": {
768+
"Code": "ValidationError",
769+
"Message": "Template format error: Unresolved resource dependencies [MyTopic] in the Resources block of the template",
770+
"Type": "Sender"
771+
},
772+
"ResponseMetadata": {
773+
"HTTPHeaders": {},
774+
"HTTPStatusCode": 400
775+
}
776+
}
777+
}
762778
}
763779
}

tests/aws/services/cloudformation/engine/test_conditions.validation.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
{
2+
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_get_att": {
3+
"last_validated_date": "2025-09-30T19:25:10+00:00",
4+
"durations_in_seconds": {
5+
"setup": 0.23,
6+
"call": 0.36,
7+
"teardown": 0.0,
8+
"total": 0.59
9+
}
10+
},
211
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref": {
3-
"last_validated_date": "2023-06-26T12:18:26+00:00"
12+
"last_validated_date": "2025-09-30T19:03:49+00:00",
13+
"durations_in_seconds": {
14+
"setup": 0.27,
15+
"call": 0.34,
16+
"teardown": 0.0,
17+
"total": 0.61
18+
}
419
},
520
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[prod-bucket-policy]": {
621
"last_validated_date": "2023-06-26T12:24:03+00:00"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Parameters:
2+
OptionParameter:
3+
Type: String
4+
AllowedValues:
5+
- option-a
6+
- option-b
7+
Resources:
8+
MyTopic:
9+
Type: AWS::SNS::Topic
10+
Condition: ShouldCreateTopic
11+
12+
MySsmParam:
13+
Type: AWS::SSM::Parameter
14+
Properties:
15+
Type: String
16+
Value: !GetAtt MyTopic.TopicName
17+
18+
Conditions:
19+
ShouldCreateTopic: !Equals
20+
- !Ref OptionParameter
21+
- option-a

0 commit comments

Comments
 (0)