From f58f5a754a2b7f22e41d1ac3263d841d693fd9af Mon Sep 17 00:00:00 2001 From: drauedo Date: Wed, 2 Sep 2026 14:56:35 +0200 Subject: [PATCH] EC2: Honor TagSpecifications in CreateTransitGatewayVpcAttachment The create_transit_gateway_vpc_attachment response handler looked up the parsed TagSpecifications under the "transit-gateway-route-table" resource type (copy-pasted from the route table handler), so tags passed at creation time were silently dropped and only tags added later via CreateTags showed up in DescribeTransitGatewayVpcAttachments / DescribeTransitGatewayAttachments. Use the correct "transit-gateway-attachment" resource type (matching EC2_RESOURCE_TO_PREFIX) and add an aws_verified test covering create-time tags on both describe calls plus merging with tags added via CreateTags. Fixes SUP-138. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01JrkEvTCFkudp83ifsALDe9 --- .../responses/transit_gateway_attachments.py | 2 +- tests/test_ec2/test_transit_gateway.py | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/moto/ec2/responses/transit_gateway_attachments.py b/moto/ec2/responses/transit_gateway_attachments.py index 48c49a5b997c..48b901de7feb 100644 --- a/moto/ec2/responses/transit_gateway_attachments.py +++ b/moto/ec2/responses/transit_gateway_attachments.py @@ -10,7 +10,7 @@ def create_transit_gateway_vpc_attachment(self) -> str: transit_gateway_id = self._get_param("TransitGatewayId") vpc_id = self._get_param("VpcId") - tags = self._parse_tag_specification().get("transit-gateway-route-table", {}) + tags = self._parse_tag_specification().get("transit-gateway-attachment", {}) transit_gateway_attachment = ( self.ec2_backend.create_transit_gateway_vpc_attachment( diff --git a/tests/test_ec2/test_transit_gateway.py b/tests/test_ec2/test_transit_gateway.py index e9783eacc3de..6acd762c951b 100644 --- a/tests/test_ec2/test_transit_gateway.py +++ b/tests/test_ec2/test_transit_gateway.py @@ -1,5 +1,6 @@ from time import sleep from unittest import SkipTest +from uuid import uuid4 import boto3 import pytest @@ -629,6 +630,61 @@ def test_create_transit_gateway_vpc_attachment(): assert "Tags" not in attachment +@pytest.mark.aws_verified +@ec2_aws_verified(create_vpc=True, create_subnet=True, create_transit_gateway=True) +def test_create_transit_gateway_vpc_attachment_with_tags( + account_id, ec2_client=None, vpc_id=None, subnet_id=None, tg_id=None +): + name_tag = {"Key": "Name", "Value": f"my-attachment-{uuid4()}"} + team_tag = {"Key": "Team", "Value": f"platform-{uuid4()}"} + env_tag = {"Key": "Env", "Value": f"test-{uuid4()}"} + + response = ec2_client.create_transit_gateway_vpc_attachment( + TransitGatewayId=tg_id, + VpcId=vpc_id, + SubnetIds=[subnet_id], + TagSpecifications=[ + { + "ResourceType": "transit-gateway-attachment", + "Tags": [name_tag, team_tag], + } + ], + ) + create = response["TransitGatewayVpcAttachment"] + tg_attachment_id = create["TransitGatewayAttachmentId"] + # AWS returns 'pending' - Moto is immediately 'available', so don't assert on State + assert len(create["Tags"]) == 2 + assert name_tag in create["Tags"] + assert team_tag in create["Tags"] + + # Wait until the attachment is fully ready + wait_for_transit_gateway_attachments(ec2_client, tg_attachment_id=tg_attachment_id) + + vpc_attachment = ec2_client.describe_transit_gateway_vpc_attachments( + TransitGatewayAttachmentIds=[tg_attachment_id] + )["TransitGatewayVpcAttachments"][0] + assert len(vpc_attachment["Tags"]) == 2 + assert name_tag in vpc_attachment["Tags"] + assert team_tag in vpc_attachment["Tags"] + + tg_attachment = ec2_client.describe_transit_gateway_attachments( + TransitGatewayAttachmentIds=[tg_attachment_id] + )["TransitGatewayAttachments"][0] + assert len(tg_attachment["Tags"]) == 2 + assert name_tag in tg_attachment["Tags"] + assert team_tag in tg_attachment["Tags"] + + # Tags added after creation are merged with the create-time tags + ec2_client.create_tags(Resources=[tg_attachment_id], Tags=[env_tag]) + vpc_attachment = ec2_client.describe_transit_gateway_vpc_attachments( + TransitGatewayAttachmentIds=[tg_attachment_id] + )["TransitGatewayVpcAttachments"][0] + assert len(vpc_attachment["Tags"]) == 3 + assert name_tag in vpc_attachment["Tags"] + assert team_tag in vpc_attachment["Tags"] + assert env_tag in vpc_attachment["Tags"] + + @mock_aws def test_modify_transit_gateway_vpc_attachment_add_subnets(): ec2 = boto3.client("ec2", region_name="us-west-1")