Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1263,13 +1263,25 @@ def visit_node_resource(
depends_on_after = depends_on_delta.after

type_delta = self.visit(node_resource.type_)
properties_delta: PreprocEntityDelta[PreprocProperties, PreprocProperties] = self.visit(
node_resource.properties

# Check conditions before visiting properties to avoid resolving references
# (e.g. GetAtt) to conditional resources that were never created.
should_process_before = change_type != ChangeType.CREATED and (
is_nothing(condition_before) or condition_before
)
should_process_after = change_type != ChangeType.REMOVED and (
is_nothing(condition_after) or condition_after
)

properties_delta: PreprocEntityDelta[PreprocProperties, PreprocProperties]
if should_process_before or should_process_after:
properties_delta = self.visit(node_resource.properties)
else:
properties_delta = PreprocEntityDelta(before=Nothing, after=Nothing)

before = Nothing
after = Nothing
if change_type != ChangeType.CREATED and is_nothing(condition_before) or condition_before:
if should_process_before:
logical_resource_id = node_resource.name
before_physical_resource_id = self._before_resource_physical_id(
resource_logical_id=logical_resource_id
Expand All @@ -1283,7 +1295,7 @@ def visit_node_resource(
depends_on=depends_on_before,
requires_replacement=False,
)
if change_type != ChangeType.REMOVED and is_nothing(condition_after) or condition_after:
if should_process_after:
logical_resource_id = node_resource.name
try:
after_physical_resource_id = self._after_resource_physical_id(
Expand Down
26 changes: 26 additions & 0 deletions tests/aws/services/cloudformation/engine/test_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,32 @@ def test_references_to_disabled_resources(
)
snapshot.match("resources-description", describe_resources)

@markers.aws.validated
@skip_if_legacy_engine()
def test_conditional_resource_referencing_conditional(
self, deploy_cfn_template, aws_client, snapshot
):
"""
Test that a template with a conditional resource referencing another conditional
resource via !GetAtt is accepted and deploys correctly when conditions are false.
"""
snapshot.add_transformer(
SortingTransformer("StackResources", lambda e: e["LogicalResourceId"])
)
snapshot.add_transformer(snapshot.transform.key_value("PhysicalResourceId"))
snapshot.add_transformer(snapshot.transform.cloudformation_api())

stack = deploy_cfn_template(
template_path=os.path.join(
os.path.dirname(__file__),
"../../../templates/conditions/conditional-resource-getatt-delete.yaml",
),
parameters={"EnableQueue": "false"},
)

resources = aws_client.cloudformation.describe_stack_resources(StackName=stack.stack_id)
snapshot.match("resources-description", resources)


class TestValidateConditions:
@markers.aws.validated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -949,5 +949,30 @@
}
}
}
},
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_resource_referencing_conditional": {
"recorded-date": "04-02-2026, 01:53:15",
"recorded-content": {
"resources-description": {
"StackResources": [
{
"DriftInformation": {
"StackResourceDriftStatus": "NOT_CHECKED"
},
"LogicalResourceId": "MyTable",
"PhysicalResourceId": "<physical-resource-id:1>",
"ResourceStatus": "CREATE_COMPLETE",
"ResourceType": "AWS::DynamoDB::Table",
"StackId": "arn:<partition>:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:1>",
"StackName": "<stack-name:1>",
"Timestamp": "timestamp"
}
],
"ResponseMetadata": {
"HTTPHeaders": {},
"HTTPStatusCode": 200
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_resource_referencing_conditional": {
"last_validated_date": "2026-02-04T01:53:29+00:00",
"durations_in_seconds": {
"setup": 0.7,
"call": 23.45,
"teardown": 14.46,
"total": 38.61
}
},
"tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_get_att": {
"last_validated_date": "2025-09-30T19:25:10+00:00",
"durations_in_seconds": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
AWSTemplateFormatVersion: '2010-09-09'

Parameters:
EnableQueue:
Type: String
Default: 'false'
AllowedValues: ['true', 'false']

Conditions:
CreateQueue: !Equals [!Ref EnableQueue, 'true']

Resources:
MyTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub '${AWS::StackName}-table'
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: PK
AttributeType: S
KeySchema:
- AttributeName: PK
KeyType: HASH

MyQueue:
Type: AWS::SQS::Queue
Condition: CreateQueue

MyAlarm:
Type: AWS::CloudWatch::Alarm
Condition: CreateQueue
Properties:
AlarmName: !Sub '${AWS::StackName}-alarm'
MetricName: ApproximateNumberOfMessagesVisible
Namespace: AWS/SQS
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 100
ComparisonOperator: GreaterThanThreshold
Dimensions:
- Name: QueueName
Value: !GetAtt MyQueue.QueueName
Loading