diff --git a/CHANGELOG.v2.alpha.md b/CHANGELOG.v2.alpha.md index 433670e7ec04c..b06628880c00e 100644 --- a/CHANGELOG.v2.alpha.md +++ b/CHANGELOG.v2.alpha.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.118.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.117.0-alpha.0...v2.118.0-alpha.0) (2024-01-03) + + +### Features + +* **glue:** database description property ([#27744](https://github.com/aws/aws-cdk/issues/27744)) ([cbac240](https://github.com/aws/aws-cdk/commit/cbac24041db7dbc39b4ae1d6da4902b3443528cb)), closes [#27740](https://github.com/aws/aws-cdk/issues/27740) +* **glue-alpha:** add `cfn-glue-table-tableinput-parameters` to Glue table construct ([#27643](https://github.com/aws/aws-cdk/issues/27643)) ([8e15482](https://github.com/aws/aws-cdk/commit/8e15482295c1324eefea020faeb11e4c686357c6)) + + +### Bug Fixes + +* **lambda-go:** path with space breaks go build ([#28554](https://github.com/aws/aws-cdk/issues/28554)) ([a8a639e](https://github.com/aws/aws-cdk/commit/a8a639e2a2114162db240361c32c40a596a7a19e)), closes [#28555](https://github.com/aws/aws-cdk/issues/28555) + ## [2.117.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.116.1-alpha.0...v2.117.0-alpha.0) (2023-12-26) diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index b9ddd965bf06c..a8d8af671f837 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,6 +2,36 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.118.0](https://github.com/aws/aws-cdk/compare/v2.117.0...v2.118.0) (2024-01-03) + + +### Features + +* **appsync:** IntrospectionConfig property ([#28500](https://github.com/aws/aws-cdk/issues/28500)) ([98ed6b3](https://github.com/aws/aws-cdk/commit/98ed6b3346e4afd423592296bb1620d20544acad)), closes [#28429](https://github.com/aws/aws-cdk/issues/28429) +* **autoscaling:** add support for `InstanceRequirements` property ([#28464](https://github.com/aws/aws-cdk/issues/28464)) ([276e3a6](https://github.com/aws/aws-cdk/commit/276e3a66febf32afc65a93d7296ec6be8f6e2126)), closes [#28393](https://github.com/aws/aws-cdk/issues/28393) +* **cloudfront:** CloudFront Function runtime property ([#28099](https://github.com/aws/aws-cdk/issues/28099)) ([9b466ae](https://github.com/aws/aws-cdk/commit/9b466ae136910d07d4297a31f1010fa26ce864d0)), closes [#28163](https://github.com/aws/aws-cdk/issues/28163) +* **cloudfront:** Key Value Store L2 ([#28473](https://github.com/aws/aws-cdk/issues/28473)) ([030db42](https://github.com/aws/aws-cdk/commit/030db42ad06a471af3833665cb80dceee034aa02)), closes [#28377](https://github.com/aws/aws-cdk/issues/28377) +* **codepipeline-actions:** more convenient methods to `CacheControl` ([#28491](https://github.com/aws/aws-cdk/issues/28491)) ([a59dc0c](https://github.com/aws/aws-cdk/commit/a59dc0cb79af98ee601f352a7cf1b5fa9cc4d365)), closes [#25477](https://github.com/aws/aws-cdk/issues/25477) +* **ecs:** `interactive` option in `ContainerDefinitionOptions` ([#28536](https://github.com/aws/aws-cdk/issues/28536)) ([1f9788f](https://github.com/aws/aws-cdk/commit/1f9788f8ad45c0f159c9b7e6bafb76763e9b0bea)), closes [#24326](https://github.com/aws/aws-cdk/issues/24326) +* **ecs:** enable cluster to grant task protection API permissions to IAM entities ([#28486](https://github.com/aws/aws-cdk/issues/28486)) ([9bc972b](https://github.com/aws/aws-cdk/commit/9bc972b923b66248fb8392e9cba1b2b5829c6e1b)), closes [#26233](https://github.com/aws/aws-cdk/issues/26233) +* **ecs:** nvidia support to BottlerocketEcsVariant enum for gpu-accelerated tasks ([#28488](https://github.com/aws/aws-cdk/issues/28488)) ([832e29a](https://github.com/aws/aws-cdk/commit/832e29a47c2cb67558c0148a3bf1fa22e4d5cb82)), closes [#25980](https://github.com/aws/aws-cdk/issues/25980) +* **iam:** validate roleName ([#28509](https://github.com/aws/aws-cdk/issues/28509)) ([999c01a](https://github.com/aws/aws-cdk/commit/999c01a1250308b482fe33e651d7ee8da1f96956)), closes [#28502](https://github.com/aws/aws-cdk/issues/28502) +* **opensearchservice:** ip address type for domain ([#28497](https://github.com/aws/aws-cdk/issues/28497)) ([6b80338](https://github.com/aws/aws-cdk/commit/6b80338be59bdfa1d14d81fa1ae79f2eda889b37)), closes [#28436](https://github.com/aws/aws-cdk/issues/28436) +* **rds:** `timeout` and `timeoutAction` properties to ServerlessCluster ([#28534](https://github.com/aws/aws-cdk/issues/28534)) ([508825b](https://github.com/aws/aws-cdk/commit/508825b14d6ccae7274afc08487329162182e887)), closes [#27183](https://github.com/aws/aws-cdk/issues/27183) +* **rds:** ClientPasswordAuthType property on DatabaseProxy ([#28540](https://github.com/aws/aws-cdk/issues/28540)) ([669e6ff](https://github.com/aws/aws-cdk/commit/669e6ffc6e9d8c7b06cb0f62348635f933b6f823)), closes [#28415](https://github.com/aws/aws-cdk/issues/28415) +* **rds:** new Aurora Postgres engine versions ([#28508](https://github.com/aws/aws-cdk/issues/28508)) ([9d8b06f](https://github.com/aws/aws-cdk/commit/9d8b06f6478a98e01e3aaa86c1dbf22d6e861f05)) +* **stepfunctions-tasks:** add `timeout` parameter for EmrCreateCluster ([#28532](https://github.com/aws/aws-cdk/issues/28532)) ([ca91626](https://github.com/aws/aws-cdk/commit/ca91626327ac4a138adc16026d951f21fadf86a3)), closes [/github.com/aws/aws-cdk/pull/28529#discussion_r1438587964](https://github.com/aws//github.com/aws/aws-cdk/pull/28529/issues/discussion_r1438587964) +* **stepfunctions-tasks:** add validations for EmrCreateCluster ([#28529](https://github.com/aws/aws-cdk/issues/28529)) ([e0b725c](https://github.com/aws/aws-cdk/commit/e0b725cd39a01a8387dcf28921e0912552eb7fce)) +* **stepfunctions-tasks:** additional allocation strategies for spot instance fleets in EmrCreateCluster ([#28525](https://github.com/aws/aws-cdk/issues/28525)) ([94003ec](https://github.com/aws/aws-cdk/commit/94003ecb056e56623aa6621a2d013c1a7e3dcebe)) + + +### Bug Fixes + +* **cli:** direct deploy method fails when there are no updates ([#28523](https://github.com/aws/aws-cdk/issues/28523)) ([dde5975](https://github.com/aws/aws-cdk/commit/dde59755cb71aee73a58f3b2c2068f2ae01e9b72)), closes [/github.com/aws/aws-cdk/blob/9d8b06f6478a98e01e3aaa86c1dbf22d6e861f05/packages/aws-cdk/lib/api/util/cloudformation.ts#L290-L296](https://github.com/aws//github.com/aws/aws-cdk/blob/9d8b06f6478a98e01e3aaa86c1dbf22d6e861f05/packages/aws-cdk/lib/api/util/cloudformation.ts/issues/L290-L296) +* **events:** event bus fails with duplicate policy resource ([#28521](https://github.com/aws/aws-cdk/issues/28521)) ([166967f](https://github.com/aws/aws-cdk/commit/166967f11727a28fc11b9af5de0fad6da2a4ad64)), closes [#27340](https://github.com/aws/aws-cdk/issues/27340) [#28520](https://github.com/aws/aws-cdk/issues/28520) +* **iam:** withConditions overrides Principal actions ([#28510](https://github.com/aws/aws-cdk/issues/28510)) ([0b345c5](https://github.com/aws/aws-cdk/commit/0b345c5a98a61ae7a587e5578ffdfc69885bb676)), closes [#28426](https://github.com/aws/aws-cdk/issues/28426) +* **rds:** circular dependencies when creating multiple DatabaseProxies ([#28471](https://github.com/aws/aws-cdk/issues/28471)) ([a12d9eb](https://github.com/aws/aws-cdk/commit/a12d9eb75cc110657a73c6cb82399d572696d36e)), closes [/github.com/aws/aws-cdk/blob/cd54c4239ec29182e30fd91634505df560d6e5f8/packages/aws-cdk-lib/aws-rds/lib/cluster.ts#L446](https://github.com/aws//github.com/aws/aws-cdk/blob/cd54c4239ec29182e30fd91634505df560d6e5f8/packages/aws-cdk-lib/aws-rds/lib/cluster.ts/issues/L446) [#25633](https://github.com/aws/aws-cdk/issues/25633) + ## [2.117.0](https://github.com/aws/aws-cdk/compare/v2.116.1...v2.117.0) (2023-12-26) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.js.snapshot/aws-cdk-rds-proxy.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.js.snapshot/aws-cdk-rds-proxy.template.json index a7fff003e31a9..21aa37f0796d9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.js.snapshot/aws-cdk-rds-proxy.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.js.snapshot/aws-cdk-rds-proxy.template.json @@ -601,6 +601,7 @@ "Auth": [ { "AuthScheme": "SECRETS", + "ClientPasswordAuthType": "POSTGRES_SCRAM_SHA_256", "IAMAuth": "DISABLED", "SecretArn": { "Ref": "dbInstanceSecretAttachment88CFBDAE" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.ts index 8b8164175d258..f293338ee941e 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy.ts @@ -27,6 +27,7 @@ new rds.DatabaseProxy(stack, 'dbProxy', { secrets: [dbInstance.secret!], proxyTarget: rds.ProxyTarget.fromInstance(dbInstance), vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.POSTGRES_SCRAM_SHA_256, }); const cluster = new rds.DatabaseCluster(stack, 'dbCluster', { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.assets.json new file mode 100644 index 0000000000000..f6fd03ebdf483 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "39bf1ae788d29e6def2af02690b18b4dd491662b26b445a93f9b8994e6f18990": { + "source": { + "path": "aws-cdk-rds-integ.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "39bf1ae788d29e6def2af02690b18b4dd491662b26b445a93f9b8994e6f18990.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.template.json new file mode 100644 index 0000000000000..e6f73b657f48c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/aws-cdk-rds-integ.template.json @@ -0,0 +1,519 @@ +{ + "Resources": { + "VPCB9E5F0B4": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC" + } + ] + } + }, + "VPCPublicSubnet1SubnetB4246D30": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableFEE4B781": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet1RouteTableAssociation0B0896DC": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "VPCPublicSubnet1DefaultRoute91CEF279": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet1EIP6AD938E8": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ] + } + }, + "VPCPublicSubnet1NATGatewayE0556630": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet1DefaultRoute91CEF279", + "VPCPublicSubnet1RouteTableAssociation0B0896DC" + ] + }, + "VPCPublicSubnet2Subnet74179F39": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTable6F1A15F1": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPublicSubnet2RouteTableAssociation5A808732": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "VPCPublicSubnet2DefaultRouteB7481BBA": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "RouteTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + }, + "DependsOn": [ + "VPCVPCGW99B986DC" + ] + }, + "VPCPublicSubnet2EIP4947BC00": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ] + } + }, + "VPCPublicSubnet2NATGateway3C070193": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "AllocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "SubnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "VPCPublicSubnet2DefaultRouteB7481BBA", + "VPCPublicSubnet2RouteTableAssociation5A808732" + ] + }, + "VPCPrivateSubnet1Subnet8BCA10E0": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableBE8A6027": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet1RouteTableAssociation347902D1": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "VPCPrivateSubnet1DefaultRouteAE1D6490": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "VPCPrivateSubnet2SubnetCFCDAA7A": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTable0A19E10E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "VPCPrivateSubnet2RouteTableAssociation0C73D413": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "SubnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "VPCPrivateSubnet2DefaultRouteF4F5CFD2": { + "Type": "AWS::EC2::Route", + "Properties": { + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "RouteTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "VPCIGWB7E252D3": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-integ/VPC" + } + ] + } + }, + "VPCVPCGW99B986DC": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "InternetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "SubnetGroup": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "My Subnet Group", + "DBSubnetGroupName": "mynotlowercasesubnetgroupname", + "SubnetIds": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ] + } + }, + "ServerlessDatabaseSecurityGroup1E143FBB": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "RDS security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "ServerlessDatabaseSecurityGroupfrom00000IndirectPortE0823E20": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "CidrIp": "0.0.0.0/0", + "Description": "Open to the world", + "FromPort": { + "Fn::GetAtt": [ + "ServerlessDatabaseDF340AE1", + "Endpoint.Port" + ] + }, + "GroupId": { + "Fn::GetAtt": [ + "ServerlessDatabaseSecurityGroup1E143FBB", + "GroupId" + ] + }, + "IpProtocol": "tcp", + "ToPort": { + "Fn::GetAtt": [ + "ServerlessDatabaseDF340AE1", + "Endpoint.Port" + ] + } + } + }, + "ServerlessDatabaseDF340AE1": { + "Type": "AWS::RDS::DBCluster", + "Properties": { + "CopyTagsToSnapshot": true, + "DBClusterParameterGroupName": "default.aurora-mysql5.7", + "DBSubnetGroupName": { + "Ref": "SubnetGroup" + }, + "Engine": "aurora-mysql", + "EngineMode": "serverless", + "MasterUserPassword": "7959866cacc02c2d243ecfe177464fe6", + "MasterUsername": "admin", + "ScalingConfiguration": { + "AutoPause": true, + "MaxCapacity": 32, + "MinCapacity": 8, + "SecondsBeforeTimeout": 480, + "SecondsUntilAutoPause": 300, + "TimeoutAction": "ForceApplyCapacityChange" + }, + "StorageEncrypted": true, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ServerlessDatabaseSecurityGroup1E143FBB", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets.json new file mode 100644 index 0000000000000..232acc8646e99 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "clusterdualtestDefaultTestDeployAssert0AE5E6E0.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/clusterdualtestDefaultTestDeployAssert0AE5E6E0.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/integ.json new file mode 100644 index 0000000000000..039efe0554cd9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "cluster-dual-test/DefaultTest": { + "stacks": [ + "aws-cdk-rds-integ" + ], + "assertionStack": "cluster-dual-test/DefaultTest/DeployAssert", + "assertionStackName": "clusterdualtestDefaultTestDeployAssert0AE5E6E0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/manifest.json new file mode 100644 index 0000000000000..08214114a2f09 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/manifest.json @@ -0,0 +1,269 @@ +{ + "version": "36.0.0", + "artifacts": { + "aws-cdk-rds-integ.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-rds-integ.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-rds-integ": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-rds-integ.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/39bf1ae788d29e6def2af02690b18b4dd491662b26b445a93f9b8994e6f18990.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-rds-integ.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-rds-integ.assets" + ], + "metadata": { + "/aws-cdk-rds-integ/VPC/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCB9E5F0B4" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1SubnetB4246D30" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableFEE4B781" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1RouteTableAssociation0B0896DC" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1DefaultRoute91CEF279" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1EIP6AD938E8" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet1NATGatewayE0556630" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2Subnet74179F39" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTable6F1A15F1" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2RouteTableAssociation5A808732" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2DefaultRouteB7481BBA" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2EIP4947BC00" + } + ], + "/aws-cdk-rds-integ/VPC/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPublicSubnet2NATGateway3C070193" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1Subnet8BCA10E0" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableBE8A6027" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1RouteTableAssociation347902D1" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet1DefaultRouteAE1D6490" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTable0A19E10E" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2RouteTableAssociation0C73D413" + } + ], + "/aws-cdk-rds-integ/VPC/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCPrivateSubnet2DefaultRouteF4F5CFD2" + } + ], + "/aws-cdk-rds-integ/VPC/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCIGWB7E252D3" + } + ], + "/aws-cdk-rds-integ/VPC/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "VPCVPCGW99B986DC" + } + ], + "/aws-cdk-rds-integ/SubnetGroup/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "SubnetGroup" + } + ], + "/aws-cdk-rds-integ/Serverless Database/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ServerlessDatabaseSecurityGroup1E143FBB" + } + ], + "/aws-cdk-rds-integ/Serverless Database/SecurityGroup/from 0.0.0.0_0:{IndirectPort}": [ + { + "type": "aws:cdk:logicalId", + "data": "ServerlessDatabaseSecurityGroupfrom00000IndirectPortE0823E20" + } + ], + "/aws-cdk-rds-integ/Serverless Database/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ServerlessDatabaseDF340AE1" + } + ], + "/aws-cdk-rds-integ/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-rds-integ/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-rds-integ" + }, + "clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "clusterdualtestDefaultTestDeployAssert0AE5E6E0": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "clusterdualtestDefaultTestDeployAssert0AE5E6E0.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "clusterdualtestDefaultTestDeployAssert0AE5E6E0.assets" + ], + "metadata": { + "/cluster-dual-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cluster-dual-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cluster-dual-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/tree.json new file mode 100644 index 0000000000000..fe6a5aac12724 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.js.snapshot/tree.json @@ -0,0 +1,902 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-rds-integ": { + "id": "aws-cdk-rds-integ", + "path": "aws-cdk-rds-integ", + "children": { + "VPC": { + "id": "VPC", + "path": "aws-cdk-rds-integ/VPC", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-integ/VPC/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "0.0.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet1RouteTableFEE4B781" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet1EIP6AD938E8", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.64.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "routeTableId": { + "Ref": "VPCPublicSubnet2RouteTable6F1A15F1" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-cdk-rds-integ/VPC/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "allocationId": { + "Fn::GetAtt": [ + "VPCPublicSubnet2EIP4947BC00", + "AllocationId" + ] + }, + "subnetId": { + "Ref": "VPCPublicSubnet2Subnet74179F39" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PrivateSubnet1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet1Subnet8BCA10E0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet1NATGatewayE0556630" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet1RouteTableBE8A6027" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.192.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC/PrivateSubnet2" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + }, + "subnetId": { + "Ref": "VPCPrivateSubnet2SubnetCFCDAA7A" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-integ/VPC/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "VPCPublicSubnet2NATGateway3C070193" + }, + "routeTableId": { + "Ref": "VPCPrivateSubnet2RouteTable0A19E10E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "IGW": { + "id": "IGW", + "path": "aws-cdk-rds-integ/VPC/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-integ/VPC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "0.0.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "aws-cdk-rds-integ/VPC/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "internetGatewayId": { + "Ref": "VPCIGWB7E252D3" + }, + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "0.0.0" + } + }, + "SubnetGroup": { + "id": "SubnetGroup", + "path": "aws-cdk-rds-integ/SubnetGroup", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-rds-integ/SubnetGroup/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBSubnetGroup", + "aws:cdk:cloudformation:props": { + "dbSubnetGroupDescription": "My Subnet Group", + "dbSubnetGroupName": "mynotlowercasesubnetgroupname", + "subnetIds": [ + { + "Ref": "VPCPublicSubnet1SubnetB4246D30" + }, + { + "Ref": "VPCPublicSubnet2Subnet74179F39" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.SubnetGroup", + "version": "0.0.0" + } + }, + "Serverless Database": { + "id": "Serverless Database", + "path": "aws-cdk-rds-integ/Serverless Database", + "children": { + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-rds-integ/Serverless Database/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-integ/Serverless Database/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "RDS security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "VPCB9E5F0B4" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + }, + "from 0.0.0.0_0:{IndirectPort}": { + "id": "from 0.0.0.0_0:{IndirectPort}", + "path": "aws-cdk-rds-integ/Serverless Database/SecurityGroup/from 0.0.0.0_0:{IndirectPort}", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress", + "aws:cdk:cloudformation:props": { + "cidrIp": "0.0.0.0/0", + "description": "Open to the world", + "fromPort": { + "Fn::GetAtt": [ + "ServerlessDatabaseDF340AE1", + "Endpoint.Port" + ] + }, + "groupId": { + "Fn::GetAtt": [ + "ServerlessDatabaseSecurityGroup1E143FBB", + "GroupId" + ] + }, + "ipProtocol": "tcp", + "toPort": { + "Fn::GetAtt": [ + "ServerlessDatabaseDF340AE1", + "Endpoint.Port" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroupIngress", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup": { + "id": "AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "path": "aws-cdk-rds-integ/Serverless Database/AuroraMySqlDatabaseClusterEngineDefaultParameterGroup", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-integ/Serverless Database/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBCluster", + "aws:cdk:cloudformation:props": { + "copyTagsToSnapshot": true, + "dbClusterParameterGroupName": "default.aurora-mysql5.7", + "dbSubnetGroupName": { + "Ref": "SubnetGroup" + }, + "engine": "aurora-mysql", + "engineMode": "serverless", + "masterUsername": "admin", + "masterUserPassword": "7959866cacc02c2d243ecfe177464fe6", + "scalingConfiguration": { + "autoPause": true, + "minCapacity": 8, + "maxCapacity": 32, + "secondsUntilAutoPause": 300, + "secondsBeforeTimeout": 480, + "timeoutAction": "ForceApplyCapacityChange" + }, + "storageEncrypted": true, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ServerlessDatabaseSecurityGroup1E143FBB", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBCluster", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.ServerlessCluster", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-rds-integ/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-rds-integ/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "cluster-dual-test": { + "id": "cluster-dual-test", + "path": "cluster-dual-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "cluster-dual-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "cluster-dual-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "cluster-dual-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cluster-dual-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cluster-dual-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.ts new file mode 100644 index 0000000000000..8b2ca217e20b6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.serverless-cluster-scaling.ts @@ -0,0 +1,44 @@ +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as cdk from 'aws-cdk-lib'; +import * as rds from 'aws-cdk-lib/aws-rds'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-rds-integ'); + +const vpc = new ec2.Vpc(stack, 'VPC', { + restrictDefaultSecurityGroup: false, + maxAzs: 2, +}); +const subnetGroup = new rds.SubnetGroup(stack, 'SubnetGroup', { + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + description: 'My Subnet Group', + subnetGroupName: 'MyNotLowerCaseSubnetGroupName', +}); + +const cluster = new rds.ServerlessCluster(stack, 'Serverless Database', { + engine: rds.DatabaseClusterEngine.AURORA_MYSQL, + credentials: { + username: 'admin', + password: cdk.SecretValue.unsafePlainText('7959866cacc02c2d243ecfe177464fe6'), + }, + vpc, + vpcSubnets: { subnetType: ec2.SubnetType.PUBLIC }, + subnetGroup, + removalPolicy: cdk.RemovalPolicy.DESTROY, + scaling: { + autoPause: cdk.Duration.minutes(5), + minCapacity: rds.AuroraCapacityUnit.ACU_8, + maxCapacity: rds.AuroraCapacityUnit.ACU_32, + timeoutAction: rds.TimeoutAction.FORCE_APPLY_CAPACITY_CHANGE, + timeout: cdk.Duration.minutes(8), + }, +}); +cluster.connections.allowDefaultPortFromAnyIpv4('Open to the world'); + +new IntegTest(app, 'cluster-dual-test', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.assets.json new file mode 100644 index 0000000000000..2adbb529701d8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.assets.json @@ -0,0 +1,19 @@ +{ + "version": "34.0.0", + "files": { + "bb5554b18d5450c7ca1e64100800a89c7f35242a1286267155fa2f0bae8ae2de": { + "source": { + "path": "aws-cdk-signer-signing-profile.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "bb5554b18d5450c7ca1e64100800a89c7f35242a1286267155fa2f0bae8ae2de.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.template.json new file mode 100644 index 0000000000000..983f40aa39404 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/aws-cdk-signer-signing-profile.template.json @@ -0,0 +1,58 @@ +{ + "Resources": { + "SigningProfileLambda4B150CCB": { + "Type": "AWS::Signer::SigningProfile", + "Properties": { + "PlatformId": "AWSLambda-SHA384-ECDSA", + "SignatureValidityPeriod": { + "Type": "MONTHS", + "Value": 135 + } + } + }, + "SigningProfileOCI1EA741C3": { + "Type": "AWS::Signer::SigningProfile", + "Properties": { + "PlatformId": "Notation-OCI-SHA384-ECDSA", + "SignatureValidityPeriod": { + "Type": "DAYS", + "Value": 60 + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdk.out new file mode 100644 index 0000000000000..2313ab5436501 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"34.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets.json new file mode 100644 index 0000000000000..cb7757bedf497 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets.json @@ -0,0 +1,19 @@ +{ + "version": "34.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/integ.json new file mode 100644 index 0000000000000..3711c89c20dca --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "34.0.0", + "testCases": { + "cdk-integ-signer-signing-profile/DefaultTest": { + "stacks": [ + "aws-cdk-signer-signing-profile" + ], + "assertionStack": "cdk-integ-signer-signing-profile/DefaultTest/DeployAssert", + "assertionStackName": "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/manifest.json new file mode 100644 index 0000000000000..530d693df32cd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/manifest.json @@ -0,0 +1,119 @@ +{ + "version": "34.0.0", + "artifacts": { + "aws-cdk-signer-signing-profile.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-signer-signing-profile.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-signer-signing-profile": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-signer-signing-profile.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/bb5554b18d5450c7ca1e64100800a89c7f35242a1286267155fa2f0bae8ae2de.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-signer-signing-profile.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-signer-signing-profile.assets" + ], + "metadata": { + "/aws-cdk-signer-signing-profile/SigningProfileLambda/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SigningProfileLambda4B150CCB" + } + ], + "/aws-cdk-signer-signing-profile/SigningProfileOCI/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SigningProfileOCI1EA741C3" + } + ], + "/aws-cdk-signer-signing-profile/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-signer-signing-profile/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-signer-signing-profile" + }, + "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "cdkintegsignersigningprofileDefaultTestDeployAssertE50BA0E5.assets" + ], + "metadata": { + "/cdk-integ-signer-signing-profile/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-integ-signer-signing-profile/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-integ-signer-signing-profile/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/tree.json new file mode 100644 index 0000000000000..4ebcd4249d0d4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.js.snapshot/tree.json @@ -0,0 +1,157 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-signer-signing-profile": { + "id": "aws-cdk-signer-signing-profile", + "path": "aws-cdk-signer-signing-profile", + "children": { + "SigningProfileLambda": { + "id": "SigningProfileLambda", + "path": "aws-cdk-signer-signing-profile/SigningProfileLambda", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-signer-signing-profile/SigningProfileLambda/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Signer::SigningProfile", + "aws:cdk:cloudformation:props": { + "platformId": "AWSLambda-SHA384-ECDSA", + "signatureValidityPeriod": { + "type": "MONTHS", + "value": 135 + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_signer.CfnSigningProfile", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_signer.SigningProfile", + "version": "0.0.0" + } + }, + "SigningProfileOCI": { + "id": "SigningProfileOCI", + "path": "aws-cdk-signer-signing-profile/SigningProfileOCI", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-signer-signing-profile/SigningProfileOCI/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Signer::SigningProfile", + "aws:cdk:cloudformation:props": { + "platformId": "Notation-OCI-SHA384-ECDSA", + "signatureValidityPeriod": { + "type": "DAYS", + "value": 60 + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_signer.CfnSigningProfile", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_signer.SigningProfile", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-signer-signing-profile/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-signer-signing-profile/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "cdk-integ-signer-signing-profile": { + "id": "cdk-integ-signer-signing-profile", + "path": "cdk-integ-signer-signing-profile", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "cdk-integ-signer-signing-profile/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "cdk-integ-signer-signing-profile/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "cdk-integ-signer-signing-profile/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-integ-signer-signing-profile/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-integ-signer-signing-profile/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.ts new file mode 100644 index 0000000000000..fbbd536cd3eba --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-signer/integ.signing-profile.ts @@ -0,0 +1,21 @@ +#!/usr/bin/env node +import * as cdk from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as signer from 'aws-cdk-lib/aws-signer'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'aws-cdk-signer-signing-profile'); + +new signer.SigningProfile(stack, 'SigningProfileLambda', { + platform: signer.Platform.AWS_LAMBDA_SHA384_ECDSA, +}); + +new signer.SigningProfile(stack, 'SigningProfileOCI', { + platform: signer.Platform.NOTATION_OCI_SHA384_ECDSA, + signatureValidity: cdk.Duration.days(60), +}); + +new IntegTest(app, 'cdk-integ-signer-signing-profile', { + testCases: [stack], +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.assets.json index 852466be8943d..673c6aba98278 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.assets.json @@ -1,7 +1,7 @@ { - "version": "30.0.0", + "version": "36.0.0", "files": { - "88187762ebb3676ec68ded03ce92c045563205c6497ae5a104f13a32dbf4ef43": { + "009040dbb1873c31d45ee6be45381ed16bbf81f9a642799664531ba2f3c56832": { "source": { "path": "aws-stepfunctions-custom-state-integ.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "88187762ebb3676ec68ded03ce92c045563205c6497ae5a104f13a32dbf4ef43.json", + "objectKey": "009040dbb1873c31d45ee6be45381ed16bbf81f9a642799664531ba2f3c56832.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.template.json index b090502f0294b..be6ebd9dd8583 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/aws-stepfunctions-custom-state-integ.template.json @@ -20,13 +20,13 @@ "StateMachine2E01A3A5": { "Type": "AWS::StepFunctions::StateMachine", "Properties": { + "DefinitionString": "{\"StartAt\":\"my custom task\",\"States\":{\"my custom task\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Retry\":[{\"ErrorEquals\":[\"States.ALL\"],\"IntervalSeconds\":10,\"MaxAttempts\":5}],\"Catch\":[{\"ErrorEquals\":[\"States.ALL\"],\"Next\":\"failed\"}]},\"final step\":{\"Type\":\"Pass\",\"End\":true},\"failed\":{\"Type\":\"Fail\",\"Error\":\"DidNotWork\",\"Cause\":\"We got stuck\"}},\"TimeoutSeconds\":30}", "RoleArn": { "Fn::GetAtt": [ "StateMachineRoleB840431D", "Arn" ] - }, - "DefinitionString": "{\"StartAt\":\"my custom task\",\"States\":{\"my custom task\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Catch\":[{\"ErrorEquals\":[\"States.ALL\"],\"Next\":\"failed\"}]},\"final step\":{\"Type\":\"Pass\",\"End\":true},\"failed\":{\"Type\":\"Fail\",\"Error\":\"DidNotWork\",\"Cause\":\"We got stuck\"}},\"TimeoutSeconds\":30}" + } }, "DependsOn": [ "StateMachineRoleB840431D" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/cdk.out index ae4b03c54e770..1f0068d32659a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"30.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/integ.json index 624779da650bd..3c6ca76f840ab 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "30.0.0", + "version": "36.0.0", "testCases": { "integ.custom-state": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/manifest.json index 1607ee7800b57..0bd5238d6c5f6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "30.0.0", + "version": "36.0.0", "artifacts": { "aws-stepfunctions-custom-state-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-stepfunctions-custom-state-integ.template.json", + "terminationProtection": false, "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/88187762ebb3676ec68ded03ce92c045563205c6497ae5a104f13a32dbf4ef43.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/009040dbb1873c31d45ee6be45381ed16bbf81f9a642799664531ba2f3c56832.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/tree.json index 6544935df1c46..c33567eaa9d4c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.js.snapshot/tree.json @@ -12,7 +12,15 @@ "id": "final step", "path": "aws-stepfunctions-custom-state-integ/final step", "constructInfo": { - "fqn": "@aws-cdk/aws-stepfunctions.Pass", + "fqn": "aws-cdk-lib.aws_stepfunctions.Pass", + "version": "0.0.0" + } + }, + "failed": { + "id": "failed", + "path": "aws-stepfunctions-custom-state-integ/failed", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_stepfunctions.Fail", "version": "0.0.0" } }, @@ -20,7 +28,7 @@ "id": "my custom task", "path": "aws-stepfunctions-custom-state-integ/my custom task", "constructInfo": { - "fqn": "@aws-cdk/aws-stepfunctions.CustomState", + "fqn": "aws-cdk-lib.aws_stepfunctions.CustomState", "version": "0.0.0" } }, @@ -36,7 +44,7 @@ "id": "ImportRole", "path": "aws-stepfunctions-custom-state-integ/StateMachine/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -61,13 +69,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -77,23 +85,23 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::StepFunctions::StateMachine", "aws:cdk:cloudformation:props": { + "definitionString": "{\"StartAt\":\"my custom task\",\"States\":{\"my custom task\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null,\"Retry\":[{\"ErrorEquals\":[\"States.ALL\"],\"IntervalSeconds\":10,\"MaxAttempts\":5}],\"Catch\":[{\"ErrorEquals\":[\"States.ALL\"],\"Next\":\"failed\"}]},\"final step\":{\"Type\":\"Pass\",\"End\":true},\"failed\":{\"Type\":\"Fail\",\"Error\":\"DidNotWork\",\"Cause\":\"We got stuck\"}},\"TimeoutSeconds\":30}", "roleArn": { "Fn::GetAtt": [ "StateMachineRoleB840431D", "Arn" ] - }, - "definitionString": "{\"StartAt\":\"my custom task\",\"States\":{\"my custom task\":{\"Next\":\"final step\",\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::dynamodb:putItem\",\"Parameters\":{\"TableName\":\"my-cool-table\",\"Item\":{\"id\":{\"S\":\"my-entry\"}}},\"ResultPath\":null},\"final step\":{\"Type\":\"Pass\",\"End\":true}},\"TimeoutSeconds\":30}" + } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-stepfunctions.CfnStateMachine", + "fqn": "aws-cdk-lib.aws_stepfunctions.CfnStateMachine", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-stepfunctions.StateMachine", + "fqn": "aws-cdk-lib.aws_stepfunctions.StateMachine", "version": "0.0.0" } }, @@ -101,7 +109,7 @@ "id": "StateMachineARN", "path": "aws-stepfunctions-custom-state-integ/StateMachineARN", "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", + "fqn": "aws-cdk-lib.CfnOutput", "version": "0.0.0" } }, @@ -109,7 +117,7 @@ "id": "BootstrapVersion", "path": "aws-stepfunctions-custom-state-integ/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, @@ -117,13 +125,13 @@ "id": "CheckBootstrapVersion", "path": "aws-stepfunctions-custom-state-integ/CheckBootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnRule", + "fqn": "aws-cdk-lib.CfnRule", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.Stack", + "fqn": "aws-cdk-lib.Stack", "version": "0.0.0" } }, @@ -132,12 +140,12 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.237" + "version": "10.3.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.App", + "fqn": "aws-cdk-lib.App", "version": "0.0.0" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.ts index 5d28b12436975..0d30c3d1b771b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-stepfunctions/test/integ.custom-state.ts @@ -35,6 +35,11 @@ const custom = new sfn.CustomState(stack, 'my custom task', { }); custom.addCatch(failure); +custom.addRetry({ + errors: [sfn.Errors.ALL], + interval: cdk.Duration.seconds(10), + maxAttempts: 5, +}); const chain = sfn.Chain.start(custom).next(finalStatus); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.assets.json new file mode 100644 index 0000000000000..81987a6476a91 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.assets.json @@ -0,0 +1,20 @@ +{ + "version": "36.0.0", + "files": { + "7ef69b8c181a37746d9dd86efa256698f93bd815bd82571bc18eee7c39ba9436": { + "source": { + "path": "PipelineStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", + "objectKey": "7ef69b8c181a37746d9dd86efa256698f93bd815bd82571bc18eee7c39ba9436.json", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.template.json new file mode 100644 index 0000000000000..30d593d002a21 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStack.template.json @@ -0,0 +1,918 @@ +{ + "Resources": { + "PipelineRoleB27FAA37": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codepipeline.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleDefaultPolicy7BDC1ABB": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::us-west-2-newpipeline-with-cross-region-replication-buckets", + "arn:aws:s3:::us-west-2-newpipeline-with-cross-region-replication-buckets/*", + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "ArtifactStores": [ + { + "ArtifactStore": { + "Location": { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputRefRegionalBucketF5C80E4B3E52A444" + }, + "Type": "S3" + }, + "Region": "us-east-1" + }, + { + "ArtifactStore": { + "Location": "us-west-2-newpipeline-with-cross-region-replication-buckets", + "Type": "S3" + }, + "Region": "us-west-2" + } + ], + "RestartExecutionOnUpdate": true, + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "jose-clickup", + "Repo": "cdk-pipelines-demo", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "Name": "jose-clickup_cdk-pipelines-demo", + "OutputArtifacts": [ + { + "Name": "jose_clickup_cdk_pipelines_demo_Source" + } + ], + "RunOrder": 1 + } + ], + "Name": "Source" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"9846e726ec481ed25679c0170187f40b4920586fd0e7314d24f56620d9f53f5b\"}]" + }, + "InputArtifacts": [ + { + "Name": "jose_clickup_cdk_pipelines_demo_Source" + } + ], + "Name": "Synth", + "OutputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "Build" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"167eef1378d6e6ad8c4c8da3461f900d6e066cd0916052ee812a8d94b87ad38c\"}]" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "SelfMutate", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "UpdatePipeline" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormation", + "Version": "1" + }, + "Configuration": { + "StackName": "us-east-1-Queue1", + "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-cfn-exec-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + "ActionMode": "CHANGE_SET_REPLACE", + "ChangeSetName": "PipelineChange", + "TemplatePath": "Synth_Output::assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.template.json" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "us-east-1.Queue1.Prepare", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + "RunOrder": 1 + }, + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormation", + "Version": "1" + }, + "Configuration": { + "StackName": "us-west-2-Queue1", + "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-cfn-exec-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "ActionMode": "CHANGE_SET_REPLACE", + "ChangeSetName": "PipelineChange", + "TemplatePath": "Synth_Output::assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.template.json" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "us-west-2.Queue1.Prepare", + "Region": "us-west-2", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "RunOrder": 1 + }, + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormation", + "Version": "1" + }, + "Configuration": { + "StackName": "us-east-1-Queue1", + "ActionMode": "CHANGE_SET_EXECUTE", + "ChangeSetName": "PipelineChange" + }, + "Name": "us-east-1.Queue1.Deploy", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + "RunOrder": 2 + }, + { + "ActionTypeId": { + "Category": "Deploy", + "Owner": "AWS", + "Provider": "CloudFormation", + "Version": "1" + }, + "Configuration": { + "StackName": "us-west-2-Queue1", + "ActionMode": "CHANGE_SET_EXECUTE", + "ChangeSetName": "PipelineChange" + }, + "Name": "us-west-2.Queue1.Deploy", + "Region": "us-west-2", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "RunOrder": 2 + } + ], + "Name": "MultiRegion" + } + ] + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "PipelineSourcejoseclickupcdkpipelinesdemoWebhookResourceEAB0C0F4": { + "Type": "AWS::CodePipeline::Webhook", + "Properties": { + "Authentication": "GITHUB_HMAC", + "AuthenticationConfiguration": { + "SecretToken": "{{resolve:secretsmanager:github-token:SecretString:::}}" + }, + "Filters": [ + { + "JsonPath": "$.ref", + "MatchEquals": "refs/heads/{Branch}" + } + ], + "RegisterWithThirdParty": true, + "TargetAction": "jose-clickup_cdk-pipelines-demo", + "TargetPipeline": { + "Ref": "Pipeline9850B417" + }, + "TargetPipelineVersion": 1 + } + }, + "PipelineBuildSynthCdkBuildProjectRole231EEA2A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:codebuild:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step PipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3", + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:7.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProjectRole231EEA2A", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"npm ci\",\n \"npm run build\",\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"base-directory\": \"cdk.out\",\n \"files\": \"**/*\"\n }\n}", + "Type": "CODEPIPELINE" + } + } + }, + "PipelineCodeBuildActionRole226DB0CB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProject6BEFA8E6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutationDAA41400", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE", + "Roles": [ + { + "Ref": "PipelineCodeBuildActionRole226DB0CB" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationRole57E559E8": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:codebuild:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + "-*" + ] + ] + } + }, + { + "Action": "sts:AssumeRole", + "Condition": { + "ForAnyValue:StringEquals": { + "iam:ResourceTag/aws-cdk:bootstrap-role": [ + "image-publishing", + "file-publishing", + "deploy" + ] + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:*:iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/*" + ] + ] + } + }, + { + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "Roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationDAA41400": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step PipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "EncryptionKey": "alias/aws/s3", + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:7.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutationRole57E559E8", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@2\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy PipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStackPipeline9DB740AF.dot b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStackPipeline9DB740AF.dot new file mode 100644 index 0000000000000..7e39513541b14 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/PipelineStackPipeline9DB740AF.dot @@ -0,0 +1,55 @@ +digraph G { + # Arrows represent an "unlocks" relationship (opposite of dependency). So chosen + # because the layout looks more natural that way. + # To represent subgraph dependencies, subgraphs are represented by BEGIN/END nodes. + # To render: `dot -Tsvg PipelineStackPipeline9DB740AF.dot > graph.svg`, open in a browser. + node [shape="box"]; +"BEGIN Build" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END Build" [shape="cds", style="filled", fillcolor="#b7deff"]; +"Build.Synth"; +"Source.jose-clickup/cdk-pipelines-demo" -> "Build.Synth"; +"BEGIN Build" -> "Build.Synth"; +"Build.Synth" -> "END Build"; +"BEGIN UpdatePipeline" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END UpdatePipeline" [shape="cds", style="filled", fillcolor="#b7deff"]; +"UpdatePipeline.SelfMutate"; +"Build.Synth" -> "UpdatePipeline.SelfMutate"; +"BEGIN UpdatePipeline" -> "UpdatePipeline.SelfMutate"; +"UpdatePipeline.SelfMutate" -> "END UpdatePipeline"; +"BEGIN MultiRegion" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END MultiRegion" [shape="cds", style="filled", fillcolor="#b7deff"]; +"UpdatePipeline.SelfMutate" -> "BEGIN MultiRegion"; +"BEGIN MultiRegion.us-east-1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END MultiRegion.us-east-1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"BEGIN MultiRegion.us-east-1.Queue1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END MultiRegion.us-east-1.Queue1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"MultiRegion.us-east-1.Queue1.Deploy"; +"MultiRegion.us-east-1.Queue1.Prepare" -> "MultiRegion.us-east-1.Queue1.Deploy"; +"MultiRegion.us-east-1.Queue1.Prepare"; +"Build.Synth" -> "MultiRegion.us-east-1.Queue1.Prepare"; +"BEGIN MultiRegion.us-east-1.Queue1" -> "MultiRegion.us-east-1.Queue1.Prepare"; +"MultiRegion.us-east-1.Queue1.Deploy" -> "END MultiRegion.us-east-1.Queue1"; +"BEGIN MultiRegion.us-east-1" -> "BEGIN MultiRegion.us-east-1.Queue1"; +"END MultiRegion.us-east-1.Queue1" -> "END MultiRegion.us-east-1"; +"BEGIN MultiRegion.us-west-2" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END MultiRegion.us-west-2" [shape="cds", style="filled", fillcolor="#b7deff"]; +"BEGIN MultiRegion.us-west-2.Queue1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END MultiRegion.us-west-2.Queue1" [shape="cds", style="filled", fillcolor="#b7deff"]; +"MultiRegion.us-west-2.Queue1.Deploy"; +"MultiRegion.us-west-2.Queue1.Prepare" -> "MultiRegion.us-west-2.Queue1.Deploy"; +"MultiRegion.us-west-2.Queue1.Prepare"; +"Build.Synth" -> "MultiRegion.us-west-2.Queue1.Prepare"; +"BEGIN MultiRegion.us-west-2.Queue1" -> "MultiRegion.us-west-2.Queue1.Prepare"; +"MultiRegion.us-west-2.Queue1.Deploy" -> "END MultiRegion.us-west-2.Queue1"; +"BEGIN MultiRegion.us-west-2" -> "BEGIN MultiRegion.us-west-2.Queue1"; +"END MultiRegion.us-west-2.Queue1" -> "END MultiRegion.us-west-2"; +"BEGIN MultiRegion" -> "BEGIN MultiRegion.us-east-1"; +"BEGIN MultiRegion" -> "BEGIN MultiRegion.us-west-2"; +"END MultiRegion.us-east-1" -> "END MultiRegion"; +"END MultiRegion.us-west-2" -> "END MultiRegion"; +"BEGIN Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"Source.jose-clickup/cdk-pipelines-demo"; +"BEGIN Source" -> "Source.jose-clickup/cdk-pipelines-demo"; +"Source.jose-clickup/cdk-pipelines-demo" -> "END Source"; +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.assets.json new file mode 100644 index 0000000000000..ee3b8cd59ea37 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.assets.json @@ -0,0 +1,20 @@ +{ + "version": "36.0.0", + "files": { + "0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5": { + "source": { + "path": "PipelineStackuseast1Queue1822FD5F8.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", + "objectKey": "0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5.json", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.template.json new file mode 100644 index 0000000000000..132b710b85c15 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.template.json @@ -0,0 +1,43 @@ +{ + "Resources": { + "Queue4A7E3555": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/manifest.json new file mode 100644 index 0000000000000..09464ce251ef7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-east-1/manifest.json @@ -0,0 +1,60 @@ +{ + "version": "36.0.0", + "artifacts": { + "PipelineStackuseast1Queue1822FD5F8.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineStackuseast1Queue1822FD5F8.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineStackuseast1Queue1822FD5F8": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/us-east-1", + "properties": { + "templateFile": "PipelineStackuseast1Queue1822FD5F8.template.json", + "terminationProtection": false, + "validateOnSynth": true, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineStackuseast1Queue1822FD5F8.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-us-east-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + }, + "stackName": "us-east-1-Queue1" + }, + "dependencies": [ + "PipelineStackuseast1Queue1822FD5F8.assets" + ], + "metadata": { + "/PipelineStack/us-east-1/Queue1/Queue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Queue4A7E3555" + } + ], + "/PipelineStack/us-east-1/Queue1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineStack/us-east-1/Queue1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineStack/us-east-1/Queue1" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.assets.json new file mode 100644 index 0000000000000..bf33a9a36c1e7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.assets.json @@ -0,0 +1,20 @@ +{ + "version": "36.0.0", + "files": { + "0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5": { + "source": { + "path": "PipelineStackuswest2Queue1C1AD8043.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-us-west-2": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2", + "objectKey": "0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5.json", + "region": "us-west-2", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-west-2" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.template.json new file mode 100644 index 0000000000000..132b710b85c15 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.template.json @@ -0,0 +1,43 @@ +{ + "Resources": { + "Queue4A7E3555": { + "Type": "AWS::SQS::Queue", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/manifest.json new file mode 100644 index 0000000000000..9caf57624ba77 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/assembly-PipelineStack-us-west-2/manifest.json @@ -0,0 +1,60 @@ +{ + "version": "36.0.0", + "artifacts": { + "PipelineStackuswest2Queue1C1AD8043.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineStackuswest2Queue1C1AD8043.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineStackuswest2Queue1C1AD8043": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/us-west-2", + "properties": { + "templateFile": "PipelineStackuswest2Queue1C1AD8043.template.json", + "terminationProtection": false, + "validateOnSynth": true, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2/0cb2dea76b65bd66a374af57914e8583b3c20712b5758474102ef97620d68ec5.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineStackuswest2Queue1C1AD8043.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-us-west-2", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + }, + "stackName": "us-west-2-Queue1" + }, + "dependencies": [ + "PipelineStackuswest2Queue1C1AD8043.assets" + ], + "metadata": { + "/PipelineStack/us-west-2/Queue1/Queue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Queue4A7E3555" + } + ], + "/PipelineStack/us-west-2/Queue1/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineStack/us-west-2/Queue1/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineStack/us-west-2/Queue1" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js new file mode 100644 index 0000000000000..9d841e15260d7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js @@ -0,0 +1 @@ +"use strict";var C=Object.create;var i=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var o in t)i(e,o,{get:t[o],enumerable:!0})},d=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of w(t))!A.call(e,s)&&s!==o&&i(e,s,{get:()=>t[s],enumerable:!(r=I(t,s))||r.enumerable});return e};var l=(e,t,o)=>(o=e!=null?C(P(e)):{},d(t||!e||!e.__esModule?i(o,"default",{value:e,enumerable:!0}):o,e)),k=e=>d(i({},"__esModule",{value:!0}),e);var U={};L(U,{autoDeleteHandler:()=>S,handler:()=>_});module.exports=k(U);var h=require("@aws-sdk/client-s3");var y=l(require("https")),m=l(require("url")),a={sendHttpRequest:T,log:b,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",B="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(e){return async(t,o)=>{let r={...t,ResponseURL:"..."};if(a.log(JSON.stringify(r,void 0,2)),t.RequestType==="Delete"&&t.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",t);return}try{let s=await e(r,o),n=D(t,s);await u("SUCCESS",n)}catch(s){let n={...t,Reason:a.includeStackTraces?s.stack:s.message};n.PhysicalResourceId||(t.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),n.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(t)}`)),await u("FAILED",n)}}}function D(e,t={}){let o=t.PhysicalResourceId??e.PhysicalResourceId??e.RequestId;if(e.RequestType==="Delete"&&o!==e.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${e.PhysicalResourceId}" to "${t.PhysicalResourceId}" during deletion`);return{...e,...t,PhysicalResourceId:o}}async function u(e,t){let o={Status:e,Reason:t.Reason??e,StackId:t.StackId,RequestId:t.RequestId,PhysicalResourceId:t.PhysicalResourceId||B,LogicalResourceId:t.LogicalResourceId,NoEcho:t.NoEcho,Data:t.Data};a.log("submit response to cloudformation",o);let r=JSON.stringify(o),s=m.parse(t.ResponseURL),n={hostname:s.hostname,path:s.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(r,"utf8")}};await O({attempts:5,sleep:1e3},a.sendHttpRequest)(n,r)}async function T(e,t){return new Promise((o,r)=>{try{let s=y.request(e,n=>o());s.on("error",r),s.write(t),s.end()}catch(s){r(s)}})}function b(e,...t){console.log(e,...t)}function O(e,t){return async(...o)=>{let r=e.attempts,s=e.sleep;for(;;)try{return await t(...o)}catch(n){if(r--<=0)throw n;await x(Math.floor(Math.random()*s)),s*=2}}}async function x(e){return new Promise(t=>setTimeout(t,e))}var g="aws-cdk:auto-delete-objects",H=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),_=R(S);async function S(e){switch(e.RequestType){case"Create":return;case"Update":return F(e);case"Delete":return f(e.ResourceProperties?.BucketName)}}async function F(e){let t=e,o=t.OldResourceProperties?.BucketName,r=t.ResourceProperties?.BucketName;if(r!=null&&o!=null&&r!==o)return f(o)}async function N(e){try{let t=(await c.getBucketPolicy({Bucket:e}))?.Policy??H,o=JSON.parse(t);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${e}/*`]}),await c.putBucketPolicy({Bucket:e,Policy:JSON.stringify(o)})}catch(t){if(t.name==="NoSuchBucket")throw t;console.log(`Could not set new object deny policy on bucket '${e}' prior to deletion.`)}}async function E(e){let t=await c.listObjectVersions({Bucket:e}),o=[...t.Versions??[],...t.DeleteMarkers??[]];if(o.length===0)return;let r=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:e,Delete:{Objects:r}}),t?.IsTruncated&&await E(e)}async function f(e){if(!e)throw new Error("No BucketName was provided.");try{if(!await W(e)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await N(e),await E(e)}catch(t){if(t.name==="NoSuchBucket"){console.log(`Bucket '${e}' does not exist.`);return}throw t}}async function W(e){return(await c.getBucketTagging({Bucket:e})).TagSet?.some(o=>o.Key===g&&o.Value==="true")}0&&(module.exports={autoDeleteHandler,handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets.json new file mode 100644 index 0000000000000..b60f3d5dac4ab --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/integ.json new file mode 100644 index 0000000000000..7e473fa163179 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "36.0.0", + "testCases": { + "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest": { + "stacks": [ + "PipelineStack", + "usEast1S3Stack", + "usWest2S3Stack" + ], + "assertionStack": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert", + "assertionStackName": "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/manifest.json new file mode 100644 index 0000000000000..0a3f70b362a29 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/manifest.json @@ -0,0 +1,363 @@ +{ + "version": "36.0.0", + "artifacts": { + "assembly-PipelineStack-us-east-1": { + "type": "cdk:cloud-assembly", + "properties": { + "directoryName": "assembly-PipelineStack-us-east-1", + "displayName": "PipelineStack/us-east-1" + } + }, + "assembly-PipelineStack-us-west-2": { + "type": "cdk:cloud-assembly", + "properties": { + "directoryName": "assembly-PipelineStack-us-west-2", + "displayName": "PipelineStack/us-west-2" + } + }, + "usEast1S3Stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "usEast1S3Stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "usEast1S3Stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/us-east-1", + "properties": { + "templateFile": "usEast1S3Stack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/dcb3b9d224db2e26297b5d99818cb49212a518e995d9fbba3f43d0f3cbb95373.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "usEast1S3Stack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-us-east-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "usEast1S3Stack.assets" + ], + "metadata": { + "/usEast1S3Stack/RegionalBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketF5C80E4B" + } + ], + "/usEast1S3Stack/RegionalBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketPolicyC6508E8A" + } + ], + "/usEast1S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketAutoDeleteObjectsCustomResource10BE89C6" + } + ], + "/usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/usEast1S3Stack/Exports/Output{\"Fn::GetAtt\":[\"RegionalBucketF5C80E4B\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + } + ], + "/usEast1S3Stack/Exports/Output{\"Ref\":\"RegionalBucketF5C80E4B\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefRegionalBucketF5C80E4B3E52A444" + } + ], + "/usEast1S3Stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/usEast1S3Stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "usEast1S3Stack" + }, + "usWest2S3Stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "usWest2S3Stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "usWest2S3Stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/us-west-2", + "properties": { + "templateFile": "usWest2S3Stack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2/be060ef9e9df7c21dec49e21423280cd2c208089a6f149a020bd51bb222fd15f.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "usWest2S3Stack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-us-west-2", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "usWest2S3Stack.assets" + ], + "metadata": { + "/usWest2S3Stack/RegionalBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketF5C80E4B" + } + ], + "/usWest2S3Stack/RegionalBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketPolicyC6508E8A" + } + ], + "/usWest2S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "RegionalBucketAutoDeleteObjectsCustomResource10BE89C6" + } + ], + "/usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/usWest2S3Stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/usWest2S3Stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "usWest2S3Stack" + }, + "PipelineStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/us-east-1", + "properties": { + "templateFile": "PipelineStack.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1/7ef69b8c181a37746d9dd86efa256698f93bd815bd82571bc18eee7c39ba9436.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-us-east-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "usWest2S3Stack", + "usEast1S3Stack", + "PipelineStack.assets" + ], + "metadata": { + "/PipelineStack/Pipeline/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleB27FAA37" + } + ], + "/PipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicy7BDC1ABB" + } + ], + "/PipelineStack/Pipeline/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Pipeline9850B417" + } + ], + "/PipelineStack/Pipeline/Pipeline/Source/jose-clickup_cdk-pipelines-demo/WebhookResource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineSourcejoseclickupcdkpipelinesdemoWebhookResourceEAB0C0F4" + } + ], + "/PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ], + "/PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C" + } + ], + "/PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ], + "/PipelineStack/Pipeline/CodeBuildActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRole226DB0CB" + } + ], + "/PipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE" + } + ], + "/PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ], + "/PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E" + } + ], + "/PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ], + "/PipelineStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineStack" + }, + "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "cdkintegcodepipelinewithcrossregionreplicationbucketsDefaultTestDeployAssertFB66B33F.assets" + ], + "metadata": { + "/cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/tree.json new file mode 100644 index 0000000000000..6647147e9ba1a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/tree.json @@ -0,0 +1,2125 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "usEast1S3Stack": { + "id": "usEast1S3Stack", + "path": "usEast1S3Stack", + "children": { + "RegionalBucket": { + "id": "RegionalBucket", + "path": "usEast1S3Stack/RegionalBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "usEast1S3Stack/RegionalBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "AES256" + } + } + ] + }, + "bucketName": "us-east-1-newpipeline-with-cross-region-replication-buckets", + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + }, + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + } + ], + "versioningConfiguration": { + "status": "Enabled" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "usEast1S3Stack/RegionalBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "usEast1S3Stack/RegionalBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "RegionalBucketF5C80E4B" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "0.0.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "usEast1S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "usEast1S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "0.0.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "usEast1S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "usEast1S3Stack/Exports", + "children": { + "Output{\"Fn::GetAtt\":[\"RegionalBucketF5C80E4B\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"RegionalBucketF5C80E4B\",\"Arn\"]}", + "path": "usEast1S3Stack/Exports/Output{\"Fn::GetAtt\":[\"RegionalBucketF5C80E4B\",\"Arn\"]}", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Ref\":\"RegionalBucketF5C80E4B\"}": { + "id": "Output{\"Ref\":\"RegionalBucketF5C80E4B\"}", + "path": "usEast1S3Stack/Exports/Output{\"Ref\":\"RegionalBucketF5C80E4B\"}", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "usEast1S3Stack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "usEast1S3Stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "usWest2S3Stack": { + "id": "usWest2S3Stack", + "path": "usWest2S3Stack", + "children": { + "RegionalBucket": { + "id": "RegionalBucket", + "path": "usWest2S3Stack/RegionalBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "usWest2S3Stack/RegionalBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "AES256" + } + } + ] + }, + "bucketName": "us-west-2-newpipeline-with-cross-region-replication-buckets", + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + }, + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + } + ], + "versioningConfiguration": { + "status": "Enabled" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "usWest2S3Stack/RegionalBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "usWest2S3Stack/RegionalBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "RegionalBucketF5C80E4B" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "0.0.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "usWest2S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "usWest2S3Stack/RegionalBucket/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "0.0.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "usWest2S3Stack/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "usWest2S3Stack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "usWest2S3Stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "PipelineStack": { + "id": "PipelineStack", + "path": "PipelineStack", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "PipelineStack/Pipeline", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "PipelineStack/Pipeline/Pipeline", + "children": { + "Role": { + "id": "Role", + "path": "PipelineStack/Pipeline/Pipeline/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "PipelineStack/Pipeline/Pipeline/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codepipeline.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "PipelineStack/Pipeline/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + "arn:aws:s3:::us-west-2-newpipeline-with-cross-region-replication-buckets", + "arn:aws:s3:::us-west-2-newpipeline-with-cross-region-replication-buckets/*", + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "artifactStores": [ + { + "region": "us-east-1", + "artifactStore": { + "type": "S3", + "location": { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputRefRegionalBucketF5C80E4B3E52A444" + } + } + }, + { + "region": "us-west-2", + "artifactStore": { + "type": "S3", + "location": "us-west-2-newpipeline-with-cross-region-replication-buckets" + } + } + ], + "restartExecutionOnUpdate": true, + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "jose-clickup_cdk-pipelines-demo", + "outputArtifacts": [ + { + "name": "jose_clickup_cdk_pipelines_demo_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "ThirdParty", + "provider": "GitHub" + }, + "configuration": { + "Owner": "jose-clickup", + "Repo": "cdk-pipelines-demo", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "runOrder": 1 + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Synth", + "inputArtifacts": [ + { + "name": "jose_clickup_cdk_pipelines_demo_Source" + } + ], + "outputArtifacts": [ + { + "name": "Synth_Output" + } + ], + "actionTypeId": { + "category": "Build", + "version": "1", + "owner": "AWS", + "provider": "CodeBuild" + }, + "configuration": { + "ProjectName": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"9846e726ec481ed25679c0170187f40b4920586fd0e7314d24f56620d9f53f5b\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + }, + { + "name": "UpdatePipeline", + "actions": [ + { + "name": "SelfMutate", + "inputArtifacts": [ + { + "name": "Synth_Output" + } + ], + "actionTypeId": { + "category": "Build", + "version": "1", + "owner": "AWS", + "provider": "CodeBuild" + }, + "configuration": { + "ProjectName": { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"167eef1378d6e6ad8c4c8da3461f900d6e066cd0916052ee812a8d94b87ad38c\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + }, + { + "name": "MultiRegion", + "actions": [ + { + "name": "us-east-1.Queue1.Prepare", + "inputArtifacts": [ + { + "name": "Synth_Output" + } + ], + "actionTypeId": { + "category": "Deploy", + "version": "1", + "owner": "AWS", + "provider": "CloudFormation" + }, + "configuration": { + "StackName": "us-east-1-Queue1", + "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-cfn-exec-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + }, + "ActionMode": "CHANGE_SET_REPLACE", + "ChangeSetName": "PipelineChange", + "TemplatePath": "Synth_Output::assembly-PipelineStack-us-east-1/PipelineStackuseast1Queue1822FD5F8.template.json" + }, + "runOrder": 1, + "roleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + } + }, + { + "name": "us-west-2.Queue1.Prepare", + "inputArtifacts": [ + { + "name": "Synth_Output" + } + ], + "actionTypeId": { + "category": "Deploy", + "version": "1", + "owner": "AWS", + "provider": "CloudFormation" + }, + "configuration": { + "StackName": "us-west-2-Queue1", + "Capabilities": "CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND", + "RoleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-cfn-exec-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "ActionMode": "CHANGE_SET_REPLACE", + "ChangeSetName": "PipelineChange", + "TemplatePath": "Synth_Output::assembly-PipelineStack-us-west-2/PipelineStackuswest2Queue1C1AD8043.template.json" + }, + "runOrder": 1, + "roleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "region": "us-west-2" + }, + { + "name": "us-east-1.Queue1.Deploy", + "actionTypeId": { + "category": "Deploy", + "version": "1", + "owner": "AWS", + "provider": "CloudFormation" + }, + "configuration": { + "StackName": "us-east-1-Queue1", + "ActionMode": "CHANGE_SET_EXECUTE", + "ChangeSetName": "PipelineChange" + }, + "runOrder": 2, + "roleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + } + }, + { + "name": "us-west-2.Queue1.Deploy", + "actionTypeId": { + "category": "Deploy", + "version": "1", + "owner": "AWS", + "provider": "CloudFormation" + }, + "configuration": { + "StackName": "us-west-2-Queue1", + "ActionMode": "CHANGE_SET_EXECUTE", + "ChangeSetName": "PipelineChange" + }, + "runOrder": 2, + "roleArn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + }, + "region": "us-west-2" + } + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "PipelineStack/Pipeline/Pipeline/Source", + "children": { + "jose-clickup_cdk-pipelines-demo": { + "id": "jose-clickup_cdk-pipelines-demo", + "path": "PipelineStack/Pipeline/Pipeline/Source/jose-clickup_cdk-pipelines-demo", + "children": { + "WebhookResource": { + "id": "WebhookResource", + "path": "PipelineStack/Pipeline/Pipeline/Source/jose-clickup_cdk-pipelines-demo/WebhookResource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Webhook", + "aws:cdk:cloudformation:props": { + "authentication": "GITHUB_HMAC", + "authenticationConfiguration": { + "secretToken": "{{resolve:secretsmanager:github-token:SecretString:::}}" + }, + "filters": [ + { + "jsonPath": "$.ref", + "matchEquals": "refs/heads/{Branch}" + } + ], + "registerWithThirdParty": true, + "targetAction": "jose-clickup_cdk-pipelines-demo", + "targetPipeline": { + "Ref": "Pipeline9850B417" + }, + "targetPipelineVersion": 1 + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codepipeline.CfnWebhook", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "Build": { + "id": "Build", + "path": "PipelineStack/Pipeline/Pipeline/Build", + "children": { + "Synth": { + "id": "Synth", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth", + "children": { + "CdkBuildProject": { + "id": "CdkBuildProject", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject", + "children": { + "Role": { + "id": "Role", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:codebuild:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step PipelineStack/Pipeline/Build/Synth", + "encryptionKey": "alias/aws/s3", + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:7.0", + "imagePullCredentialsType": "CODEBUILD", + "privilegedMode": false, + "computeType": "BUILD_GENERAL1_SMALL" + }, + "serviceRole": { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProjectRole231EEA2A", + "Arn" + ] + }, + "source": { + "type": "CODEPIPELINE", + "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"npm ci\",\n \"npm run build\",\n \"npx cdk synth\"\n ]\n }\n },\n \"artifacts\": {\n \"base-directory\": \"cdk.out\",\n \"files\": \"**/*\"\n }\n}" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "PipelineStack/Pipeline/Pipeline/UpdatePipeline", + "children": { + "SelfMutate": { + "id": "SelfMutate", + "path": "PipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "MultiRegion": { + "id": "MultiRegion", + "path": "PipelineStack/Pipeline/Pipeline/MultiRegion", + "children": { + "us-east-1.Queue1.Prepare": { + "id": "us-east-1.Queue1.Prepare", + "path": "PipelineStack/Pipeline/Pipeline/MultiRegion/us-east-1.Queue1.Prepare", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "us-west-2.Queue1.Prepare": { + "id": "us-west-2.Queue1.Prepare", + "path": "PipelineStack/Pipeline/Pipeline/MultiRegion/us-west-2.Queue1.Prepare", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "us-east-1.Queue1.Deploy": { + "id": "us-east-1.Queue1.Deploy", + "path": "PipelineStack/Pipeline/Pipeline/MultiRegion/us-east-1.Queue1.Deploy", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "us-west-2.Queue1.Deploy": { + "id": "us-west-2.Queue1.Deploy", + "path": "PipelineStack/Pipeline/Pipeline/MultiRegion/us-west-2.Queue1.Deploy", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1": { + "id": "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "path": "PipelineStack/Pipeline/Pipeline/MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1": { + "id": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1", + "children": { + "8389e75f-0810-4838-bf64-d6f85a95cf83": { + "id": "8389e75f-0810-4838-bf64-d6f85a95cf83", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-east-1/8389e75f-0810-4838-bf64-d6f85a95cf83", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1": { + "id": "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "path": "PipelineStack/Pipeline/Pipeline/MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1": { + "id": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-east-1", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2": { + "id": "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "path": "PipelineStack/Pipeline/Pipeline/MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2": { + "id": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2", + "children": { + "8389e75f-0810-4838-bf64-d6f85a95cf83": { + "id": "8389e75f-0810-4838-bf64-d6f85a95cf83", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-deploy-role-${AWS::AccountId}-us-west-2/8389e75f-0810-4838-bf64-d6f85a95cf83", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2": { + "id": "MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "path": "PipelineStack/Pipeline/Pipeline/MutableRolearn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2": { + "id": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "path": "PipelineStack/Pipeline/Pipeline/arn:${AWS::Partition}:iam::${AWS::AccountId}:role--cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-us-west-2", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codepipeline.Pipeline", + "version": "0.0.0" + } + }, + "CodeBuildActionRole": { + "id": "CodeBuildActionRole", + "path": "PipelineStack/Pipeline/CodeBuildActionRole", + "children": { + "ImportCodeBuildActionRole": { + "id": "ImportCodeBuildActionRole", + "path": "PipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/CodeBuildActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "PipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildSynthCdkBuildProject6BEFA8E6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutationDAA41400", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE", + "roles": [ + { + "Ref": "PipelineCodeBuildActionRole226DB0CB" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "PipelineStack/Pipeline/UpdatePipeline", + "children": { + "SelfMutation": { + "id": "SelfMutation", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation", + "children": { + "Role": { + "id": "Role", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:logs:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:codebuild:us-east-1:", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + "-*" + ] + ] + } + }, + { + "Action": "sts:AssumeRole", + "Condition": { + "ForAnyValue:StringEquals": { + "iam:ResourceTag/aws-cdk:bootstrap-role": [ + "image-publishing", + "file-publishing", + "deploy" + ] + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:*:iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/*" + ] + ] + } + }, + { + "Action": [ + "cloudformation:DescribeStacks", + "s3:ListBucket" + ], + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step PipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "encryptionKey": "alias/aws/s3", + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:7.0", + "imagePullCredentialsType": "CODEBUILD", + "privilegedMode": false, + "computeType": "BUILD_GENERAL1_SMALL" + }, + "serviceRole": { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutationRole57E559E8", + "Arn" + ] + }, + "source": { + "type": "CODEPIPELINE", + "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@2\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy PipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.pipelines.CodePipeline", + "version": "0.0.0" + } + }, + "us-east-1": { + "id": "us-east-1", + "path": "PipelineStack/us-east-1", + "children": { + "Queue1": { + "id": "Queue1", + "path": "PipelineStack/us-east-1/Queue1", + "children": { + "Queue": { + "id": "Queue", + "path": "PipelineStack/us-east-1/Queue1/Queue", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/us-east-1/Queue1/Queue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineStack/us-east-1/Queue1/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineStack/us-east-1/Queue1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stage", + "version": "0.0.0" + } + }, + "us-west-2": { + "id": "us-west-2", + "path": "PipelineStack/us-west-2", + "children": { + "Queue1": { + "id": "Queue1", + "path": "PipelineStack/us-west-2/Queue1", + "children": { + "Queue": { + "id": "Queue", + "path": "PipelineStack/us-west-2/Queue1/Queue", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/us-west-2/Queue1/Queue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineStack/us-west-2/Queue1/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineStack/us-west-2/Queue1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stage", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "cdk-integ-codepipeline-with-cross-region-replication-buckets": { + "id": "cdk-integ-codepipeline-with-cross-region-replication-buckets", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "cdk-integ-codepipeline-with-cross-region-replication-buckets/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.assets.json new file mode 100644 index 0000000000000..9cba80d2c32f7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "36.0.0", + "files": { + "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3": { + "source": { + "path": "asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3", + "packaging": "zip" + }, + "destinations": { + "current_account-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", + "objectKey": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" + } + } + }, + "dcb3b9d224db2e26297b5d99818cb49212a518e995d9fbba3f43d0f3cbb95373": { + "source": { + "path": "usEast1S3Stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", + "objectKey": "dcb3b9d224db2e26297b5d99818cb49212a518e995d9fbba3f43d0f3cbb95373.json", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.template.json new file mode 100644 index 0000000000000..e638647bfcba3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usEast1S3Stack.template.json @@ -0,0 +1,306 @@ +{ + "Resources": { + "RegionalBucketF5C80E4B": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "BucketName": "us-east-1-newpipeline-with-cross-region-replication-buckets", + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ], + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "RegionalBucketPolicyC6508E8A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "RegionalBucketF5C80E4B" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-east-1" + ] + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "RegionalBucketAutoDeleteObjectsCustomResource10BE89C6": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "RegionalBucketF5C80E4B" + } + }, + "DependsOn": [ + "RegionalBucketPolicyC6508E8A" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1" + }, + "S3Key": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "RegionalBucketF5C80E4B" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + } + }, + "Outputs": { + "ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C": { + "Value": { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "Export": { + "Name": "usEast1S3Stack:ExportsOutputFnGetAttRegionalBucketF5C80E4BArn49E35D9C" + } + }, + "ExportsOutputRefRegionalBucketF5C80E4B3E52A444": { + "Value": { + "Ref": "RegionalBucketF5C80E4B" + }, + "Export": { + "Name": "usEast1S3Stack:ExportsOutputRefRegionalBucketF5C80E4B3E52A444" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.assets.json new file mode 100644 index 0000000000000..b8c0fa5f9737e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "36.0.0", + "files": { + "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3": { + "source": { + "path": "asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3", + "packaging": "zip" + }, + "destinations": { + "current_account-us-west-2": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2", + "objectKey": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip", + "region": "us-west-2", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-west-2" + } + } + }, + "be060ef9e9df7c21dec49e21423280cd2c208089a6f149a020bd51bb222fd15f": { + "source": { + "path": "usWest2S3Stack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-us-west-2": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2", + "objectKey": "be060ef9e9df7c21dec49e21423280cd2c208089a6f149a020bd51bb222fd15f.json", + "region": "us-west-2", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-west-2" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.template.json new file mode 100644 index 0000000000000..64ba53840c761 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.js.snapshot/usWest2S3Stack.template.json @@ -0,0 +1,285 @@ +{ + "Resources": { + "RegionalBucketF5C80E4B": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "AES256" + } + } + ] + }, + "BucketName": "us-west-2-newpipeline-with-cross-region-replication-buckets", + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + }, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ], + "VersioningConfiguration": { + "Status": "Enabled" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "RegionalBucketPolicyC6508E8A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "RegionalBucketF5C80E4B" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":role/cdk-hnb659fds-deploy-role-", + { + "Ref": "AWS::AccountId" + }, + "-us-west-2" + ] + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "RegionalBucketF5C80E4B", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "RegionalBucketAutoDeleteObjectsCustomResource10BE89C6": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "RegionalBucketF5C80E4B" + } + }, + "DependsOn": [ + "RegionalBucketPolicyC6508E8A" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-us-west-2" + }, + "S3Key": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "RegionalBucketF5C80E4B" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.ts new file mode 100644 index 0000000000000..ce91fd3fad3f4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.newpipeline-with-cross-region-replication-buckets.ts @@ -0,0 +1,112 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +/// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true +import * as sqs from 'aws-cdk-lib/aws-sqs'; +import { + App, + Stack, + StackProps, + Stage, + StageProps, + RemovalPolicy, +} from 'aws-cdk-lib'; +import { Construct } from 'constructs'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import * as pipelines from 'aws-cdk-lib/pipelines'; +import * as s3 from 'aws-cdk-lib/aws-s3'; + +const regionalBuckets: {[key: string]: string} = { + 'us-east-1': 'us-east-1-newpipeline-with-cross-region-replication-buckets', + 'us-west-2': 'us-west-2-newpipeline-with-cross-region-replication-buckets', +}; + +interface CrossRegionReplicationBuckets { + [key: string]: s3.Bucket; +} + +class RegionalS3Stack extends Stack { + public bucket: s3.Bucket; + + constructor(scope: Construct, id: string, props?: StackProps, bucketName?: string) { + super(scope, id, props); + + this.bucket = new s3.Bucket(this, 'RegionalBucket', { + bucketName: bucketName, + blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + encryption: s3.BucketEncryption.S3_MANAGED, + enforceSSL: true, + versioned: true, + autoDeleteObjects: true, + removalPolicy: RemovalPolicy.DESTROY, + }); + } +} + +class PipelineStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps, crossRegionReplicationBuckets?: CrossRegionReplicationBuckets) { + super(scope, id, props); + + const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.gitHub( + 'jose-clickup/cdk-pipelines-demo', + 'main', + ), + commands: ['npm ci', 'npm run build', 'npx cdk synth'], + }), + crossRegionReplicationBuckets, + }); + + const wave = pipeline.addWave('MultiRegion'); + for (const region in regionalBuckets) { + wave.addStage(new AppStage(this, region, { env: { region: region } })); + } + } +} + +class AppStage extends Stage { + constructor(scope: Construct, id: string, props?: StageProps) { + super(scope, id, props); + + const stack1 = new Stack(this, 'Queue1'); + new sqs.Queue(stack1, 'Queue'); + } +} + +const app = new App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); + +const usEast1S3Stack = new RegionalS3Stack(app, 'usEast1S3Stack', { + env: { + region: 'us-east-1', + }, +}, regionalBuckets['us-east-1']); + +const usWest2S3Stack = new RegionalS3Stack(app, 'usWest2S3Stack', { + env: { + region: 'us-west-2', + }, +}, regionalBuckets['us-west-2']); + +const crossRegionReplicationBuckets = { + 'us-east-1': usEast1S3Stack.bucket, + 'us-west-2': usWest2S3Stack.bucket, +}; + +const pipelineStack = new PipelineStack(app, 'PipelineStack', { + env: { + region: 'us-east-1', + }, +}, crossRegionReplicationBuckets); + +new integ.IntegTest( + app, + 'cdk-integ-codepipeline-with-cross-region-replication-buckets', + { + testCases: [pipelineStack, usEast1S3Stack, usWest2S3Stack], + }, +); + +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda-go-alpha/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-go-alpha/lib/bundling.ts index f219915c068f3..de91e04bb360d 100644 --- a/packages/@aws-cdk/aws-lambda-go-alpha/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-go-alpha/lib/bundling.ts @@ -209,7 +209,7 @@ export class Bundling implements cdk.BundlingOptions { const goBuildCommand: string = [ 'go', 'build', hasVendor ? '-mod=vendor': '', - '-o', `${pathJoin(outputDir, 'bootstrap')}`, + '-o', `"${pathJoin(outputDir, 'bootstrap')}"`, `${this.props.goBuildFlags ? this.props.goBuildFlags.join(' ') : ''}`, `${this.relativeEntryPath.replace(/\\/g, '/')}`, ].filter(c => !!c).join(' '); diff --git a/packages/@aws-cdk/aws-lambda-go-alpha/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-go-alpha/test/bundling.test.ts index 3fdf7aa467f5f..f9a8559add078 100644 --- a/packages/@aws-cdk/aws-lambda-go-alpha/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-go-alpha/test/bundling.test.ts @@ -53,7 +53,7 @@ test('bundling', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap ./cmd/api', + 'go build -o "/asset-output/bootstrap" ./cmd/api', ].join(' && '), ], }), @@ -81,7 +81,7 @@ test('bundling with file as entry', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap ./main.go', + 'go build -o "/asset-output/bootstrap" ./main.go', ].join(' && '), ], }), @@ -102,7 +102,7 @@ test('bundling with file in subdirectory as entry', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap ./cmd/api/main.go', + 'go build -o "/asset-output/bootstrap" ./cmd/api/main.go', ].join(' && '), ], }), @@ -123,7 +123,7 @@ test('bundling with file other than main.go in subdirectory as entry', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap ./cmd/api/api.go', + 'go build -o "/asset-output/bootstrap" ./cmd/api/api.go', ].join(' && '), ], }), @@ -265,7 +265,7 @@ test('Go build flags can be passed', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap -ldflags "-s -w" ./cmd/api', + 'go build -o "/asset-output/bootstrap" -ldflags "-s -w" ./cmd/api', ].join(' && '), ], }), @@ -297,7 +297,7 @@ test('AssetHashType can be specified', () => { command: [ 'bash', '-c', [ - 'go build -o /asset-output/bootstrap ./cmd/api', + 'go build -o "/asset-output/bootstrap" ./cmd/api', ].join(' && '), ], }), diff --git a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES index 9927af86bd644..c430595bb0514 100644 --- a/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES +++ b/packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES @@ -207,7 +207,7 @@ The @aws-cdk/cli-lib-alpha package includes the following third-party software/l ---------------- -** @jsii/check-node@1.92.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.92.0 | Apache-2.0 +** @jsii/check-node@1.93.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.93.0 | Apache-2.0 jsii Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -471,7 +471,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE ---------------- -** aws-sdk@2.1498.0 - https://www.npmjs.com/package/aws-sdk/v/2.1498.0 | Apache-2.0 +** aws-sdk@2.1517.0 - https://www.npmjs.com/package/aws-sdk/v/2.1517.0 | Apache-2.0 AWS SDK for JavaScript Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -668,7 +668,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ---------------- -** cdk-from-cfn@0.84.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.84.0 | MIT OR Apache-2.0 +** cdk-from-cfn@0.91.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.91.0 | MIT OR Apache-2.0 ---------------- diff --git a/packages/@aws-cdk/cloudformation-diff/lib/diff-template.ts b/packages/@aws-cdk/cloudformation-diff/lib/diff-template.ts index 6e06e56f90af1..055bc3be8248b 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/diff-template.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/diff-template.ts @@ -1,3 +1,7 @@ +// The SDK is only used to reference `DescribeChangeSetOutput`, so the SDK is added as a devDependency. +// The SDK should not make network calls here +// eslint-disable-next-line import/no-extraneous-dependencies +import { CloudFormation } from 'aws-sdk'; import * as impl from './diff'; import * as types from './diff/types'; import { deepEqual, diffKeyedEntities, unionOf } from './diff/util'; @@ -33,12 +37,33 @@ const DIFF_HANDLERS: HandlerRegistry = { * * @param currentTemplate the current state of the stack. * @param newTemplate the target state of the stack. + * @param changeSet the change set for this stack. * * @returns a +types.TemplateDiff+ object that represents the changes that will happen if * a stack which current state is described by +currentTemplate+ is updated with * the template +newTemplate+. */ -export function diffTemplate(currentTemplate: { [key: string]: any }, newTemplate: { [key: string]: any }): types.TemplateDiff { +export function fullDiff( + currentTemplate: { [key: string]: any }, + newTemplate: { [key: string]: any }, + changeSet?: CloudFormation.DescribeChangeSetOutput, +): types.TemplateDiff { + + normalize(currentTemplate); + normalize(newTemplate); + const theDiff = diffTemplate(currentTemplate, newTemplate); + if (changeSet) { + filterFalsePositivies(theDiff, changeSet); + } + + return theDiff; +} + +function diffTemplate( + currentTemplate: { [key: string]: any }, + newTemplate: { [key: string]: any }, +): types.TemplateDiff { + // Base diff const theDiff = calculateTemplateDiff(currentTemplate, newTemplate); @@ -105,7 +130,6 @@ function calculateTemplateDiff(currentTemplate: { [key: string]: any }, newTempl const handler: DiffHandler = DIFF_HANDLERS[key] || ((_diff, oldV, newV) => unknown[key] = impl.diffUnknown(oldV, newV)); handler(differences, oldValue, newValue); - } if (Object.keys(unknown).length > 0) { differences.unknown = new types.DifferenceCollection(unknown); @@ -184,3 +208,93 @@ function deepCopy(x: any): any { return x; } + +function filterFalsePositivies(diff: types.TemplateDiff, changeSet: CloudFormation.DescribeChangeSetOutput) { + const replacements = findResourceReplacements(changeSet); + diff.resources.forEachDifference((logicalId: string, change: types.ResourceDifference) => { + change.forEachDifference((type: 'Property' | 'Other', name: string, value: types.Difference | types.PropertyDifference) => { + if (type === 'Property') { + if (!replacements[logicalId]) { + (value as types.PropertyDifference).changeImpact = types.ResourceImpact.NO_CHANGE; + (value as types.PropertyDifference).isDifferent = false; + return; + } + switch (replacements[logicalId].propertiesReplaced[name]) { + case 'Always': + (value as types.PropertyDifference).changeImpact = types.ResourceImpact.WILL_REPLACE; + break; + case 'Never': + (value as types.PropertyDifference).changeImpact = types.ResourceImpact.WILL_UPDATE; + break; + case 'Conditionally': + (value as types.PropertyDifference).changeImpact = types.ResourceImpact.MAY_REPLACE; + break; + case undefined: + (value as types.PropertyDifference).changeImpact = types.ResourceImpact.NO_CHANGE; + (value as types.PropertyDifference).isDifferent = false; + break; + // otherwise, defer to the changeImpact from `diffTemplate` + } + } else if (type === 'Other') { + switch (name) { + case 'Metadata': + change.setOtherChange('Metadata', new types.Difference(value.newValue, value.newValue)); + break; + } + } + }); + }); +} + +function findResourceReplacements(changeSet: CloudFormation.DescribeChangeSetOutput): types.ResourceReplacements { + const replacements: types.ResourceReplacements = {}; + for (const resourceChange of changeSet.Changes ?? []) { + const propertiesReplaced: { [propName: string]: types.ChangeSetReplacement } = {}; + for (const propertyChange of resourceChange.ResourceChange?.Details ?? []) { + if (propertyChange.Target?.Attribute === 'Properties') { + const requiresReplacement = propertyChange.Target.RequiresRecreation === 'Always'; + if (requiresReplacement && propertyChange.Evaluation === 'Static') { + propertiesReplaced[propertyChange.Target.Name!] = 'Always'; + } else if (requiresReplacement && propertyChange.Evaluation === 'Dynamic') { + // If Evaluation is 'Dynamic', then this may cause replacement, or it may not. + // see 'Replacement': https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ResourceChange.html + propertiesReplaced[propertyChange.Target.Name!] = 'Conditionally'; + } else { + propertiesReplaced[propertyChange.Target.Name!] = propertyChange.Target.RequiresRecreation as types.ChangeSetReplacement; + } + } + } + replacements[resourceChange.ResourceChange?.LogicalResourceId!] = { + resourceReplaced: resourceChange.ResourceChange?.Replacement === 'True', + propertiesReplaced, + }; + } + + return replacements; +} + +function normalize(template: any) { + if (typeof template === 'object') { + for (const key of (Object.keys(template ?? {}))) { + if (key === 'Fn::GetAtt' && typeof template[key] === 'string') { + template[key] = template[key].split('.'); + continue; + } else if (key === 'DependsOn') { + if (typeof template[key] === 'string') { + template[key] = [template[key]]; + } else if (Array.isArray(template[key])) { + template[key] = template[key].sort(); + } + continue; + } + + if (Array.isArray(template[key])) { + for (const element of (template[key])) { + normalize(element); + } + } else { + normalize(template[key]); + } + } + } +} diff --git a/packages/@aws-cdk/cloudformation-diff/lib/diff/types.ts b/packages/@aws-cdk/cloudformation-diff/lib/diff/types.ts index 7bd91b58f6ee4..e85265bf99c1f 100644 --- a/packages/@aws-cdk/cloudformation-diff/lib/diff/types.ts +++ b/packages/@aws-cdk/cloudformation-diff/lib/diff/types.ts @@ -6,6 +6,15 @@ import { SecurityGroupChanges } from '../network/security-group-changes'; export type PropertyMap = {[key: string]: any }; +export type ResourceReplacements = { [logicalId: string]: ResourceReplacement }; + +export interface ResourceReplacement { + resourceReplaced: boolean, + propertiesReplaced: { [propertyName: string]: ChangeSetReplacement }; +} + +export type ChangeSetReplacement = 'Always' | 'Never' | 'Conditionally'; + /** Semantic differences between two CloudFormation templates. */ export class TemplateDiff implements ITemplateDiff { public awsTemplateFormatVersion?: Difference; @@ -296,7 +305,7 @@ export class Difference implements IDifference { * * isDifferent => (isUpdate | isRemoved | isUpdate) */ - public readonly isDifferent: boolean; + public isDifferent: boolean; /** * @param oldValue the old value, cannot be equal (to the sense of +deepEqual+) to +newValue+. @@ -327,7 +336,7 @@ export class Difference implements IDifference { } export class PropertyDifference extends Difference { - public readonly changeImpact?: ResourceImpact; + public changeImpact?: ResourceImpact; constructor(oldValue: ValueType | undefined, newValue: ValueType | undefined, args: { changeImpact?: ResourceImpact }) { super(oldValue, newValue); @@ -352,6 +361,10 @@ export class DifferenceCollection> { return ret; } + public remove(logicalId: string): void { + delete this.diffs[logicalId]; + } + public get logicalIds(): string[] { return Object.keys(this.changes); } @@ -621,6 +634,18 @@ export class ResourceDifference implements IDifference { this.propertyDiffs[propertyName] = change; } + /** + * Replace a OtherChange in this object + * + * This affects the property diff as it is summarized to users, but it DOES + * NOT affect either the "oldValue" or "newValue" values; those still contain + * the actual template values as provided by the user (they might still be + * used for downstream processing). + */ + public setOtherChange(otherName: string, change: PropertyDifference) { + this.otherDiffs[otherName] = change; + } + public get changeImpact(): ResourceImpact { // Check the Type first if (this.resourceTypes.oldType !== this.resourceTypes.newType) { diff --git a/packages/@aws-cdk/cloudformation-diff/package.json b/packages/@aws-cdk/cloudformation-diff/package.json index 0afbb125805c8..51b2fb7d0963b 100644 --- a/packages/@aws-cdk/cloudformation-diff/package.json +++ b/packages/@aws-cdk/cloudformation-diff/package.json @@ -23,8 +23,8 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-cdk/aws-service-spec": "^0.0.38", - "@aws-cdk/service-spec-types": "^0.0.38", + "@aws-cdk/aws-service-spec": "^0.0.40", + "@aws-cdk/service-spec-types": "^0.0.40", "chalk": "^4", "diff": "^5.1.0", "fast-deep-equal": "^3.1.3", @@ -38,6 +38,7 @@ "@types/string-width": "^4.0.1", "fast-check": "^3.14.0", "jest": "^29.7.0", + "aws-sdk": "2.1516.0", "ts-jest": "^29.1.1" }, "repository": { diff --git a/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts b/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts index 5c755339fd737..b211c1d17c085 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/diff-template.test.ts @@ -1,6 +1,6 @@ import * as fc from 'fast-check'; import { arbitraryTemplate } from './test-arbitraries'; -import { diffTemplate, ResourceImpact } from '../lib/diff-template'; +import { fullDiff, ResourceImpact } from '../lib/diff-template'; const POLICY_DOCUMENT = { foo: 'Bar' }; // Obviously a fake one! const BUCKET_POLICY_RESOURCE = { @@ -27,7 +27,7 @@ test('when there is no difference', () => { // Making a JSON-clone, because === is cheating! const newTemplate = JSON.parse(JSON.stringify(currentTemplate)); - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(0); }); @@ -36,7 +36,7 @@ test('when a resource is created', () => { const newTemplate = { Resources: { BucketResource: { Type: 'AWS::S3::Bucket' } } }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketResource; @@ -60,7 +60,7 @@ test('when a resource is deleted (no DeletionPolicy)', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketPolicyResource; @@ -89,7 +89,7 @@ test('when a resource is deleted (DeletionPolicy=Retain)', () => { Resources: { BucketResource: { Type: 'AWS::S3::Bucket' } }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketPolicyResource; @@ -130,7 +130,7 @@ test('when a property changes', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketResource; @@ -161,7 +161,7 @@ test('change in dependencies counts as a simple update', () => { }, }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); // THEN expect(differences.differenceCount).toBe(1); @@ -196,7 +196,7 @@ test('when a property is deleted', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketResource; @@ -234,7 +234,7 @@ test('when a property is added', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketResource; @@ -268,7 +268,7 @@ test('when a resource type changed', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.BucketResource; @@ -318,7 +318,7 @@ test('resource replacement is tracked through references', () => { }, }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); // THEN expect(differences.resources.differenceCount).toBe(3); @@ -370,10 +370,10 @@ test('adding and removing quotes from a numeric property causes no changes', () }, }, }; - let differences = diffTemplate(currentTemplate, newTemplate); + let differences = fullDiff(currentTemplate, newTemplate); expect(differences.resources.differenceCount).toBe(0); - differences = diffTemplate(newTemplate, currentTemplate); + differences = fullDiff(newTemplate, currentTemplate); expect(differences.resources.differenceCount).toBe(0); }); @@ -401,122 +401,9 @@ test('versions are correctly detected as not numbers', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.resources.differenceCount).toBe(1); }); - -test('single element arrays are equivalent to the single element in DependsOn expressions', () => { - // GIVEN - const currentTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: ['SomeResource'], - }, - }, - }; - - // WHEN - const newTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: 'SomeResource', - }, - }, - }; - - let differences = diffTemplate(currentTemplate, newTemplate); - expect(differences.resources.differenceCount).toBe(0); - - differences = diffTemplate(newTemplate, currentTemplate); - expect(differences.resources.differenceCount).toBe(0); -}); - -test('array equivalence is independent of element order in DependsOn expressions', () => { - // GIVEN - const currentTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: ['SomeResource', 'AnotherResource'], - }, - }, - }; - - // WHEN - const newTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: ['AnotherResource', 'SomeResource'], - }, - }, - }; - - let differences = diffTemplate(currentTemplate, newTemplate); - expect(differences.resources.differenceCount).toBe(0); - - differences = diffTemplate(newTemplate, currentTemplate); - expect(differences.resources.differenceCount).toBe(0); -}); - -test('arrays of different length are considered unequal in DependsOn expressions', () => { - // GIVEN - const currentTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: ['SomeResource', 'AnotherResource', 'LastResource'], - }, - }, - }; - - // WHEN - const newTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - DependsOn: ['AnotherResource', 'SomeResource'], - }, - }, - }; - - let differences = diffTemplate(currentTemplate, newTemplate); - expect(differences.resources.differenceCount).toBe(1); - - differences = diffTemplate(newTemplate, currentTemplate); - expect(differences.resources.differenceCount).toBe(1); -}); - -test('arrays that differ only in element order are considered unequal outside of DependsOn expressions', () => { - // GIVEN - const currentTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - BucketName: { 'Fn::Select': [0, ['name1', 'name2']] }, - }, - }, - }; - - // WHEN - const newTemplate = { - Resources: { - BucketResource: { - Type: 'AWS::S3::Bucket', - BucketName: { 'Fn::Select': [0, ['name2', 'name1']] }, - }, - }, - }; - - let differences = diffTemplate(currentTemplate, newTemplate); - expect(differences.resources.differenceCount).toBe(1); - - differences = diffTemplate(newTemplate, currentTemplate); - expect(differences.resources.differenceCount).toBe(1); -}); - test('boolean properties are considered equal with their stringified counterparts', () => { // GIVEN const currentTemplate = { @@ -545,7 +432,7 @@ test('boolean properties are considered equal with their stringified counterpart }; // WHEN - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); // THEN expect(differences.differenceCount).toBe(0); @@ -577,10 +464,10 @@ test('when a property changes including equivalent DependsOn', () => { }; // THEN - let differences = diffTemplate(currentTemplate, newTemplate); + let differences = fullDiff(currentTemplate, newTemplate); expect(differences.resources.differenceCount).toBe(1); - differences = diffTemplate(newTemplate, currentTemplate); + differences = fullDiff(newTemplate, currentTemplate); expect(differences.resources.differenceCount).toBe(1); }); @@ -615,7 +502,7 @@ test.each([ }, }; // WHEN - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); // THEN expect(differences.differenceCount).toBe(1); @@ -651,7 +538,7 @@ test('when a property with a number-like format doesn\'t change', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(0); expect(differences.resources.differenceCount).toBe(0); const difference = differences.resources.changes.BucketResource; @@ -677,7 +564,7 @@ test('handles a resource changing its Type', () => { }, }; - const differences = diffTemplate(currentTemplate, newTemplate); + const differences = fullDiff(currentTemplate, newTemplate); expect(differences.differenceCount).toBe(1); expect(differences.resources.differenceCount).toBe(1); const difference = differences.resources.changes.FunctionApi; @@ -696,8 +583,538 @@ test('diffing any two arbitrary templates should not crash', () => { // We're not interested in making sure we find the right differences here -- just // that we're not crashing. fc.assert(fc.property(arbitraryTemplate, arbitraryTemplate, (t1, t2) => { - diffTemplate(t1, t2); + fullDiff(t1, t2); }), { // path: '1:0:0:0:3:0:1:1:1:1:1:1:1:1:1:1:1:1:1:2:1:1:1', }); }); + +test('metadata changes are rendered in the diff', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: 'magic-bucket', + Metadata: { + 'aws:cdk:path': '/foo/BucketResource', + }, + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: 'magic-bucket', + Metadata: { + 'aws:cdk:path': '/bar/BucketResource', + }, + }, + }, + }; + + // THEN + let differences = fullDiff(currentTemplate, newTemplate); + expect(differences.differenceCount).toBe(1); + + differences = fullDiff(newTemplate, currentTemplate); + expect(differences.resources.differenceCount).toBe(1); +}); + +describe('changeset', () => { + test('changeset overrides spec replacements', () => { + // GIVEN + const currentTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'Name1' }, // Immutable prop + }, + }, + }; + const newTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: { Ref: 'BucketName' } }, // No change + }, + }, + }; + + // WHEN + const differences = fullDiff(currentTemplate, newTemplate, { + Parameters: [ + { + ParameterKey: 'BucketName', + ParameterValue: 'Name1', + }, + ], + Changes: [], + }); + + // THEN + expect(differences.differenceCount).toBe(0); + }); + + test('changeset does not overrides spec additions or deletions', () => { + // GIVEN + const currentTemplate = { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'MagicBucket' }, + }, + }, + }; + const newTemplate = { + Resources: { + Queue: { + Type: 'AWS::SQS::Queue', + Properties: { QueueName: 'MagicQueue' }, + }, + }, + }; + + // WHEN + const differences = fullDiff(currentTemplate, newTemplate, { + Changes: [ + { + ResourceChange: { + Action: 'Remove', + LogicalResourceId: 'Bucket', + ResourceType: 'AWS::S3::Bucket', + Details: [], + }, + }, + { + ResourceChange: { + Action: 'Add', + LogicalResourceId: 'Queue', + ResourceType: 'AWS::SQS::Queue', + Details: [], + }, + }, + ], + }); + + // A realistic changeset will include Additions and Removals, but this shows that we don't use the changeset to determine additions or removals + const emptyChangeSetDifferences = fullDiff(currentTemplate, newTemplate, { + Changes: [], + }); + + // THEN + expect(differences.differenceCount).toBe(2); + expect(emptyChangeSetDifferences.differenceCount).toBe(2); + }); + + test('changeset replacements are respected', () => { + // GIVEN + const currentTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'Name1' }, // Immutable prop + }, + }, + }; + const newTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: { Ref: 'BucketName' } }, // 'Name1' -> 'Name2' + }, + }, + }; + + // WHEN + const differences = fullDiff(currentTemplate, newTemplate, { + Parameters: [ + { + ParameterKey: 'BucketName', + ParameterValue: 'Name2', + }, + ], + Changes: [ + { + Type: 'Resource', + ResourceChange: { + Action: 'Modify', + LogicalResourceId: 'Bucket', + ResourceType: 'AWS::S3::Bucket', + Replacement: 'True', + Details: [ + { + Target: { + Attribute: 'Properties', + Name: 'BucketName', + RequiresRecreation: 'Always', + }, + Evaluation: 'Static', + ChangeSource: 'DirectModification', + }, + ], + }, + }, + ], + }); + + // THEN + expect(differences.differenceCount).toBe(1); + }); + + // This is directly in-line with changeset behavior, + // see 'Replacement': https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ResourceChange.html + test('dynamic changeset replacements are considered conditional replacements', () => { + // GIVEN + const currentTemplate = { + Resources: { + Instance: { + Type: 'AWS::EC2::Instance', + Properties: { + ImageId: 'ami-79fd7eee', + KeyName: 'rsa-is-fun', + }, + }, + }, + }; + const newTemplate = { + Resources: { + Instance: { + Type: 'AWS::EC2::Instance', + Properties: { + ImageId: 'ami-79fd7eee', + KeyName: 'but-sha-is-cool', + }, + }, + }, + }; + + // WHEN + const differences = fullDiff(currentTemplate, newTemplate, { + Changes: [ + { + Type: 'Resource', + ResourceChange: { + Action: 'Modify', + LogicalResourceId: 'Instance', + ResourceType: 'AWS::EC2::Instance', + Replacement: 'Conditional', + Details: [ + { + Target: { + Attribute: 'Properties', + Name: 'KeyName', + RequiresRecreation: 'Always', + }, + Evaluation: 'Dynamic', + ChangeSource: 'DirectModification', + }, + ], + }, + }, + ], + }); + + // THEN + expect(differences.differenceCount).toBe(1); + expect(differences.resources.changes.Instance.changeImpact).toEqual(ResourceImpact.MAY_REPLACE); + expect(differences.resources.changes.Instance.propertyUpdates).toEqual({ + KeyName: { + changeImpact: ResourceImpact.MAY_REPLACE, + isDifferent: true, + oldValue: 'rsa-is-fun', + newValue: 'but-sha-is-cool', + }, + }); + }); + + test('changeset resource replacement is not tracked through references', () => { + // GIVEN + const currentTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'Name1' }, // Immutable prop + }, + Queue: { + Type: 'AWS::SQS::Queue', + Properties: { QueueName: { Ref: 'Bucket' } }, // Immutable prop + }, + Topic: { + Type: 'AWS::SNS::Topic', + Properties: { TopicName: { Ref: 'Queue' } }, // Immutable prop + }, + }, + }; + + // WHEN + const newTemplate = { + Parameters: { + BucketName: { + Type: 'String', + }, + }, + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: { Ref: 'BucketName' } }, + }, + Queue: { + Type: 'AWS::SQS::Queue', + Properties: { QueueName: { Ref: 'Bucket' } }, + }, + Topic: { + Type: 'AWS::SNS::Topic', + Properties: { TopicName: { Ref: 'Queue' } }, + }, + }, + }; + const differences = fullDiff(currentTemplate, newTemplate, { + Parameters: [ + { + ParameterKey: 'BucketName', + ParameterValue: 'Name1', + }, + ], + Changes: [ + { + Type: 'Resource', + ResourceChange: { + Action: 'Modify', + LogicalResourceId: 'Bucket', + ResourceType: 'AWS::S3::Bucket', + Replacement: 'False', + Details: [], + }, + }, + ], + }); + + // THEN + expect(differences.resources.differenceCount).toBe(0); + }); + + test('Fn::GetAtt short form and long form are equivalent', () => { + // GIVEN + const currentTemplate = { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'BucketName' }, + }, + }, + Outputs: { + BucketArnOneWay: { 'Fn::GetAtt': ['BucketName', 'Arn'] }, + BucketArnAnotherWay: { 'Fn::GetAtt': 'BucketName.Arn' }, + }, + }; + const newTemplate = { + Resources: { + Bucket: { + Type: 'AWS::S3::Bucket', + Properties: { BucketName: 'BucketName' }, + }, + }, + Outputs: { + BucketArnOneWay: { 'Fn::GetAtt': 'BucketName.Arn' }, + BucketArnAnotherWay: { 'Fn::GetAtt': ['BucketName', 'Arn'] }, + }, + }; + + // WHEN + const differences = fullDiff(currentTemplate, newTemplate); + + // THEN + expect(differences.differenceCount).toBe(0); + }); + + test('metadata changes are obscured from the diff', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: 'magic-bucket', + Metadata: { + 'aws:cdk:path': '/foo/BucketResource', + }, + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: 'magic-bucket', + Metadata: { + 'aws:cdk:path': '/bar/BucketResource', + }, + }, + }, + }; + + // THEN + let differences = fullDiff(currentTemplate, newTemplate, {}); + expect(differences.differenceCount).toBe(0); + }); + + test('single element arrays are equivalent to the single element in DependsOn expressions', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['SomeResource'], + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: 'SomeResource', + }, + }, + }; + + let differences = fullDiff(currentTemplate, newTemplate, {}); + expect(differences.resources.differenceCount).toBe(0); + + differences = fullDiff(newTemplate, currentTemplate, {}); + expect(differences.resources.differenceCount).toBe(0); + }); + + test('array equivalence is independent of element order in DependsOn expressions', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['SomeResource', 'AnotherResource'], + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['AnotherResource', 'SomeResource'], + }, + }, + }; + + let differences = fullDiff(currentTemplate, newTemplate, {}); + expect(differences.resources.differenceCount).toBe(0); + + differences = fullDiff(newTemplate, currentTemplate, {}); + expect(differences.resources.differenceCount).toBe(0); + }); + + test('arrays of different length are considered unequal in DependsOn expressions', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['SomeResource', 'AnotherResource', 'LastResource'], + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + DependsOn: ['AnotherResource', 'SomeResource'], + }, + }, + }; + + // dependsOn changes do not appear in the changeset + let differences = fullDiff(currentTemplate, newTemplate, {}); + expect(differences.resources.differenceCount).toBe(1); + + differences = fullDiff(newTemplate, currentTemplate, {}); + expect(differences.resources.differenceCount).toBe(1); + }); + + test('arrays that differ only in element order are considered unequal outside of DependsOn expressions', () => { + // GIVEN + const currentTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: { 'Fn::Select': [0, ['name1', 'name2']] }, + }, + }, + }; + + // WHEN + const newTemplate = { + Resources: { + BucketResource: { + Type: 'AWS::S3::Bucket', + BucketName: { 'Fn::Select': [0, ['name2', 'name1']] }, + }, + }, + }; + + let differences = fullDiff(currentTemplate, newTemplate, { + Changes: [ + { + Type: 'Resource', + ResourceChange: { + Action: 'Modify', + LogicalResourceId: 'BucketResource', + ResourceType: 'AWS::S3::Bucket', + Replacement: 'True', + Details: [{ + Evaluation: 'Direct', + Target: { + Attribute: 'Properties', + Name: 'BucketName', + RequiresRecreation: 'Always', + }, + }], + }, + }, + ], + }); + expect(differences.resources.differenceCount).toBe(1); + }); +}); diff --git a/packages/@aws-cdk/cloudformation-diff/test/iam/broadening.test.ts b/packages/@aws-cdk/cloudformation-diff/test/iam/broadening.test.ts index afc53da90baa4..4d67d104f3a68 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/iam/broadening.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/iam/broadening.test.ts @@ -1,10 +1,10 @@ -import { diffTemplate, formatSecurityChanges } from '../../lib'; +import { fullDiff, formatSecurityChanges } from '../../lib'; import { poldoc, resource, template } from '../util'; describe('broadening is', () => { test('adding of positive statements', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc({ @@ -22,7 +22,7 @@ describe('broadening is', () => { test('permissions diff can be printed', () => { // GIVEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc({ @@ -47,7 +47,7 @@ describe('broadening is', () => { test('adding of positive statements to an existing policy', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc( @@ -85,7 +85,7 @@ describe('broadening is', () => { test('removal of not-statements', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc({ @@ -103,7 +103,7 @@ describe('broadening is', () => { test('changing of resource target', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc( @@ -135,7 +135,7 @@ describe('broadening is', () => { test('addition of ingress rules', () => { // WHEN - const diff = diffTemplate( + const diff = fullDiff( template({ }), template({ @@ -157,7 +157,7 @@ describe('broadening is', () => { test('addition of egress rules', () => { // WHEN - const diff = diffTemplate( + const diff = fullDiff( template({ }), template({ @@ -181,7 +181,7 @@ describe('broadening is', () => { describe('broadening is not', () => { test('removal of positive statements from an existing policy', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc( diff --git a/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts b/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts index c9e70ec456c4e..bc2638029ad90 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/iam/detect-changes.test.ts @@ -1,4 +1,4 @@ -import { diffTemplate } from '../../lib'; +import { fullDiff } from '../../lib'; import { MaybeParsed } from '../../lib/diff/maybe-parsed'; import { IamChangesJson } from '../../lib/iam/iam-changes'; import { deepRemoveUndefined } from '../../lib/util'; @@ -6,7 +6,7 @@ import { poldoc, policy, resource, role, template } from '../util'; test('shows new AssumeRolePolicyDocument', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyRole: role({ AssumeRolePolicyDocument: poldoc({ Action: 'sts:AssumeRole', @@ -32,7 +32,7 @@ test('shows new AssumeRolePolicyDocument', () => { test('implicitly knows principal of identity policy for all resource types', () => { for (const attr of ['Roles', 'Users', 'Groups']) { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyPolicy: policy({ [attr]: [{ Ref: 'MyRole' }], PolicyDocument: poldoc({ @@ -60,7 +60,7 @@ test('implicitly knows principal of identity policy for all resource types', () test('policies on an identity object', () => { for (const resourceType of ['Role', 'User', 'Group']) { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyIdentity: resource(`AWS::IAM::${resourceType}`, { Policies: [ { @@ -90,7 +90,7 @@ test('policies on an identity object', () => { }); test('statement is an intrinsic', () => { - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyIdentity: resource('AWS::IAM::User', { Policies: [ { @@ -124,7 +124,7 @@ test('statement is an intrinsic', () => { test('if policy is attached to multiple roles all are shown', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyPolicy: policy({ Roles: [{ Ref: 'MyRole' }, { Ref: 'ThyRole' }], PolicyDocument: poldoc({ @@ -156,7 +156,7 @@ test('if policy is attached to multiple roles all are shown', () => { test('correctly parses Lambda permissions', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyPermission: resource('AWS::Lambda::Permission', { Action: 'lambda:InvokeFunction', FunctionName: { Ref: 'MyFunction' }, @@ -185,7 +185,7 @@ test('correctly parses Lambda permissions', () => { test('implicitly knows resource of (queue) resource policy even if * given', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue' }], PolicyDocument: poldoc({ @@ -212,7 +212,7 @@ test('implicitly knows resource of (queue) resource policy even if * given', () test('finds sole statement removals', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ BucketPolicy: resource('AWS::S3::BucketPolicy', { Bucket: { Ref: 'MyBucket' }, PolicyDocument: poldoc({ @@ -239,7 +239,7 @@ test('finds sole statement removals', () => { test('finds one of many statement removals', () => { // WHEN - const diff = diffTemplate( + const diff = fullDiff( template({ BucketPolicy: resource('AWS::S3::BucketPolicy', { Bucket: { Ref: 'MyBucket' }, @@ -283,7 +283,7 @@ test('finds one of many statement removals', () => { test('finds policy attachments', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ SomeRole: resource('AWS::IAM::Role', { ManagedPolicyArns: ['arn:policy'], }), @@ -302,7 +302,7 @@ test('finds policy attachments', () => { test('finds policy removals', () => { // WHEN - const diff = diffTemplate( + const diff = fullDiff( template({ SomeRole: resource('AWS::IAM::Role', { ManagedPolicyArns: ['arn:policy', 'arn:policy2'], @@ -327,7 +327,7 @@ test('finds policy removals', () => { test('queuepolicy queue change counts as removal+addition', () => { // WHEN - const diff = diffTemplate(template({ + const diff = fullDiff(template({ QueuePolicy: resource('AWS::SQS::QueuePolicy', { Queues: [{ Ref: 'MyQueue1' }], PolicyDocument: poldoc({ @@ -372,7 +372,7 @@ test('queuepolicy queue change counts as removal+addition', () => { test('supports Fn::If in the top-level property value of Role', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyRole: role({ AssumeRolePolicyDocument: poldoc({ Action: 'sts:AssumeRole', @@ -413,7 +413,7 @@ test('supports Fn::If in the top-level property value of Role', () => { test('supports Fn::If in the elements of an array-typed property of Role', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ MyRole: role({ AssumeRolePolicyDocument: poldoc({ Action: 'sts:AssumeRole', diff --git a/packages/@aws-cdk/cloudformation-diff/test/network/detect-changes.test.ts b/packages/@aws-cdk/cloudformation-diff/test/network/detect-changes.test.ts index 37f0e13da204b..6542a72eac807 100644 --- a/packages/@aws-cdk/cloudformation-diff/test/network/detect-changes.test.ts +++ b/packages/@aws-cdk/cloudformation-diff/test/network/detect-changes.test.ts @@ -1,9 +1,9 @@ -import { diffTemplate } from '../../lib'; +import { fullDiff } from '../../lib'; import { resource, template } from '../util'; test('detect addition of all types of rules', () => { // WHEN - const diff = diffTemplate({}, template({ + const diff = fullDiff({}, template({ SG: resource('AWS::EC2::SecurityGroup', { SecurityGroupIngress: [ { diff --git a/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts b/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts index 233b8349ab6a8..2277c95ac0915 100644 --- a/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts +++ b/packages/@aws-cdk/integ-runner/lib/runner/snapshot-test-runner.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { Writable, WritableOptions } from 'stream'; import { StringDecoder } from 'string_decoder'; -import { diffTemplate, formatDifferences, ResourceDifference, ResourceImpact } from '@aws-cdk/cloudformation-diff'; +import { fullDiff, formatDifferences, ResourceDifference, ResourceImpact } from '@aws-cdk/cloudformation-diff'; import { AssemblyManifestReader } from './private/cloud-assembly'; import { IntegRunnerOptions, IntegRunner, DEFAULT_SYNTH_OPTIONS } from './runner-base'; import { Diagnostic, DiagnosticReason, DestructiveChange, SnapshotVerificationOptions } from '../workers/common'; @@ -211,7 +211,7 @@ export class IntegSnapshotRunner extends IntegRunner { actualTemplate = this.canonicalizeTemplate(actualTemplate, actual[stackId].assets); expectedTemplate = this.canonicalizeTemplate(expectedTemplate, expected[stackId].assets); } - const templateDiff = diffTemplate(expectedTemplate, actualTemplate); + const templateDiff = fullDiff(expectedTemplate, actualTemplate); if (!templateDiff.isEmpty) { const allowedDestroyTypes = this.getAllowedDestroyTypesForStack(stackId) ?? []; diff --git a/packages/@aws-cdk/integ-runner/package.json b/packages/@aws-cdk/integ-runner/package.json index 3b3c3a89d2569..cf88a2c0340c8 100644 --- a/packages/@aws-cdk/integ-runner/package.json +++ b/packages/@aws-cdk/integ-runner/package.json @@ -74,7 +74,7 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0", "@aws-cdk/cloudformation-diff": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "@aws-cdk/aws-service-spec": "^0.0.38", + "@aws-cdk/aws-service-spec": "^0.0.40", "cdk-assets": "0.0.0", "@aws-cdk/cdk-cli-wrapper": "0.0.0", "aws-cdk": "0.0.0", diff --git a/packages/aws-cdk-lib/README.md b/packages/aws-cdk-lib/README.md index 1aa3f0db1b592..446cb1a118976 100644 --- a/packages/aws-cdk-lib/README.md +++ b/packages/aws-cdk-lib/README.md @@ -396,7 +396,7 @@ CloudFormation to re-read the secret. ## ARN manipulation Sometimes you will need to put together or pick apart Amazon Resource Names -(ARNs). The functions `stack.formatArn()` and `stack.parseArn()` exist for +(ARNs). The functions `stack.formatArn()` and `stack.splitArn()` exist for this purpose. `formatArn()` can be used to build an ARN from components. It will automatically @@ -409,12 +409,12 @@ declare const stack: Stack; stack.formatArn({ service: 'lambda', resource: 'function', - sep: ':', + arnFormat: ArnFormat.COLON_RESOURCE_NAME, resourceName: 'MyFunction' }); ``` -`parseArn()` can be used to get a single component from an ARN. `parseArn()` +`splitArn()` can be used to get a single component from an ARN. `splitArn()` will correctly deal with both literal ARNs and deploy-time values (tokens), but in case of a deploy-time value be aware that the result will be another deploy-time value which cannot be inspected in the CDK application. @@ -423,14 +423,13 @@ deploy-time value which cannot be inspected in the CDK application. declare const stack: Stack; // Extracts the function name out of an AWS Lambda Function ARN -const arnComponents = stack.parseArn(arn, ':'); +const arnComponents = stack.splitArn(arn, ArnFormat.COLON_RESOURCE_NAME); const functionName = arnComponents.resourceName; ``` -Note that depending on the service, the resource separator can be either -`:` or `/`, and the resource name can be either the 6th or 7th -component in the ARN. When using these functions, you will need to know -the format of the ARN you are dealing with. +Note that the format of the resource separator depends on the service and +may be any of the values supported by `ArnFormat`. When dealing with these +functions, it is important to know the format of the ARN you are dealing with. For an exhaustive list of ARN formats used in AWS, see [AWS ARNs and Namespaces](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) @@ -611,7 +610,7 @@ response to the CloudFormation service and handle various error cases. Set `serviceToken` to `lambda.functionArn` to use this provider: ```ts -const fn = new lambda.Function(this, 'MyProvider', functionProps); +const fn = new lambda.SingletonFunction(this, 'MyProvider', functionProps); new CustomResource(this, 'MyResource', { serviceToken: fn.functionArn, @@ -625,7 +624,8 @@ framework designed to implement simple and slim custom resource providers. It currently only supports Node.js-based user handlers, represents permissions as raw JSON blobs instead of `iam.PolicyStatement` objects, and it does not have support for asynchronous waiting (handler cannot exceed the 15min lambda -timeout). +timeout). The `CustomResourceProviderRuntime` supports runtime `nodejs12.x`, +`nodejs14.x`, `nodejs16.x`, `nodejs18.x`. [`@aws-cdk/core.CustomResourceProvider`]: https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CustomResourceProvider.html @@ -1096,6 +1096,31 @@ declare const regionTable: CfnMapping; regionTable.findInMap(Aws.REGION, 'regionName'); ``` +An optional default value can also be passed to `findInMap`. If either key is not found in the map and the mapping is lazy, `findInMap` will return the default value and not render the mapping. +If the mapping is not lazy or either key is an unresolved token, the call to `findInMap` will return a token that resolves to +`{ "Fn::FindInMap": [ "MapName", "TopLevelKey", "SecondLevelKey", { "DefaultValue": "DefaultValue" } ] }`, and the mapping will be rendered. +Note that the `AWS::LanguageExtentions` transform is added to enable the default value functionality. + +For example, the following code will again not produce anything in the "Mappings" section. The +call to `findInMap` will be able to resolve the value during synthesis and simply return +`'Region not found'`. + +```ts +const regionTable = new CfnMapping(this, 'RegionTable', { + mapping: { + 'us-east-1': { + regionName: 'US East (N. Virginia)', + }, + 'us-east-2': { + regionName: 'US East (Ohio)', + }, + }, + lazy: true, +}); + +regionTable.findInMap('us-west-1', 'regionName', 'Region not found'); +``` + [cfn-mappings]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html ### Dynamic References @@ -1187,6 +1212,13 @@ const stack = new Stack(app, 'StackName', { }); ``` +You can also set termination protection with the setter after you've instantiated the stack. + +```ts +const stack = new Stack(app, 'StackName', {}); +stack.terminationProtection = true; +``` + By default, termination protection is disabled. ### Description @@ -1245,6 +1277,20 @@ It's possible to synthesize the project with more Resources than the allowed (or Set the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources. +### Template Indentation + +The AWS CloudFormation templates generated by CDK include indentation by default. +Indentation makes the templates more readable, but also increases their size, +and CloudFormation templates cannot exceed 1MB. + +It's possible to reduce the size of your templates by suppressing indentation. + +To do this for all templates, set the context key `@aws-cdk/core:suppressTemplateIndentation` to `true`. + +To do this for a specific stack, add a `suppressTemplateIndentation: true` property to the +stack's `StackProps` parameter. You can also set this property to `false` to override +the context key setting. + ## App Context [Context values](https://docs.aws.amazon.com/cdk/v2/guide/context.html) are key-value pairs that can be associated with an app, stack, or construct. @@ -1440,6 +1486,10 @@ class MyPlugin implements IPolicyValidationPluginBeta1 { } ``` +In addition to the name, plugins may optionally report their version (`version` +property ) and a list of IDs of the rules they are going to evaluate (`ruleIds` +property). + Note that plugins are not allowed to modify anything in the cloud assembly. Any attempt to do so will result in synthesis failure. @@ -1452,4 +1502,40 @@ add it to the `postinstall` [script](https://docs.npmjs.com/cli/v9/using-npm/scripts) in the `package.json` file. +## Annotations + +Construct authors can add annotations to constructs to report at three different +levels: `ERROR`, `WARN`, `INFO`. + +Typically warnings are added for things that are important for the user to be +aware of, but will not cause deployment errors in all cases. Some common +scenarios are (non-exhaustive list): + +- Warn when the user needs to take a manual action, e.g. IAM policy should be + added to an referenced resource. +- Warn if the user configuration might not follow best practices (but is still + valid) +- Warn if the user is using a deprecated API + +### Acknowledging Warnings + +If you would like to run with `--strict` mode enabled (warnings will throw +errors) it is possible to `acknowledge` warnings to make the warning go away. + +For example, if > 10 IAM managed policies are added to an IAM Group, a warning +will be created: + +```text +IAM:Group:MaxPoliciesExceeded: You added 11 to IAM Group my-group. The maximum number of managed policies attached to an IAM group is 10. +``` + +If you have requested a [quota increase](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entities) +you may have the ability to add > 10 managed policies which means that this +warning does not apply to you. You can acknowledge this by `acknowledging` the +warning by the `id`. + +```ts +Annotations.of(this).acknowledgeWarning('IAM:Group:MaxPoliciesExceeded', 'Account has quota increased to 20'); +``` + diff --git a/packages/aws-cdk-lib/amzn-sdc/.jsiirc.json b/packages/aws-cdk-lib/amzn-sdc/.jsiirc.json new file mode 100644 index 0000000000000..5cfe20f8f3d23 --- /dev/null +++ b/packages/aws-cdk-lib/amzn-sdc/.jsiirc.json @@ -0,0 +1,13 @@ +{ + "targets": { + "java": { + "package": "amzn.sdc" + }, + "dotnet": { + "package": "Amazon.CDK.AMZN.SDC" + }, + "python": { + "module": "aws_cdk.amzn_sdc" + } + } +} diff --git a/packages/aws-cdk-lib/amzn-sdc/README.md b/packages/aws-cdk-lib/amzn-sdc/README.md new file mode 100644 index 0000000000000..e3bbbe4e450b3 --- /dev/null +++ b/packages/aws-cdk-lib/amzn-sdc/README.md @@ -0,0 +1,39 @@ +# AMZN::SDC Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as amzn_sdc from 'aws-cdk-lib/amzn-sdc'; +``` + + + +There are no official hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. Here are some suggestions on how to proceed: + +- Search [Construct Hub for SDC construct libraries](https://constructs.dev/search?q=sdc) +- Use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, in the same way you would use [the CloudFormation AMZN::SDC resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AMZN_SDC.html) directly. + + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AMZN::SDC](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AMZN_SDC.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and submit an RFC if you are interested in contributing to this construct library.) + + diff --git a/packages/aws-cdk-lib/amzn-sdc/index.ts b/packages/aws-cdk-lib/amzn-sdc/index.ts new file mode 100644 index 0000000000000..f41a696fd204d --- /dev/null +++ b/packages/aws-cdk-lib/amzn-sdc/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/packages/aws-cdk-lib/amzn-sdc/lib/index.ts b/packages/aws-cdk-lib/amzn-sdc/lib/index.ts new file mode 100644 index 0000000000000..35a2984cc24f3 --- /dev/null +++ b/packages/aws-cdk-lib/amzn-sdc/lib/index.ts @@ -0,0 +1,2 @@ +// AMZN::SDC Cloudformation Resources +export * from './sdc.generated'; diff --git a/packages/aws-cdk-lib/aws-codetest/.jsiirc.json b/packages/aws-cdk-lib/aws-codetest/.jsiirc.json new file mode 100644 index 0000000000000..c2f229e5beedf --- /dev/null +++ b/packages/aws-cdk-lib/aws-codetest/.jsiirc.json @@ -0,0 +1,13 @@ +{ + "targets": { + "java": { + "package": "software.amazon.awscdk.services.codetest" + }, + "dotnet": { + "package": "Amazon.CDK.AWS.CodeTest" + }, + "python": { + "module": "aws_cdk.aws_codetest" + } + } +} diff --git a/packages/aws-cdk-lib/aws-codetest/README.md b/packages/aws-cdk-lib/aws-codetest/README.md new file mode 100644 index 0000000000000..57a3722006d41 --- /dev/null +++ b/packages/aws-cdk-lib/aws-codetest/README.md @@ -0,0 +1,39 @@ +# AWS::CodeTest Construct Library + + +--- + +![cfn-resources: Stable](https://img.shields.io/badge/cfn--resources-stable-success.svg?style=for-the-badge) + +> All classes with the `Cfn` prefix in this module ([CFN Resources]) are always stable and safe to use. +> +> [CFN Resources]: https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib + +--- + + + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. + +```ts nofixture +import * as codetest from 'aws-cdk-lib/aws-codetest'; +``` + + + +There are no official hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. Here are some suggestions on how to proceed: + +- Search [Construct Hub for CodeTest construct libraries](https://constructs.dev/search?q=codetest) +- Use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, in the same way you would use [the CloudFormation AWS::CodeTest resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CodeTest.html) directly. + + + + +There are no hand-written ([L2](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_lib)) constructs for this service yet. +However, you can still use the automatically generated [L1](https://docs.aws.amazon.com/cdk/latest/guide/constructs.html#constructs_l1_using) constructs, and use this service exactly as you would using CloudFormation directly. + +For more information on the resources and properties available for this service, see the [CloudFormation documentation for AWS::CodeTest](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CodeTest.html). + +(Read the [CDK Contributing Guide](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and submit an RFC if you are interested in contributing to this construct library.) + + diff --git a/packages/aws-cdk-lib/aws-codetest/index.ts b/packages/aws-cdk-lib/aws-codetest/index.ts new file mode 100644 index 0000000000000..f41a696fd204d --- /dev/null +++ b/packages/aws-cdk-lib/aws-codetest/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/packages/aws-cdk-lib/aws-codetest/lib/index.ts b/packages/aws-cdk-lib/aws-codetest/lib/index.ts new file mode 100644 index 0000000000000..f2606fb9ca317 --- /dev/null +++ b/packages/aws-cdk-lib/aws-codetest/lib/index.ts @@ -0,0 +1,2 @@ +// AWS::CodeTest Cloudformation Resources +export * from './codetest.generated'; diff --git a/packages/aws-cdk-lib/aws-rds/README.md b/packages/aws-cdk-lib/aws-rds/README.md index 6b56958ebae40..24046fb698435 100644 --- a/packages/aws-cdk-lib/aws-rds/README.md +++ b/packages/aws-cdk-lib/aws-rds/README.md @@ -788,6 +788,27 @@ proxy.grantConnect(role, 'admin'); // Grant the role connection access to the DB **Note**: In addition to the setup above, a database user will need to be created to support IAM auth. See for setup instructions. +To specify the details of authentication used by a proxy to log in as a specific database +user use the `clientPasswordAuthType` property: + +```ts +declare const vpc: ec2.Vpc; +const cluster = new rds.DatabaseCluster(this, 'Database', { + engine: rds.DatabaseClusterEngine.auroraMysql({ + version: rds.AuroraMysqlEngineVersion.VER_3_03_0, + }), + writer: rds.ClusterInstance.provisioned('writer'), + vpc, +}); + +const proxy = new rds.DatabaseProxy(this, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromCluster(cluster), + secrets: [cluster.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.MYSQL_NATIVE_PASSWORD, +}); +``` + ### Cluster The following example shows granting connection access for an IAM role to an Aurora Cluster. @@ -1042,6 +1063,8 @@ const cluster = new rds.ServerlessCluster(this, 'AnotherCluster', { autoPause: Duration.minutes(10), // default is to pause after 5 minutes of idle time minCapacity: rds.AuroraCapacityUnit.ACU_8, // default is 2 Aurora capacity units (ACUs) maxCapacity: rds.AuroraCapacityUnit.ACU_32, // default is 16 Aurora capacity units (ACUs) + timeout: Duration.seconds(100), // default is 5 minutes + timeoutAction: rds.TimeoutAction.FORCE_APPLY_CAPACITY_CHANGE // default is ROLLBACK_CAPACITY_CHANGE } }); ``` diff --git a/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts b/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts index 52773f1f0bbea..8fabbdc351658 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts @@ -1973,6 +1973,8 @@ export class SqlServerEngineVersion { public static readonly VER_15_00_4322_2_V1 = SqlServerEngineVersion.of('15.00.4322.2.v1', '15.00'); /** Version "15.00.4335.1.v1". */ public static readonly VER_15_00_4335_1_V1 = SqlServerEngineVersion.of('15.00.4335.1.v1', '15.00'); + /** Version "15.00.4345.5.v1". */ + public static readonly VER_15_00_4345_5_V1 = SqlServerEngineVersion.of('15.00.4345.5.v1', '15.00'); /** Version "16.00.4085.2.v1". */ public static readonly VER_16_00_4085_2_V1 = SqlServerEngineVersion.of('16.00.4085.2.v1', '16.00'); /** Version "16.00.4095.4.v1". */ diff --git a/packages/aws-cdk-lib/aws-rds/lib/proxy.ts b/packages/aws-cdk-lib/aws-rds/lib/proxy.ts index c1cfae1925ca0..1e66307be4406 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/proxy.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/proxy.ts @@ -10,6 +10,28 @@ import * as secretsmanager from '../../aws-secretsmanager'; import * as cdk from '../../core'; import * as cxapi from '../../cx-api'; +/** + * Client password authentication type used by a proxy to log in as a specific database user. + */ +export enum ClientPasswordAuthType { + /** + * MySQL Native Password client authentication type. + */ + MYSQL_NATIVE_PASSWORD = 'MYSQL_NATIVE_PASSWORD', + /** + * SCRAM SHA 256 client authentication type. + */ + POSTGRES_SCRAM_SHA_256 = 'POSTGRES_SCRAM_SHA_256', + /** + * PostgreSQL MD5 client authentication type. + */ + POSTGRES_MD5 = 'POSTGRES_MD5', + /** + * SQL Server Authentication client authentication type. + */ + SQL_SERVER_AUTHENTICATION = 'SQL_SERVER_AUTHENTICATION', +} + /** * SessionPinningFilter * @@ -259,6 +281,13 @@ export interface DatabaseProxyOptions { * The VPC to associate with the new proxy. */ readonly vpc: ec2.IVpc; + + /** + * Specifies the details of authentication used by a proxy to log in as a specific database user. + * + * @default - CloudFormation defaults will apply given the specified database engine. + */ + readonly clientPasswordAuthType?: ClientPasswordAuthType; } /** @@ -445,10 +474,13 @@ export class DatabaseProxy extends DatabaseProxyBase } this.secrets = props.secrets; + this.validateClientPasswordAuthType(bindResult.engineFamily, props.clientPasswordAuthType); + this.resource = new CfnDBProxy(this, 'Resource', { auth: props.secrets.map(_ => { return { authScheme: 'SECRETS', + clientPasswordAuthType: props.clientPasswordAuthType, iamAuth: props.iamAuth ? 'REQUIRED' : 'DISABLED', secretArn: _.secretArn, }; @@ -529,6 +561,22 @@ export class DatabaseProxy extends DatabaseProxyBase } return super.grantConnect(grantee, dbUser); } + + private validateClientPasswordAuthType(engineFamily: string, clientPasswordAuthType?: ClientPasswordAuthType) { + if (!clientPasswordAuthType || cdk.Token.isUnresolved(clientPasswordAuthType)) return; + if (clientPasswordAuthType === ClientPasswordAuthType.MYSQL_NATIVE_PASSWORD && engineFamily !== 'MYSQL') { + throw new Error(`${ClientPasswordAuthType.MYSQL_NATIVE_PASSWORD} client password authentication type requires MYSQL engineFamily, got ${engineFamily}`); + } + if (clientPasswordAuthType === ClientPasswordAuthType.POSTGRES_SCRAM_SHA_256 && engineFamily !== 'POSTGRESQL') { + throw new Error(`${ClientPasswordAuthType.POSTGRES_SCRAM_SHA_256} client password authentication type requires POSTGRESQL engineFamily, got ${engineFamily}`); + } + if (clientPasswordAuthType === ClientPasswordAuthType.POSTGRES_MD5 && engineFamily !== 'POSTGRESQL') { + throw new Error(`${ClientPasswordAuthType.POSTGRES_MD5} client password authentication type requires POSTGRESQL engineFamily, got ${engineFamily}`); + } + if (clientPasswordAuthType === ClientPasswordAuthType.SQL_SERVER_AUTHENTICATION && engineFamily !== 'SQLSERVER') { + throw new Error(`${ClientPasswordAuthType.SQL_SERVER_AUTHENTICATION} client password authentication type requires SQLSERVER engineFamily, got ${engineFamily}`); + } + } } /** diff --git a/packages/aws-cdk-lib/aws-rds/lib/serverless-cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/serverless-cluster.ts index ca2662b84e3ed..d43d78a6ea415 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/serverless-cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/serverless-cluster.ts @@ -239,6 +239,26 @@ export enum AuroraCapacityUnit { ACU_384 = 384 } +/** + * TimeoutAction defines the action to take when a timeout occurs if a scaling point is not found. + * + * @see https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v1.how-it-works.html#aurora-serverless.how-it-works.timeout-action + */ +export enum TimeoutAction { + /** + * FORCE_APPLY_CAPACITY_CHANGE sets the capacity to the specified value as soon as possible. + * Transactions may be interrupted, and connections to temporary tables and locks may be dropped. + * Only select this option if your application can recover from dropped connections or incomplete transactions. + */ + FORCE_APPLY_CAPACITY_CHANGE = 'ForceApplyCapacityChange', + + /** + * ROLLBACK_CAPACITY_CHANGE ignores the capacity change if a scaling point is not found. + * This is the default behavior. + */ + ROLLBACK_CAPACITY_CHANGE = 'RollbackCapacityChange', +} + /** * Options for configuring scaling on an Aurora Serverless cluster * @@ -272,6 +292,23 @@ export interface ServerlessScalingOptions { * @default - automatic pause enabled after 5 minutes */ readonly autoPause?: Duration; + + /** + * The amount of time that Aurora Serverless v1 tries to find a scaling point to perform + * seamless scaling before enforcing the timeout action. + * + * @default - 5 minutes + */ + readonly timeout? : Duration; + + /** + * The action to take when the timeout is reached. + * Selecting ForceApplyCapacityChange will force the capacity to the specified value as soon as possible, even without a scaling point. + * Selecting RollbackCapacityChange will ignore the capacity change if a scaling point is not found. This is the default behavior. + * + * @default - TimeoutAction.ROLLBACK_CAPACITY_CHANGE + */ + readonly timeoutAction?: TimeoutAction; } /** @@ -444,6 +481,7 @@ abstract class ServerlessClusterNew extends ServerlessClusterBase { private renderScalingConfiguration(options: ServerlessScalingOptions): CfnDBCluster.ScalingConfigurationProperty { const minCapacity = options.minCapacity; const maxCapacity = options.maxCapacity; + const timeout = options.timeout?.toSeconds(); if (minCapacity && maxCapacity && minCapacity > maxCapacity) { throw new Error('maximum capacity must be greater than or equal to minimum capacity.'); @@ -454,11 +492,17 @@ abstract class ServerlessClusterNew extends ServerlessClusterBase { throw new Error('auto pause time must be between 5 minutes and 1 day.'); } + if (timeout && (timeout < 60 || timeout > 600)) { + throw new Error(`timeout must be between 60 and 600 seconds, but got ${timeout} seconds.`); + } + return { autoPause: (secondsToAutoPause === 0) ? false : true, minCapacity: options.minCapacity, maxCapacity: options.maxCapacity, secondsUntilAutoPause: (secondsToAutoPause === 0) ? undefined : secondsToAutoPause, + secondsBeforeTimeout: timeout, + timeoutAction: options.timeoutAction, }; } } diff --git a/packages/aws-cdk-lib/aws-rds/test/proxy.test.ts b/packages/aws-cdk-lib/aws-rds/test/proxy.test.ts index 492e90c295d94..6546164210972 100644 --- a/packages/aws-cdk-lib/aws-rds/test/proxy.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/proxy.test.ts @@ -450,6 +450,141 @@ describe('proxy', () => { ], }); }); + + describe('clientPasswordAuthType', () => { + test('create a DB proxy with specified client password authentication type', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_5_7, + }), + vpc, + }); + + // WHEN + new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromInstance(instance), + secrets: [instance.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.MYSQL_NATIVE_PASSWORD, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBProxy', { + Auth: [ + { + AuthScheme: 'SECRETS', + IAMAuth: 'DISABLED', + ClientPasswordAuthType: 'MYSQL_NATIVE_PASSWORD', + SecretArn: { + Ref: 'InstanceSecretAttachment83BEE581', + }, + }, + ], + DBProxyName: 'Proxy', + EngineFamily: 'MYSQL', + RequireTLS: true, + RoleArn: { + 'Fn::GetAtt': [ + 'ProxyIAMRole2FE8AB0F', + 'Arn', + ], + }, + VpcSubnetIds: [ + { + Ref: 'VPCPrivateSubnet1Subnet8BCA10E0', + }, + { + Ref: 'VPCPrivateSubnet2SubnetCFCDAA7A', + }, + ], + }); + }); + + test('MYSQL_NATIVE_PASSWORD clientPasswordAuthType requires MYSQL engine family', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.postgres({ + version: rds.PostgresEngineVersion.VER_11, + }), + vpc, + }); + + // WHEN + // THEN + expect(() => { + new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromInstance(instance), + secrets: [instance.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.MYSQL_NATIVE_PASSWORD, + }); + }).toThrow(/MYSQL_NATIVE_PASSWORD client password authentication type requires MYSQL engineFamily, got POSTGRESQL/); + }); + + test('POSTGRES_SCRAM_SHA_256 clientPasswordAuthType requires POSTGRESQL engine family', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_5_7, + }), + vpc, + }); + + // WHEN + // THEN + expect(() => { + new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromInstance(instance), + secrets: [instance.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.POSTGRES_SCRAM_SHA_256, + }); + }).toThrow(/POSTGRES_SCRAM_SHA_256 client password authentication type requires POSTGRESQL engineFamily, got MYSQL/); + }); + + test('POSTGRES_MD5 clientPasswordAuthType requires POSTGRESQL engine family', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_5_7, + }), + vpc, + }); + + // WHEN + // THEN + expect(() => { + new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromInstance(instance), + secrets: [instance.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.POSTGRES_MD5, + }); + }).toThrow(/POSTGRES_MD5 client password authentication type requires POSTGRESQL engineFamily, got MYSQL/); + }); + + test('SQL_SERVER_AUTHENTICATION clientPasswordAuthType requires SQLSERVER engine family', () => { + // GIVEN + const instance = new rds.DatabaseInstance(stack, 'Instance', { + engine: rds.DatabaseInstanceEngine.mysql({ + version: rds.MysqlEngineVersion.VER_5_7, + }), + vpc, + }); + + // WHEN + // THEN + expect(() => { + new rds.DatabaseProxy(stack, 'Proxy', { + proxyTarget: rds.ProxyTarget.fromInstance(instance), + secrets: [instance.secret!], + vpc, + clientPasswordAuthType: rds.ClientPasswordAuthType.SQL_SERVER_AUTHENTICATION, + }); + }).toThrow(/SQL_SERVER_AUTHENTICATION client password authentication type requires SQLSERVER engineFamily, got MYSQL/); + }); + }); }); describe('feature flag @aws-cdk/aws-rds:databaseProxyUniqueResourceName', () => { diff --git a/packages/aws-cdk-lib/aws-rds/test/serverless-cluster.test.ts b/packages/aws-cdk-lib/aws-rds/test/serverless-cluster.test.ts index cae4e4a84b886..08c57abf25ffc 100644 --- a/packages/aws-cdk-lib/aws-rds/test/serverless-cluster.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/serverless-cluster.test.ts @@ -4,7 +4,7 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import * as cdk from '../../core'; import * as cxapi from '../../cx-api'; -import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret, SubnetGroup } from '../lib'; +import { AuroraPostgresEngineVersion, ServerlessCluster, DatabaseClusterEngine, ParameterGroup, AuroraCapacityUnit, DatabaseSecret, SubnetGroup, TimeoutAction } from '../lib'; describe('serverless cluster', () => { test('can create a Serverless Cluster with Aurora Postgres database engine', () => { @@ -935,6 +935,56 @@ describe('serverless cluster', () => { }); }); + test('check properties propagation of ServerlessScalingOptions', () => { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpc: new ec2.Vpc(stack, 'Vpc'), + scaling: { + autoPause: cdk.Duration.minutes(10), + minCapacity: AuroraCapacityUnit.ACU_8, + maxCapacity: AuroraCapacityUnit.ACU_32, + timeout: cdk.Duration.minutes(10), + timeoutAction: TimeoutAction.FORCE_APPLY_CAPACITY_CHANGE, + }, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::RDS::DBCluster', { + ScalingConfiguration: { + AutoPause: true, + MaxCapacity: 32, + MinCapacity: 8, + SecondsUntilAutoPause: 600, + SecondsBeforeTimeout: 600, + TimeoutAction: 'ForceApplyCapacityChange', + }, + }); + }); + + test.each([ + cdk.Duration.seconds(59), + cdk.Duration.seconds(601), + ])('invalid ServerlessScalingOptions throws', (duration) => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc'); + + // THEN + expect(() => new ServerlessCluster(stack, 'Database1', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + vpc, + scaling: { + autoPause: cdk.Duration.minutes(10), + minCapacity: AuroraCapacityUnit.ACU_8, + maxCapacity: AuroraCapacityUnit.ACU_32, + timeout: duration, + }, + })).toThrow(/timeout must be between 60 and 600 seconds/); + }); }); function testStack(app?: cdk.App, id?: string): cdk.Stack { diff --git a/packages/aws-cdk-lib/aws-signer/lib/signing-profile.ts b/packages/aws-cdk-lib/aws-signer/lib/signing-profile.ts index 8637f242f5a36..d562dfa566393 100644 --- a/packages/aws-cdk-lib/aws-signer/lib/signing-profile.ts +++ b/packages/aws-cdk-lib/aws-signer/lib/signing-profile.ts @@ -10,32 +10,47 @@ export class Platform { /** * Specification of signature format and signing algorithms for AWS IoT Device. */ - public static readonly AWS_IOT_DEVICE_MANAGEMENT_SHA256_ECDSA = new Platform('AWSIoTDeviceManagement-SHA256-ECDSA'); + public static readonly AWS_IOT_DEVICE_MANAGEMENT_SHA256_ECDSA = Platform.of('AWSIoTDeviceManagement-SHA256-ECDSA'); /** * Specification of signature format and signing algorithms for AWS Lambda. */ - public static readonly AWS_LAMBDA_SHA384_ECDSA = new Platform('AWSLambda-SHA384-ECDSA'); + public static readonly AWS_LAMBDA_SHA384_ECDSA = Platform.of('AWSLambda-SHA384-ECDSA'); /** * Specification of signature format and signing algorithms with * SHA1 hash and RSA encryption for Amazon FreeRTOS. */ - public static readonly AMAZON_FREE_RTOS_TI_CC3220SF = new Platform('AmazonFreeRTOS-TI-CC3220SF'); + public static readonly AMAZON_FREE_RTOS_TI_CC3220SF = Platform.of('AmazonFreeRTOS-TI-CC3220SF'); /** * Specification of signature format and signing algorithms with * SHA256 hash and ECDSA encryption for Amazon FreeRTOS. */ - public static readonly AMAZON_FREE_RTOS_DEFAULT = new Platform('AmazonFreeRTOS-Default'); + public static readonly AMAZON_FREE_RTOS_DEFAULT = Platform.of('AmazonFreeRTOS-Default'); /** - * The id of signing platform. + * Specification of signature format and signing algorithms with + * SHA256 hash and ECDSA encryption for container registries with notation. + */ + public static readonly NOTATION_OCI_SHA384_ECDSA = Platform.of('Notation-OCI-SHA384-ECDSA'); + + /** + * Custom signing profile platform. + * * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-signer-signingprofile.html#cfn-signer-signingprofile-platformid + * + * @param platformId - The id of signing platform. */ - public readonly platformId: string; + public static of(platformId: string): Platform { + return new Platform(platformId); + } - private constructor(platformId: string) { + /** + * + * @param platformId - The id of signing platform. + */ + private constructor(public readonly platformId: string) { this.platformId = platformId; } } diff --git a/packages/aws-cdk-lib/aws-signer/test/signing-profile.test.ts b/packages/aws-cdk-lib/aws-signer/test/signing-profile.test.ts index 49075529598fb..e415832424f31 100644 --- a/packages/aws-cdk-lib/aws-signer/test/signing-profile.test.ts +++ b/packages/aws-cdk-lib/aws-signer/test/signing-profile.test.ts @@ -4,15 +4,16 @@ import * as signer from '../lib'; let app: cdk.App; let stack: cdk.Stack; -beforeEach( () => { - app = new cdk.App( {} ); - stack = new cdk.Stack( app ); -} ); + +beforeEach(() => { + app = new cdk.App({}); + stack = new cdk.Stack(app); +}); describe('signing profile', () => { - test( 'default', () => { + test('default', () => { const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; - new signer.SigningProfile( stack, 'SigningProfile', { platform } ); + new signer.SigningProfile(stack, 'SigningProfile', { platform }); Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { PlatformId: platform.platformId, @@ -23,12 +24,12 @@ describe('signing profile', () => { }); }); - test( 'default with signature validity period', () => { + test('default with signature validity period', () => { const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; - new signer.SigningProfile( stack, 'SigningProfile', { + new signer.SigningProfile(stack, 'SigningProfile', { platform, - signatureValidity: cdk.Duration.days( 7 ), - } ); + signatureValidity: cdk.Duration.days(7), + }); Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { PlatformId: platform.platformId, @@ -39,9 +40,9 @@ describe('signing profile', () => { }); }); - test( 'default with some tags', () => { + test('default with some tags', () => { const platform = signer.Platform.AWS_LAMBDA_SHA384_ECDSA; - const signing = new signer.SigningProfile( stack, 'SigningProfile', { platform } ); + const signing = new signer.SigningProfile(stack, 'SigningProfile', { platform }); cdk.Tags.of(signing).add('tag1', 'value1'); cdk.Tags.of(signing).add('tag2', 'value2'); @@ -70,6 +71,19 @@ describe('signing profile', () => { }); }); + test('default container registries with notation platform', () => { + const platform = signer.Platform.NOTATION_OCI_SHA384_ECDSA; + new signer.SigningProfile(stack, 'SigningProfile', { platform }); + + Template.fromStack(stack).hasResourceProperties('AWS::Signer::SigningProfile', { + PlatformId: platform.platformId, + SignatureValidityPeriod: { + Type: 'MONTHS', + Value: 135, + }, + }); + }); + describe('import', () => { test('from signingProfileProfileName and signingProfileProfileVersion', () => { const signingProfileName = 'test'; @@ -111,5 +125,5 @@ describe('signing profile', () => { }); Template.fromStack(stack).templateMatches({}); }); - } ); + }); }); diff --git a/packages/aws-cdk-lib/aws-stepfunctions/README.md b/packages/aws-cdk-lib/aws-stepfunctions/README.md index aef1e2ffaa631..6ddae341b2506 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions/README.md +++ b/packages/aws-cdk-lib/aws-stepfunctions/README.md @@ -602,6 +602,13 @@ const custom = new sfn.CustomState(this, 'my custom task', { const errorHandler = new sfn.Pass(this, 'handle failure'); custom.addCatch(errorHandler); +// retry the task if something goes wrong +custom.addRetry({ + errors: [sfn.Errors.ALL], + interval: Duration.seconds(10), + maxAttempts: 5, +}); + const chain = sfn.Chain.start(custom) .next(finalStatus); diff --git a/packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts b/packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts index db66a5a8de17f..fd247118c6347 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions/lib/states/custom-state.ts @@ -1,7 +1,7 @@ import { Construct } from 'constructs'; import { State } from './state'; import { Chain } from '..'; -import { CatchProps, IChainable, INextable } from '../types'; +import { CatchProps, IChainable, INextable, RetryProps } from '../types'; /** * Properties for defining a custom state definition @@ -34,6 +34,17 @@ export class CustomState extends State implements IChainable, INextable { this.stateJson = props.stateJson; } + /** + * Add retry configuration for this state + * + * This controls if and how the execution will be retried if a particular + * error occurs. + */ + public addRetry(props: RetryProps = {}): CustomState { + super._addRetry(props); + return this; + } + /** * Add a recovery handler for this state * diff --git a/packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts b/packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts index 766b8ac659abe..7935f911e9977 100644 --- a/packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts +++ b/packages/aws-cdk-lib/aws-stepfunctions/test/custom-state.test.ts @@ -120,4 +120,47 @@ describe('Custom State', () => { }, ); }); + + test('can add a retry state', () => { + // GIVEN + const custom = new sfn.CustomState(stack, 'Custom', { + stateJson, + }); + const chain = sfn.Chain.start(custom); + + // WHEN + custom.addRetry({ + errors: [sfn.Errors.ALL], + interval: cdk.Duration.seconds(10), + maxAttempts: 5, + }); + + // THEN + expect(render(stack, chain)).toStrictEqual( + { + StartAt: 'Custom', + States: { + Custom: { + Type: 'Task', + Resource: 'arn:aws:states:::dynamodb:putItem', + Parameters: { + TableName: 'MyTable', + Item: { + id: { + S: 'MyEntry', + }, + }, + }, + ResultPath: null, + Retry: [{ + ErrorEquals: ['States.ALL'], + IntervalSeconds: 10, + MaxAttempts: 5, + }], + End: true, + }, + }, + }, + ); + }); }); \ No newline at end of file diff --git a/packages/aws-cdk-lib/core/README.md b/packages/aws-cdk-lib/core/README.md index 4c7e9ecd309d0..446cb1a118976 100644 --- a/packages/aws-cdk-lib/core/README.md +++ b/packages/aws-cdk-lib/core/README.md @@ -17,9 +17,37 @@ dependencies. According to the kind of project you are developing: -- For projects that are CDK libraries, declare them both under the `devDependencies` - **and** `peerDependencies` sections. -- For CDK apps, declare them under the `dependencies` section only. +For projects that are CDK libraries in NPM, declare them both under the `devDependencies` **and** `peerDependencies` sections. +To make sure your library is compatible with the widest range of CDK versions: pick the minimum `aws-cdk-lib` version +that your library requires; declare a range dependency with a caret on that version in peerDependencies, and declare a +point version dependency on that version in devDependencies. + +For example, let's say the minimum version your library needs is `2.38.0`. Your `package.json` should look like this: + +```javascript +{ + "peerDependencies": { + "aws-cdk-lib": "^2.38.0", + "constructs": "^10.0.0" + }, + "devDependencies": { + /* Install the oldest version for testing so we don't accidentally use features from a newer version than we declare */ + "aws-cdk-lib": "2.38.0" + } +} +``` + +For CDK apps, declare them under the `dependencies` section. Use a caret so you always get the latest version: + +```json +{ + "dependencies": { + "aws-cdk-lib": "^2.38.0", + "constructs": "^10.0.0" + } +} +``` + ### Use in your code @@ -27,20 +55,27 @@ According to the kind of project you are developing: You can use a classic import to get access to each service namespaces: -```ts -import { aws_s3 as s3 } from 'aws-cdk-lib'; +```ts nofixture +import { Stack, App, aws_s3 as s3 } from 'aws-cdk-lib'; -new s3.Bucket(this, 'TestBucket'); +const app = new App(); +const stack = new Stack(app, 'TestStack'); + +new s3.Bucket(stack, 'TestBucket'); ``` #### Barrel import Alternatively, you can use "barrel" imports: -```ts +```ts nofixture +import { App, Stack } from 'aws-cdk-lib'; import { Bucket } from 'aws-cdk-lib/aws-s3'; -new Bucket(this, 'TestBucket'); +const app = new App(); +const stack = new Stack(app, 'TestStack'); + +new Bucket(stack, 'TestBucket'); ``` @@ -361,7 +396,7 @@ CloudFormation to re-read the secret. ## ARN manipulation Sometimes you will need to put together or pick apart Amazon Resource Names -(ARNs). The functions `stack.formatArn()` and `stack.parseArn()` exist for +(ARNs). The functions `stack.formatArn()` and `stack.splitArn()` exist for this purpose. `formatArn()` can be used to build an ARN from components. It will automatically @@ -374,12 +409,12 @@ declare const stack: Stack; stack.formatArn({ service: 'lambda', resource: 'function', - sep: ':', + arnFormat: ArnFormat.COLON_RESOURCE_NAME, resourceName: 'MyFunction' }); ``` -`parseArn()` can be used to get a single component from an ARN. `parseArn()` +`splitArn()` can be used to get a single component from an ARN. `splitArn()` will correctly deal with both literal ARNs and deploy-time values (tokens), but in case of a deploy-time value be aware that the result will be another deploy-time value which cannot be inspected in the CDK application. @@ -388,14 +423,13 @@ deploy-time value which cannot be inspected in the CDK application. declare const stack: Stack; // Extracts the function name out of an AWS Lambda Function ARN -const arnComponents = stack.parseArn(arn, ':'); +const arnComponents = stack.splitArn(arn, ArnFormat.COLON_RESOURCE_NAME); const functionName = arnComponents.resourceName; ``` -Note that depending on the service, the resource separator can be either -`:` or `/`, and the resource name can be either the 6th or 7th -component in the ARN. When using these functions, you will need to know -the format of the ARN you are dealing with. +Note that the format of the resource separator depends on the service and +may be any of the values supported by `ArnFormat`. When dealing with these +functions, it is important to know the format of the ARN you are dealing with. For an exhaustive list of ARN formats used in AWS, see [AWS ARNs and Namespaces](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) @@ -576,7 +610,7 @@ response to the CloudFormation service and handle various error cases. Set `serviceToken` to `lambda.functionArn` to use this provider: ```ts -const fn = new lambda.Function(this, 'MyProvider', functionProps); +const fn = new lambda.SingletonFunction(this, 'MyProvider', functionProps); new CustomResource(this, 'MyResource', { serviceToken: fn.functionArn, @@ -678,8 +712,8 @@ exports.handler = async (e) => { `sum.ts`: ```ts nofixture +import { Construct } from 'constructs'; import { - Construct, CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, @@ -781,7 +815,7 @@ new CustomResource(this, 'MyResource', { }); ``` -See the [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html) for more details. +See the [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-cdk-lib.custom_resources-readme.html) for more details. ## AWS CloudFormation features @@ -905,7 +939,7 @@ a property of the creationPolicy on the resource options. Setting it to true wil resources that depend on the fleet resource. ```ts -const fleet = new CfnFleet(stack, 'Fleet', { +const fleet = new appstream.CfnFleet(this, 'Fleet', { instanceType: 'stream.standard.small', name: 'Fleet', computeCapacity: { @@ -928,10 +962,14 @@ The format of the timeout is `PT#H#M#S`. In the example below AWS Cloudformation `CREATE_COMPLETE`. ```ts -resource.cfnOptions.resourceSignal = { - count: 3, - timeout: 'PR15M', -} +declare const resource: CfnResource; + +resource.cfnOptions.creationPolicy = { + resourceSignal: { + count: 3, + timeout: 'PR15M', + } +}; ``` [creation-policy]: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html @@ -1330,8 +1368,6 @@ to all roles within a specific construct scope. The most common use case would be to apply a permissions boundary at the `Stage` level. ```ts -declare const app: App; - const prodStage = new Stage(app, 'ProdStage', { permissionsBoundary: PermissionsBoundary.fromName('cdk-${Qualifier}-PermissionsBoundary'), }); @@ -1363,11 +1399,11 @@ will be printed to the console or to a file (see below). To use one or more validation plugins in your application, use the `policyValidationBeta1` property of `Stage`: -```ts +```ts fixture=validation-plugin // globally for the entire app (an app is a stage) const app = new App({ policyValidationBeta1: [ - // These hypothetical classes implement IValidationPlugin: + // These hypothetical classes implement IPolicyValidationPluginBeta1: new ThirdPartyPluginX(), new ThirdPartyPluginY(), ], @@ -1375,7 +1411,9 @@ const app = new App({ // only apply to a particular stage const prodStage = new Stage(app, 'ProdStage', { - policyValidationBeta1: [...], + policyValidationBeta1: [ + new ThirdPartyPluginX(), + ], }); ``` @@ -1412,35 +1450,39 @@ the standard output. ### For plugin authors The communication protocol between the CDK core module and your policy tool is -defined by the `IValidationPluginBeta1` interface. To create a new plugin you must +defined by the `IPolicyValidationPluginBeta1` interface. To create a new plugin you must write a class that implements this interface. There are two things you need to implement: the plugin name (by overriding the `name` property), and the `validate()` method. -The framework will call `validate()`, passing an `IValidationContextBeta1` object. +The framework will call `validate()`, passing an `IPolicyValidationContextBeta1` object. The location of the templates to be validated is given by `templatePaths`. The -plugin should return an instance of `ValidationPluginReportBeta1`. This object +plugin should return an instance of `PolicyValidationPluginReportBeta1`. This object represents the report that the user wil receive at the end of the synthesis. -```ts -validate(context: ValidationContextBeta1): ValidationReportBeta1 { - // First read the templates using context.templatePaths... - - // ...then perform the validation, and then compose and return the report. - // Using hard-coded values here for better clarity: - return { - success: false, - violations: [{ - ruleName: 'CKV_AWS_117', - recommendation: 'Ensure that AWS Lambda function is configured inside a VPC', - fix: 'https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1', - violatingResources: [{ - resourceName: 'MyFunction3BAA72D1', - templatePath: '/home/johndoe/myapp/cdk.out/MyService.template.json', - locations: 'Properties/VpcConfig', +```ts fixture=validation-plugin +class MyPlugin implements IPolicyValidationPluginBeta1 { + public readonly name = 'MyPlugin'; + + public validate(context: IPolicyValidationContextBeta1): PolicyValidationPluginReportBeta1 { + // First read the templates using context.templatePaths... + + // ...then perform the validation, and then compose and return the report. + // Using hard-coded values here for better clarity: + return { + success: false, + violations: [{ + ruleName: 'CKV_AWS_117', + description: 'Ensure that AWS Lambda function is configured inside a VPC', + fix: 'https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1', + violatingResources: [{ + resourceLogicalId: 'MyFunction3BAA72D1', + templatePath: '/home/johndoe/myapp/cdk.out/MyService.template.json', + locations: ['Properties/VpcConfig'], + }], }], - }], - }; + }; + } } ``` @@ -1483,7 +1525,7 @@ errors) it is possible to `acknowledge` warnings to make the warning go away. For example, if > 10 IAM managed policies are added to an IAM Group, a warning will be created: -``` +```text IAM:Group:MaxPoliciesExceeded: You added 11 to IAM Group my-group. The maximum number of managed policies attached to an IAM group is 10. ``` diff --git a/packages/aws-cdk-lib/core/lib/asset-staging.ts b/packages/aws-cdk-lib/core/lib/asset-staging.ts index 91ec93914a2f0..8991dfbe18634 100644 --- a/packages/aws-cdk-lib/core/lib/asset-staging.ts +++ b/packages/aws-cdk-lib/core/lib/asset-staging.ts @@ -343,11 +343,16 @@ export class AssetStaging extends Construct { this.stageAsset(bundledAsset.path, stagedPath, 'move'); // If bundling produced a single archive file we "touch" this file in the bundling - // directory after it has been moved to the staging directory. This way if bundling + // directory after it has been moved to the staging directory if the hash is known before bundling. This way if bundling // is skipped because the bundling directory already exists we can still determine // the correct packaging type. + // If the hash is calculated after bundling we remove the temporary directory now. if (bundledAsset.packaging === FileAssetPackaging.FILE) { - fs.closeSync(fs.openSync(bundledAsset.path, 'w')); + if (this.hashType === AssetHashType.OUTPUT || this.hashType === AssetHashType.BUNDLE) { + fs.removeSync(path.dirname(bundledAsset.path)); + } else { + fs.closeSync(fs.openSync(bundledAsset.path, 'w')); + } } return { diff --git a/packages/aws-cdk-lib/core/test/staging.test.ts b/packages/aws-cdk-lib/core/test/staging.test.ts index 6f3d904b4ed6e..dff63c09a76f8 100644 --- a/packages/aws-cdk-lib/core/test/staging.test.ts +++ b/packages/aws-cdk-lib/core/test/staging.test.ts @@ -1419,6 +1419,37 @@ describe('staging', () => { expect(staging.isArchive).toEqual(false); }); + test('bundling that produces a single file with SINGLE_FILE and hash type OUTPUT', () => { + // GIVEN + const app = new App({ context: { [cxapi.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: false } }); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1', 'subdir'); + + // WHEN + const staging = new AssetStaging(stack, 'Asset', { + sourcePath: directory, + assetHashType: AssetHashType.OUTPUT, + bundling: { + image: DockerImage.fromRegistry('alpine'), + command: [DockerStubCommand.SINGLE_FILE], + outputType: BundlingOutput.SINGLE_FILE, + }, + }); + + // THEN + const assembly = app.synth(); + expect(fs.readdirSync(assembly.directory)).toEqual([ + // 'bundling-temp-0e346bd27baa32f4f2d15d1d73c8972db3293080f6c2836328b7bf77747683db', this directory gets removed and does no longer exist + 'asset.95c924c84f5d023be4edee540cb2cb401a49f115d01ed403b288f6cb412771df.txt', + 'cdk.out', + 'manifest.json', + 'stack.template.json', + 'tree.json', + ]); + expect(staging.packaging).toEqual(FileAssetPackaging.FILE); + expect(staging.isArchive).toEqual(false); + }); + }); describe('staging with docker cp', () => { diff --git a/packages/aws-cdk-lib/index.ts b/packages/aws-cdk-lib/index.ts index 89b01494ed956..99a3876bfad74 100644 --- a/packages/aws-cdk-lib/index.ts +++ b/packages/aws-cdk-lib/index.ts @@ -1,4 +1,5 @@ export * as alexa_ask from './alexa-ask'; +export * as amzn_sdc from './amzn-sdc'; export * as assertions from './assertions'; export * as assets from './assets'; export * as aws_accessanalyzer from './aws-accessanalyzer'; @@ -57,6 +58,7 @@ export * as aws_codepipeline_actions from './aws-codepipeline-actions'; export * as aws_codestar from './aws-codestar'; export * as aws_codestarconnections from './aws-codestarconnections'; export * as aws_codestarnotifications from './aws-codestarnotifications'; +export * as aws_codetest from './aws-codetest'; export * as aws_cognito from './aws-cognito'; export * as aws_comprehend from './aws-comprehend'; export * as aws_config from './aws-config'; diff --git a/packages/aws-cdk-lib/package.json b/packages/aws-cdk-lib/package.json index 87c434cf4ccff..c904c9ad791c0 100644 --- a/packages/aws-cdk-lib/package.json +++ b/packages/aws-cdk-lib/package.json @@ -133,7 +133,7 @@ "yaml": "1.10.2" }, "devDependencies": { - "@aws-cdk/aws-service-spec": "^0.0.38", + "@aws-cdk/aws-service-spec": "^0.0.40", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/custom-resource-handlers": "0.0.0", "@aws-cdk/pkglint": "0.0.0", @@ -209,6 +209,7 @@ "./.jsii": "./.jsii", "./.warnings.jsii.js": "./.warnings.jsii.js", "./alexa-ask": "./alexa-ask/index.js", + "./amzn-sdc": "./amzn-sdc/index.js", "./assertions": "./assertions/index.js", "./assertions/lib/helpers-internal": "./assertions/lib/helpers-internal/index.js", "./assets": "./assets/index.js", @@ -268,6 +269,7 @@ "./aws-codestar": "./aws-codestar/index.js", "./aws-codestarconnections": "./aws-codestarconnections/index.js", "./aws-codestarnotifications": "./aws-codestarnotifications/index.js", + "./aws-codetest": "./aws-codetest/index.js", "./aws-cognito": "./aws-cognito/index.js", "./aws-comprehend": "./aws-comprehend/index.js", "./aws-config": "./aws-config/index.js", diff --git a/packages/aws-cdk-lib/pipelines/README.md b/packages/aws-cdk-lib/pipelines/README.md index 4eefcbf3a8991..1e8e0030f9b4c 100644 --- a/packages/aws-cdk-lib/pipelines/README.md +++ b/packages/aws-cdk-lib/pipelines/README.md @@ -16,17 +16,18 @@ everything you need. If you want or need more control, we recommend you drop down to using the `aws-codepipeline` construct library directly. > This module contains two sets of APIs: an **original** and a **modern** version of -CDK Pipelines. The *modern* API has been updated to be easier to work with and -customize, and will be the preferred API going forward. The *original* version -of the API is still available for backwards compatibility, but we recommend migrating -to the new version if possible. +> CDK Pipelines. The *modern* API has been updated to be easier to work with and +> customize, and will be the preferred API going forward. The *original* version +> of the API is still available for backwards compatibility, but we recommend migrating +> to the new version if possible. > > Compared to the original API, the modern API: has more sensible defaults; is > more flexible; supports parallel deployments; supports multiple synth inputs; > allows more control of CodeBuild project generation; supports deployment > engines other than CodePipeline. > -> The README for the original API, as well as a migration guide, can be found in [our GitHub repository](https://github.com/aws/aws-cdk/blob/main/packages/@aws-cdk/pipelines/ORIGINAL_API.md). +> The README for the original API, as well as a migration guide, can be found in +> [our GitHub repository](https://github.com/aws/aws-cdk/blob/main/packages/@aws-cdk/pipelines/ORIGINAL_API.md). ## At a glance @@ -1232,6 +1233,52 @@ and orphan the old bucket. You should manually delete the orphaned bucket after you are sure you have redeployed all CDK applications and there are no more references to the old asset bucket. +## Considerations around Running at Scale + +If you are planning to run pipelines for more than a hundred repos +deploying across multiple regions, then you will want to consider reusing +both artifacts buckets and cross-region replication buckets. + +In a situation like this, you will want to have a separate CDK app / dedicated repo which creates +and managed the buckets which will be shared by the pipelines of all your other apps. +Note that this app must NOT be using the shared buckets because of chicken & egg issues. + +The following code assumes you have created and are managing your buckets in the aforementioned +separate cdk repo and are just importing them for use in one of your (many) pipelines. + +```ts +declare const sharedXRegionUsWest1BucketArn: string; +declare const sharedXRegionUsWest1KeyArn: string; + +declare const sharedXRegionUsWest2BucketArn: string; +declare const sharedXRegionUsWest2KeyArn: string; + +const usWest1Bucket = s3.Bucket.fromBucketAttributes(scope, 'UsEast1Bucket', { + bucketArn: sharedXRegionUsWest1BucketArn, + encryptionKey: kms.Key.fromKeyArn(scope, 'UsEast1BucketKeyArn', sharedXRegionUsWest1BucketArn), +}); + +const usWest2Bucket = s3.Bucket.fromBucketAttributes(scope, 'UsWest2Bucket', { + bucketArn: sharedXRegionUsWest2BucketArn, + encryptionKey: kms.Key.fromKeyArn(scope, 'UsWest2BucketKeyArn', sharedXRegionUsWest2KeyArn), +}); + +const crossRegionReplicationBuckets: Record = { + 'us-west-1': usWest1Bucket, + 'us-west-2': usWest2Bucket, + // Support for additional regions. +} + +const pipeline = new pipelines.CodePipeline(this, 'Pipeline', { + synth: new pipelines.ShellStep('Synth', { + input: pipelines.CodePipelineSource.connection('my-org/my-app', 'main', { + connectionArn: 'arn:aws:codestar-connections:us-east-1:222222222222:connection/7d2469ff-514a-4e4f-9003-5ca4a43cdc41', + }), + commands: ['npm ci','npm run build','npx cdk synth'], + }), // Use shared buckets. + crossRegionReplicationBuckets, +}); +``` ## Context Lookups You might be using CDK constructs that need to look up [runtime diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts index 92ad511679ebc..d699cd3c45aa1 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts @@ -244,6 +244,16 @@ export interface CodePipelineProps { * @default - A new S3 bucket will be created. */ readonly artifactBucket?: s3.IBucket; + /** + * A map of region to S3 bucket name used for cross-region CodePipeline. + * For every Action that you specify targeting a different region than the Pipeline itself, + * if you don't provide an explicit Bucket for that region using this property, + * the construct will automatically create a Stack containing an S3 Bucket in that region. + * Passed directly through to the {@link cp.Pipeline}. + * + * @default - no cross region replication buckets. + */ + readonly crossRegionReplicationBuckets?: { [region: string]: s3.IBucket }; } /** @@ -440,6 +450,9 @@ export class CodePipeline extends PipelineBase { if (this.props.enableKeyRotation !== undefined) { throw new Error('Cannot set \'enableKeyRotation\' if an existing CodePipeline is given using \'codePipeline\''); } + if (this.props.crossRegionReplicationBuckets !== undefined) { + throw new Error('Cannot set \'crossRegionReplicationBuckets\' if an existing CodePipeline is given using \'codePipeline\''); + } if (this.props.reuseCrossRegionSupportStacks !== undefined) { throw new Error('Cannot set \'reuseCrossRegionSupportStacks\' if an existing CodePipeline is given using \'codePipeline\''); } @@ -455,6 +468,7 @@ export class CodePipeline extends PipelineBase { this._pipeline = new cp.Pipeline(this, 'Pipeline', { pipelineName: this.props.pipelineName, crossAccountKeys: this.props.crossAccountKeys ?? false, + crossRegionReplicationBuckets: this.props.crossRegionReplicationBuckets, reuseCrossRegionSupportStacks: this.props.reuseCrossRegionSupportStacks, // This is necessary to make self-mutation work (deployments are guaranteed // to happen only after the builds of the latest pipeline definition). diff --git a/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline-existing.test.ts b/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline-existing.test.ts index b63378fedb0c4..1da9b4ecfb71e 100644 --- a/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline-existing.test.ts +++ b/packages/aws-cdk-lib/pipelines/test/codepipeline/codepipeline-existing.test.ts @@ -46,4 +46,20 @@ describeDeprecated('codepipeline existing', () => { }); }).toThrow("Cannot set 'enableKeyRotation' if an existing CodePipeline is given using 'codePipeline'"); }); + + test('Does not allow setting crossRegionReplicationBuckets if an existing CodePipeline is given', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'PipelineStack'); + const existingCodePipeline = new codePipeline.Pipeline(stack, 'CustomCodePipeline'); + + expect(() => { + new cdkp.CodePipeline(stack, 'CDKPipeline', { + crossRegionReplicationBuckets: {}, // Even the empty set is forbidden. + codePipeline: existingCodePipeline, + synth: new cdkp.ShellStep('Synth', { + commands: ['echo hello'], + }), + }).buildPipeline(); + }).toThrow("Cannot set 'crossRegionReplicationBuckets' if an existing CodePipeline is given using 'codePipeline'"); + }); }); \ No newline at end of file diff --git a/packages/aws-cdk-lib/rosetta/default.ts-fixture b/packages/aws-cdk-lib/rosetta/default.ts-fixture index 4b594b61d4233..8e6da2abe5cee 100644 --- a/packages/aws-cdk-lib/rosetta/default.ts-fixture +++ b/packages/aws-cdk-lib/rosetta/default.ts-fixture @@ -12,6 +12,7 @@ import * as sqs from 'aws-cdk-lib/aws-sqs'; import * as s3 from 'aws-cdk-lib/aws-s3'; import { Annotations, + ArnFormat, App, Aws, CfnCondition, @@ -57,7 +58,7 @@ declare const construct: Construct; declare const constructA: Construct; declare const constructB: Construct; declare const constructC: Construct; -declare const functionProps: lambda.FunctionProps; +declare const functionProps: lambda.SingletonFunctionProps; declare const isCompleteHandler: lambda.Function; declare const myBucket: s3.IBucket; declare const myFunction: lambda.IFunction; diff --git a/packages/aws-cdk-lib/rosetta/pipelines/default.ts-fixture b/packages/aws-cdk-lib/rosetta/pipelines/default.ts-fixture index 61817e5475480..72368fdb67f9b 100644 --- a/packages/aws-cdk-lib/rosetta/pipelines/default.ts-fixture +++ b/packages/aws-cdk-lib/rosetta/pipelines/default.ts-fixture @@ -16,6 +16,7 @@ import secretsmanager = require('aws-cdk-lib/aws-secretsmanager'); import sns = require('aws-cdk-lib/aws-sns'); import subscriptions = require('aws-cdk-lib/aws-sns-subscriptions'); import s3 = require('aws-cdk-lib/aws-s3'); +import kms = require('aws-cdk-lib/aws-kms'); class MyApplicationStage extends Stage { constructor(scope: Construct, id: string, props?: StageProps) { diff --git a/packages/aws-cdk-lib/scripts/scope-map.json b/packages/aws-cdk-lib/scripts/scope-map.json index 6f66e3226a6ab..8263a92920b6c 100644 --- a/packages/aws-cdk-lib/scripts/scope-map.json +++ b/packages/aws-cdk-lib/scripts/scope-map.json @@ -2,6 +2,9 @@ "alexa-ask": [ "Alexa::ASK" ], + "amzn-sdc": [ + "AMZN::SDC" + ], "aws-accessanalyzer": [ "AWS::AccessAnalyzer" ], @@ -146,6 +149,9 @@ "aws-codestarnotifications": [ "AWS::CodeStarNotifications" ], + "aws-codetest": [ + "AWS::CodeTest" + ], "aws-cognito": [ "AWS::Cognito" ], diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 864c7de02c968..7642508136e9d 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -165,6 +165,10 @@ $ # Diff against the currently deployed stack with quiet parameter enabled $ cdk diff --quiet --app='node bin/main.js' MyStackName ``` +The `change-set` flag will make `diff` create a change set and extract resource replacement data from it. This is a bit slower, but will provide no false positives for resource replacement. +The `--no-change-set` mode will consider any change to a property that requires replacement to be a resource replacement, +even if the change is purely cosmetic (like replacing a resource reference with a hardcoded arn). + ### `cdk deploy` Deploys a stack of your CDK app to its environment. During the deployment, the toolkit will output progress diff --git a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml index 399562f08bade..6d4ec2323efbd 100644 --- a/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml +++ b/packages/aws-cdk/lib/api/bootstrap/bootstrap-template.yaml @@ -519,6 +519,7 @@ Resources: Effect: Allow Action: - ssm:GetParameter + - ssm:GetParameters # CreateChangeSet uses this to evaluate any SSM parameters (like `CdkBootstrapVersion`) Resource: - Fn::Sub: "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter${CdkBootstrapVersion}" Version: '2012-10-17' @@ -618,7 +619,7 @@ Resources: Type: String Name: Fn::Sub: '/cdk-bootstrap/${Qualifier}/version' - Value: '19' + Value: '20' Outputs: BucketName: Description: The name of the S3 bucket owned by the CDK toolkit stack diff --git a/packages/aws-cdk/lib/api/deploy-stack.ts b/packages/aws-cdk/lib/api/deploy-stack.ts index 02d1d7b0f0324..8e1c8f55e7ba8 100644 --- a/packages/aws-cdk/lib/api/deploy-stack.ts +++ b/packages/aws-cdk/lib/api/deploy-stack.ts @@ -1,7 +1,6 @@ import * as cxapi from '@aws-cdk/cx-api'; import type { CloudFormation } from 'aws-sdk'; import * as chalk from 'chalk'; -import * as fs from 'fs-extra'; import * as uuid from 'uuid'; import { ISDK, SdkProvider } from './aws-auth'; import { EnvironmentResources } from './environment-resources'; @@ -13,18 +12,12 @@ import { waitForStackDeploy, waitForStackDelete, ParameterValues, ParameterChanges, ResourcesToImport, } from './util/cloudformation'; import { StackActivityMonitor, StackActivityProgress } from './util/cloudformation/stack-activity-monitor'; +import { TemplateBodyParameter, makeBodyParameter } from './util/template-body-parameter'; import { addMetadataAssetsToManifest } from '../assets'; import { Tag } from '../cdk-toolkit'; -import { debug, error, print, warning } from '../logging'; -import { toYAML } from '../serialize'; +import { debug, print, warning } from '../logging'; import { AssetManifestBuilder } from '../util/asset-manifest-builder'; import { publishAssets } from '../util/asset-publishing'; -import { contentHash } from '../util/content-hash'; - -type TemplateBodyParameter = { - TemplateBody?: string - TemplateURL?: string -}; export interface DeployStackResult { readonly noOp: boolean; @@ -233,8 +226,6 @@ export interface ChangeSetDeploymentMethod { readonly changeSetName?: string; } -const LARGE_TEMPLATE_SIZE_KB = 50; - export async function deployStack(options: DeployStackOptions): Promise { const stackArtifact = options.stack; @@ -478,16 +469,24 @@ class FullCloudFormationDeployment { const startTime = new Date(); if (this.update) { - await this.cfn.updateStack({ - StackName: this.stackName, - ClientRequestToken: `update${this.uuid}`, - ...this.commonPrepareOptions(), - ...this.commonExecuteOptions(), - }).promise(); - - const ret = await this.monitorDeployment(startTime, undefined); await this.updateTerminationProtection(); - return ret; + + try { + await this.cfn.updateStack({ + StackName: this.stackName, + ClientRequestToken: `update${this.uuid}`, + ...this.commonPrepareOptions(), + ...this.commonExecuteOptions(), + }).promise(); + } catch (err: any) { + if (err.message === 'No updates are to be performed.') { + debug('No updates are to be performed for stack %s', this.stackName); + return { noOp: true, outputs: this.cloudFormationStack.outputs, stackArn: this.cloudFormationStack.stackId }; + } + throw err; + } + + return this.monitorDeployment(startTime, undefined); } else { // Take advantage of the fact that we can set termination protection during create const terminationProtection = this.stackArtifact.terminationProtection ?? false; @@ -559,100 +558,6 @@ class FullCloudFormationDeployment { } } -/** - * Prepares the body parameter for +CreateChangeSet+. - * - * If the template is small enough to be inlined into the API call, just return - * it immediately. - * - * Otherwise, add it to the asset manifest to get uploaded to the staging - * bucket and return its coordinates. If there is no staging bucket, an error - * is thrown. - * - * @param stack the synthesized stack that provides the CloudFormation template - * @param toolkitInfo information about the toolkit stack - */ -async function makeBodyParameter( - stack: cxapi.CloudFormationStackArtifact, - resolvedEnvironment: cxapi.Environment, - assetManifest: AssetManifestBuilder, - resources: EnvironmentResources, - sdk: ISDK, - overrideTemplate?: any, -): Promise { - - // If the template has already been uploaded to S3, just use it from there. - if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) { - return { TemplateURL: restUrlFromManifest(stack.stackTemplateAssetObjectUrl, resolvedEnvironment, sdk) }; - } - - // Otherwise, pass via API call (if small) or upload here (if large) - const templateJson = toYAML(overrideTemplate ?? stack.template); - - if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) { - return { TemplateBody: templateJson }; - } - - const toolkitInfo = await resources.lookupToolkit(); - if (!toolkitInfo.found) { - error( - `The template for stack "${stack.displayName}" is ${Math.round(templateJson.length / 1024)}KiB. ` + - `Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.\n` + - 'Run the following command in order to setup an S3 bucket in this environment, and then re-deploy:\n\n', - chalk.blue(`\t$ cdk bootstrap ${resolvedEnvironment.name}\n`)); - - throw new Error('Template too large to deploy ("cdk bootstrap" is required)'); - } - - const templateHash = contentHash(templateJson); - const key = `cdk/${stack.id}/${templateHash}.yml`; - - let templateFile = stack.templateFile; - if (overrideTemplate) { - // Add a variant of this template - templateFile = `${stack.templateFile}-${templateHash}.yaml`; - await fs.writeFile(templateFile, templateJson, { encoding: 'utf-8' }); - } - - assetManifest.addFileAsset(templateHash, { - path: templateFile, - }, { - bucketName: toolkitInfo.bucketName, - objectKey: key, - }); - - const templateURL = `${toolkitInfo.bucketUrl}/${key}`; - debug('Storing template in S3 at:', templateURL); - return { TemplateURL: templateURL }; -} - -/** - * Prepare a body parameter for CFN, performing the upload - * - * Return it as-is if it is small enough to pass in the API call, - * upload to S3 and return the coordinates if it is not. - */ -export async function makeBodyParameterAndUpload( - stack: cxapi.CloudFormationStackArtifact, - resolvedEnvironment: cxapi.Environment, - resources: EnvironmentResources, - sdkProvider: SdkProvider, - sdk: ISDK, - overrideTemplate?: any): Promise { - - // We don't have access to the actual asset manifest here, so pretend that the - // stack doesn't have a pre-published URL. - const forceUploadStack = Object.create(stack, { - stackTemplateAssetObjectUrl: { value: undefined }, - }); - - const builder = new AssetManifestBuilder(); - const bodyparam = await makeBodyParameter(forceUploadStack, resolvedEnvironment, builder, resources, sdk, overrideTemplate); - const manifest = builder.toManifest(stack.assembly.directory); - await publishAssets(manifest, sdkProvider, resolvedEnvironment, { quiet: true }); - return bodyparam; -} - export interface DestroyStackOptions { /** * The stack to be destroyed @@ -783,40 +688,6 @@ function compareTags(a: Tag[], b: Tag[]): boolean { return true; } -/** - * Format an S3 URL in the manifest for use with CloudFormation - * - * Replaces environment placeholders (which this field may contain), - * and reformats s3://.../... urls into S3 REST URLs (which CloudFormation - * expects) - */ -function restUrlFromManifest(url: string, environment: cxapi.Environment, sdk: ISDK): string { - const doNotUseMarker = '**DONOTUSE**'; - // This URL may contain placeholders, so still substitute those. - url = cxapi.EnvironmentPlaceholders.replace(url, { - accountId: environment.account, - region: environment.region, - partition: doNotUseMarker, - }); - - // Yes, this is extremely crude, but we don't actually need this so I'm not inclined to spend - // a lot of effort trying to thread the right value to this location. - if (url.indexOf(doNotUseMarker) > -1) { - throw new Error('Cannot use \'${AWS::Partition}\' in the \'stackTemplateAssetObjectUrl\' field'); - } - - const s3Url = url.match(/s3:\/\/([^/]+)\/(.*)$/); - if (!s3Url) { return url; } - - // We need to pass an 'https://s3.REGION.amazonaws.com[.cn]/bucket/object' URL to CloudFormation, but we - // got an 's3://bucket/object' URL instead. Construct the rest API URL here. - const bucketName = s3Url[1]; - const objectKey = s3Url[2]; - - const urlSuffix: string = sdk.getEndpointSuffix(environment.region); - return `https://s3.${environment.region}.${urlSuffix}/${bucketName}/${objectKey}`; -} - function suffixWithErrors(msg: string, errors?: string[]) { return errors && errors.length > 0 ? `${msg}: ${errors.join(', ')}` diff --git a/packages/aws-cdk/lib/api/deployments.ts b/packages/aws-cdk/lib/api/deployments.ts index e6c2254c70ebb..4da0d27837c92 100644 --- a/packages/aws-cdk/lib/api/deployments.ts +++ b/packages/aws-cdk/lib/api/deployments.ts @@ -4,13 +4,14 @@ import { AssetManifest, IManifestEntry } from 'cdk-assets'; import { Mode } from './aws-auth/credentials'; import { ISDK } from './aws-auth/sdk'; import { CredentialsOptions, SdkForEnvironment, SdkProvider } from './aws-auth/sdk-provider'; -import { deployStack, DeployStackResult, destroyStack, makeBodyParameterAndUpload, DeploymentMethod } from './deploy-stack'; +import { deployStack, DeployStackResult, destroyStack, DeploymentMethod } from './deploy-stack'; import { EnvironmentResources, EnvironmentResourcesRegistry } from './environment-resources'; import { HotswapMode } from './hotswap/common'; import { loadCurrentTemplateWithNestedStacks, loadCurrentTemplate, flattenNestedStackNames, TemplateWithNestedStackCount } from './nested-stack-helpers'; import { CloudFormationStack, Template, ResourcesToImport, ResourceIdentifierSummaries } from './util/cloudformation'; import { StackActivityProgress } from './util/cloudformation/stack-activity-monitor'; import { replaceEnvPlaceholders } from './util/placeholders'; +import { makeBodyParameterAndUpload } from './util/template-body-parameter'; import { Tag } from '../cdk-toolkit'; import { debug, warning } from '../logging'; import { buildAssets, publishAssets, BuildAssetsOptions, PublishAssetsOptions, PublishingAws, EVENT_TO_LOGGER } from '../util/asset-publishing'; @@ -424,6 +425,10 @@ export class Deployments { return stack.exists; } + public async prepareSdkWithDeployRole(stackArtifact: cxapi.CloudFormationStackArtifact): Promise { + return this.prepareSdkFor(stackArtifact, undefined, Mode.ForWriting); + } + private async prepareSdkWithLookupOrDeployRole(stackArtifact: cxapi.CloudFormationStackArtifact): Promise { // try to assume the lookup role try { diff --git a/packages/aws-cdk/lib/api/hotswap-deployments.ts b/packages/aws-cdk/lib/api/hotswap-deployments.ts index 0188f2fbd1cf3..51404d624b92e 100644 --- a/packages/aws-cdk/lib/api/hotswap-deployments.ts +++ b/packages/aws-cdk/lib/api/hotswap-deployments.ts @@ -81,7 +81,7 @@ export async function tryHotswapDeployment( nestedStackNames: currentTemplate.nestedStackNames, }); - const stackChanges = cfn_diff.diffTemplate(currentTemplate.deployedTemplate, stackArtifact.template); + const stackChanges = cfn_diff.fullDiff(currentTemplate.deployedTemplate, stackArtifact.template); const { hotswappableChanges, nonHotswappableChanges } = await classifyResourceChanges( stackChanges, evaluateCfnTemplate, sdk, currentTemplate.nestedStackNames, ); @@ -247,7 +247,7 @@ async function findNestedHotswappableChanges( nestedStackName, change.newValue?.Properties?.NestedTemplate, change.newValue?.Properties?.Parameters, ); - const nestedDiff = cfn_diff.diffTemplate( + const nestedDiff = cfn_diff.fullDiff( change.oldValue?.Properties?.NestedTemplate, change.newValue?.Properties?.NestedTemplate, ); diff --git a/packages/aws-cdk/lib/api/util/cloudformation.ts b/packages/aws-cdk/lib/api/util/cloudformation.ts index 6f66e6dc220b4..18f627fe8c1d0 100644 --- a/packages/aws-cdk/lib/api/util/cloudformation.ts +++ b/packages/aws-cdk/lib/api/util/cloudformation.ts @@ -1,8 +1,12 @@ import { SSMPARAM_NO_INVALIDATE } from '@aws-cdk/cx-api'; +import * as cxapi from '@aws-cdk/cx-api'; import { CloudFormation } from 'aws-sdk'; import { StackStatus } from './cloudformation/stack-status'; +import { makeBodyParameterAndUpload, TemplateBodyParameter } from './template-body-parameter'; import { debug } from '../../logging'; import { deserializeStructure } from '../../serialize'; +import { SdkProvider } from '../aws-auth'; +import { Deployments } from '../deployments'; export type Template = { Parameters?: Record; @@ -280,6 +284,115 @@ export async function waitForChangeSet( return ret; } +export type PrepareChangeSetOptions = { + stack: cxapi.CloudFormationStackArtifact; + deployments: Deployments; + uuid: string; + willExecute: boolean; + sdkProvider: SdkProvider; + stream: NodeJS.WritableStream; + parameters: { [name: string]: string | undefined }; +} + +export type CreateChangeSetOptions = { + cfn: CloudFormation; + changeSetName: string; + willExecute: boolean; + exists: boolean; + uuid: string; + stack: cxapi.CloudFormationStackArtifact; + bodyParameter: TemplateBodyParameter; + parameters: { [name: string]: string | undefined }; +} + +/** + * Create a changeset for a diff operation + */ +export async function createDiffChangeSet(options: PrepareChangeSetOptions): Promise { + // `options.stack` has been modified to include any nested stack templates directly inline with its own template, under a special `NestedTemplate` property. + // Thus the parent template's Resources section contains the nested template's CDK metadata check, which uses Fn::Equals. + // This causes CreateChangeSet to fail with `Template Error: Fn::Equals cannot be partially collapsed`. + for (const resource of Object.values((options.stack.template.Resources ?? {}))) { + if ((resource as any).Type === 'AWS::CloudFormation::Stack') { + // eslint-disable-next-line no-console + debug('This stack contains one or more nested stacks, falling back to no change set diff...'); + + return undefined; + } + } + + return uploadBodyParameterAndCreateChangeSet(options); +} + +async function uploadBodyParameterAndCreateChangeSet(options: PrepareChangeSetOptions): Promise { + try { + const preparedSdk = (await options.deployments.prepareSdkWithDeployRole(options.stack)); + const bodyParameter = await makeBodyParameterAndUpload( + options.stack, + preparedSdk.resolvedEnvironment, + preparedSdk.envResources, + options.sdkProvider, + preparedSdk.stackSdk, + ); + const cfn = preparedSdk.stackSdk.cloudFormation(); + const exists = (await CloudFormationStack.lookup(cfn, options.stack.stackName, false)).exists; + + options.stream.write('Creating a change set, this may take a while...\n'); + return await createChangeSet({ + cfn, + changeSetName: 'cdk-diff-change-set', + stack: options.stack, + exists, + uuid: options.uuid, + willExecute: options.willExecute, + bodyParameter, + parameters: options.parameters, + }); + } catch (e: any) { + // eslint-disable-next-line no-console + console.error(`Failed to create change set with error: '${e.message}', falling back to no change-set diff`); + + return undefined; + } +} + +async function createChangeSet(options: CreateChangeSetOptions): Promise { + await cleanupOldChangeset(options.exists, options.changeSetName, options.stack.stackName, options.cfn); + + debug(`Attempting to create ChangeSet with name ${options.changeSetName} for stack ${options.stack.stackName}`); + + const templateParams = TemplateParameters.fromTemplate(options.stack.template); + const stackParams = templateParams.supplyAll(options.parameters); + + const changeSet = await options.cfn.createChangeSet({ + StackName: options.stack.stackName, + ChangeSetName: options.changeSetName, + ChangeSetType: options.exists ? 'UPDATE' : 'CREATE', + Description: `CDK Changeset for diff ${options.uuid}`, + ClientToken: `diff${options.uuid}`, + TemplateURL: options.bodyParameter.TemplateURL, + TemplateBody: options.bodyParameter.TemplateBody, + Parameters: stackParams.apiParameters, + Capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], + }).promise(); + + debug('Initiated creation of changeset: %s; waiting for it to finish creating...', changeSet.Id); + // Fetching all pages if we'll execute, so we can have the correct change count when monitoring. + const createdChangeSet = await waitForChangeSet(options.cfn, options.stack.stackName, options.changeSetName, { fetchAll: options.willExecute }); + await cleanupOldChangeset(options.exists, options.changeSetName, options.stack.stackName, options.cfn); + + return createdChangeSet; +} + +export async function cleanupOldChangeset(exists: boolean, changeSetName: string, stackName: string, cfn: CloudFormation) { + if (exists) { + // Delete any existing change sets generated by CDK since change set names must be unique. + // The delete request is successful as long as the stack exists (even if the change set does not exist). + debug(`Removing existing change set with name ${changeSetName} if it exists`); + await cfn.deleteChangeSet({ StackName: stackName, ChangeSetName: changeSetName }).promise(); + } +} + /** * Return true if the given change set has no changes * diff --git a/packages/aws-cdk/lib/api/util/template-body-parameter.ts b/packages/aws-cdk/lib/api/util/template-body-parameter.ts new file mode 100644 index 0000000000000..cc8381ac2d44a --- /dev/null +++ b/packages/aws-cdk/lib/api/util/template-body-parameter.ts @@ -0,0 +1,146 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import * as chalk from 'chalk'; +import * as fs from 'fs-extra'; +import { debug, error } from '../../logging'; +import { toYAML } from '../../serialize'; +import { AssetManifestBuilder } from '../../util/asset-manifest-builder'; +import { publishAssets } from '../../util/asset-publishing'; +import { contentHash } from '../../util/content-hash'; +import { ISDK, SdkProvider } from '../aws-auth'; +import { EnvironmentResources } from '../environment-resources'; + +export type TemplateBodyParameter = { + TemplateBody?: string + TemplateURL?: string +}; + +const LARGE_TEMPLATE_SIZE_KB = 50; + +/** + * Prepares the body parameter for +CreateChangeSet+. + * + * If the template is small enough to be inlined into the API call, just return + * it immediately. + * + * Otherwise, add it to the asset manifest to get uploaded to the staging + * bucket and return its coordinates. If there is no staging bucket, an error + * is thrown. + * + * @param stack the synthesized stack that provides the CloudFormation template + * @param toolkitInfo information about the toolkit stack + */ +export async function makeBodyParameter( + stack: cxapi.CloudFormationStackArtifact, + resolvedEnvironment: cxapi.Environment, + assetManifest: AssetManifestBuilder, + resources: EnvironmentResources, + sdk: ISDK, + overrideTemplate?: any, +): Promise { + + // If the template has already been uploaded to S3, just use it from there. + if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) { + return { TemplateURL: restUrlFromManifest(stack.stackTemplateAssetObjectUrl, resolvedEnvironment, sdk) }; + } + + // Otherwise, pass via API call (if small) or upload here (if large) + const templateJson = toYAML(overrideTemplate ?? stack.template); + + if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) { + return { TemplateBody: templateJson }; + } + + const toolkitInfo = await resources.lookupToolkit(); + if (!toolkitInfo.found) { + error( + `The template for stack "${stack.displayName}" is ${Math.round(templateJson.length / 1024)}KiB. ` + + `Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.\n` + + 'Run the following command in order to setup an S3 bucket in this environment, and then re-deploy:\n\n', + chalk.blue(`\t$ cdk bootstrap ${resolvedEnvironment.name}\n`)); + + throw new Error('Template too large to deploy ("cdk bootstrap" is required)'); + } + + const templateHash = contentHash(templateJson); + const key = `cdk/${stack.id}/${templateHash}.yml`; + + let templateFile = stack.templateFile; + if (overrideTemplate) { + // Add a variant of this template + templateFile = `${stack.templateFile}-${templateHash}.yaml`; + await fs.writeFile(templateFile, templateJson, { encoding: 'utf-8' }); + } + + assetManifest.addFileAsset(templateHash, { + path: templateFile, + }, { + bucketName: toolkitInfo.bucketName, + objectKey: key, + }); + + const templateURL = `${toolkitInfo.bucketUrl}/${key}`; + debug('Storing template in S3 at:', templateURL); + return { TemplateURL: templateURL }; +} + +/** + * Prepare a body parameter for CFN, performing the upload + * + * Return it as-is if it is small enough to pass in the API call, + * upload to S3 and return the coordinates if it is not. + */ +export async function makeBodyParameterAndUpload( + stack: cxapi.CloudFormationStackArtifact, + resolvedEnvironment: cxapi.Environment, + resources: EnvironmentResources, + sdkProvider: SdkProvider, + sdk: ISDK, + overrideTemplate?: any): Promise { + + // We don't have access to the actual asset manifest here, so pretend that the + // stack doesn't have a pre-published URL. + const forceUploadStack = Object.create(stack, { + stackTemplateAssetObjectUrl: { value: undefined }, + }); + + const builder = new AssetManifestBuilder(); + const bodyparam = await makeBodyParameter(forceUploadStack, resolvedEnvironment, builder, resources, sdk, overrideTemplate); + const manifest = builder.toManifest(stack.assembly.directory); + await publishAssets(manifest, sdkProvider, resolvedEnvironment, { quiet: true }); + + return bodyparam; +} + +/** + * Format an S3 URL in the manifest for use with CloudFormation + * + * Replaces environment placeholders (which this field may contain), + * and reformats s3://.../... urls into S3 REST URLs (which CloudFormation + * expects) + */ +function restUrlFromManifest(url: string, environment: cxapi.Environment, sdk: ISDK): string { + const doNotUseMarker = '**DONOTUSE**'; + // This URL may contain placeholders, so still substitute those. + url = cxapi.EnvironmentPlaceholders.replace(url, { + accountId: environment.account, + region: environment.region, + partition: doNotUseMarker, + }); + + // Yes, this is extremely crude, but we don't actually need this so I'm not inclined to spend + // a lot of effort trying to thread the right value to this location. + if (url.indexOf(doNotUseMarker) > -1) { + throw new Error('Cannot use \'${AWS::Partition}\' in the \'stackTemplateAssetObjectUrl\' field'); + } + + const s3Url = url.match(/s3:\/\/([^/]+)\/(.*)$/); + if (!s3Url) { return url; } + + // We need to pass an 'https://s3.REGION.amazonaws.com[.cn]/bucket/object' URL to CloudFormation, but we + // got an 's3://bucket/object' URL instead. Construct the rest API URL here. + const bucketName = s3Url[1]; + const objectKey = s3Url[2]; + + const urlSuffix: string = sdk.getEndpointSuffix(environment.region); + return `https://s3.${environment.region}.${urlSuffix}/${bucketName}/${objectKey}`; +} diff --git a/packages/aws-cdk/lib/cdk-toolkit.ts b/packages/aws-cdk/lib/cdk-toolkit.ts index d2faab3a274c9..43a2638154a3a 100644 --- a/packages/aws-cdk/lib/cdk-toolkit.ts +++ b/packages/aws-cdk/lib/cdk-toolkit.ts @@ -5,6 +5,7 @@ import * as chalk from 'chalk'; import * as chokidar from 'chokidar'; import * as fs from 'fs-extra'; import * as promptly from 'promptly'; +import * as uuid from 'uuid'; import { DeploymentMethod } from './api'; import { SdkProvider } from './api/aws-auth'; import { Bootstrapper, BootstrapEnvironmentOptions } from './api/bootstrap'; @@ -14,6 +15,7 @@ import { Deployments } from './api/deployments'; import { HotswapMode } from './api/hotswap/common'; import { findCloudWatchLogGroups } from './api/logs/find-cloudwatch-logs'; import { CloudWatchLogEventMonitor } from './api/logs/logs-monitor'; +import { createDiffChangeSet } from './api/util/cloudformation'; import { StackActivityProgress } from './api/util/cloudformation/stack-activity-monitor'; import { generateCdkApp, generateStack, readFromPath, readFromStack, setEnvironment, validateSourceOptions } from './commands/migrate'; import { printSecurityDiff, printStackDiff, RequireApproval } from './diff'; @@ -121,6 +123,8 @@ export class CdkToolkit { const quiet = options.quiet || false; let diffs = 0; + const parameterMap = buildParameterMap(options.parameters); + if (options.templatePath !== undefined) { // Compare single stack against fixed template if (stacks.stackCount !== 1) { @@ -130,10 +134,21 @@ export class CdkToolkit { if (!await fs.pathExists(options.templatePath)) { throw new Error(`There is no file at ${options.templatePath}`); } + + const changeSet = options.changeSet ? await createDiffChangeSet({ + stack: stacks.firstStack, + uuid: uuid.v4(), + willExecute: false, + deployments: this.props.deployments, + sdkProvider: this.props.sdkProvider, + parameters: Object.assign({}, parameterMap['*'], parameterMap[stacks.firstStack.stackName]), + stream, + }) : undefined; + const template = deserializeStructure(await fs.readFile(options.templatePath, { encoding: 'UTF-8' })); diffs = options.securityOnly - ? numberFromBool(printSecurityDiff(template, stacks.firstStack, RequireApproval.Broadening)) - : printStackDiff(template, stacks.firstStack, strict, contextLines, quiet, stream); + ? numberFromBool(printSecurityDiff(template, stacks.firstStack, RequireApproval.Broadening, changeSet)) + : printStackDiff(template, stacks.firstStack, strict, contextLines, quiet, changeSet, stream); } else { // Compare N stacks against deployed templates for (const stack of stacks.stackArtifacts) { @@ -147,10 +162,20 @@ export class CdkToolkit { const currentTemplate = templateWithNames.deployedTemplate; const nestedStackCount = templateWithNames.nestedStackCount; + const changeSet = options.changeSet ? await createDiffChangeSet({ + stack, + uuid: uuid.v4(), + deployments: this.props.deployments, + willExecute: false, + sdkProvider: this.props.sdkProvider, + parameters: Object.assign({}, parameterMap['*'], parameterMap[stacks.firstStack.stackName]), + stream, + }) : undefined; + const stackCount = options.securityOnly - ? (numberFromBool(printSecurityDiff(currentTemplate, stack, RequireApproval.Broadening)) > 0 ? 1 : 0) - : (printStackDiff(currentTemplate, stack, strict, contextLines, quiet, stream) > 0 ? 1 : 0); + ? (numberFromBool(printSecurityDiff(currentTemplate, stack, RequireApproval.Broadening, changeSet)) > 0 ? 1 : 0) + : (printStackDiff(currentTemplate, stack, strict, contextLines, quiet, changeSet, stream) > 0 ? 1 : 0); diffs += stackCount + nestedStackCount; } @@ -181,20 +206,7 @@ export class CdkToolkit { const requireApproval = options.requireApproval ?? RequireApproval.Broadening; - const parameterMap: { [name: string]: { [name: string]: string | undefined } } = { '*': {} }; - for (const key in options.parameters) { - if (options.parameters.hasOwnProperty(key)) { - const [stack, parameter] = key.split(':', 2); - if (!parameter) { - parameterMap['*'][stack] = options.parameters[key]; - } else { - if (!parameterMap[stack]) { - parameterMap[stack] = {}; - } - parameterMap[stack][parameter] = options.parameters[key]; - } - } - } + const parameterMap = buildParameterMap(options.parameters); if (options.hotswap !== HotswapMode.FULL_DEPLOYMENT) { warning('⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments'); @@ -929,6 +941,19 @@ export interface DiffOptions { * @default false */ quiet?: boolean; + + /** + * Additional parameters for CloudFormation at diff time, used to create a change set + * @default {} + */ + parameters?: { [name: string]: string | undefined }; + + /** + * Whether or not to create, analyze, and subsequently delete a changeset + * + * @default true + */ + changeSet?: boolean; } interface CfnDeployOptions { @@ -1286,3 +1311,24 @@ function roundPercentage(num: number): number { function millisecondsToSeconds(num: number): number { return num / 1000; } + +function buildParameterMap(parameters: { + [name: string]: string | undefined; +} | undefined): { [name: string]: { [name: string]: string | undefined } } { + const parameterMap: { [name: string]: { [name: string]: string | undefined } } = { '*': {} }; + for (const key in parameters) { + if (parameters.hasOwnProperty(key)) { + const [stack, parameter] = key.split(':', 2); + if (!parameter) { + parameterMap['*'][stack] = parameters[key]; + } else { + if (!parameterMap[stack]) { + parameterMap[stack] = {}; + } + parameterMap[stack][parameter] = parameters[key]; + } + } + } + + return parameterMap; +} \ No newline at end of file diff --git a/packages/aws-cdk/lib/cli.ts b/packages/aws-cdk/lib/cli.ts index 85e3bdaaf4996..df2f3c24fa569 100644 --- a/packages/aws-cdk/lib/cli.ts +++ b/packages/aws-cdk/lib/cli.ts @@ -262,7 +262,8 @@ async function parseCommandLineArguments(args: string[]) { .option('security-only', { type: 'boolean', desc: 'Only diff for broadened security changes', default: false }) .option('fail', { type: 'boolean', desc: 'Fail with exit code 1 in case of diff' }) .option('processed', { type: 'boolean', desc: 'Whether to compare against the template with Transforms already processed', default: false }) - .option('quiet', { type: 'boolean', alias: 'q', desc: 'Do not print stack name and default message when there is no diff to stdout', default: false })) + .option('quiet', { type: 'boolean', alias: 'q', desc: 'Do not print stack name and default message when there is no diff to stdout', default: false }) + .option('change-set', { type: 'boolean', desc: 'Whether to create a changeset to analyze resource replacements. In this mode, diff will use the deploy role instead of the lookup role.', default: true })) .command('metadata [STACK]', 'Returns all metadata associated with this stack') .command(['acknowledge [ID]', 'ack [ID]'], 'Acknowledge a notice so that it does not show up anymore') .command('notices', 'Returns a list of relevant notices') @@ -495,6 +496,7 @@ export async function exec(args: string[], synthesizer?: Synthesizer): Promise 0) { diff = mangledDiff; @@ -74,8 +76,13 @@ export enum RequireApproval { * * Returns true if the changes are prompt-worthy, false otherwise. */ -export function printSecurityDiff(oldTemplate: any, newTemplate: cxapi.CloudFormationStackArtifact, requireApproval: RequireApproval): boolean { - const diff = cfnDiff.diffTemplate(oldTemplate, newTemplate.template); +export function printSecurityDiff( + oldTemplate: any, + newTemplate: cxapi.CloudFormationStackArtifact, + requireApproval: RequireApproval, + changeSet?: CloudFormation.DescribeChangeSetOutput, +): boolean { + const diff = cfnDiff.fullDiff(oldTemplate, newTemplate.template, changeSet); if (difRequiresApproval(diff, requireApproval)) { // eslint-disable-next-line max-len diff --git a/packages/aws-cdk/lib/import.ts b/packages/aws-cdk/lib/import.ts index 0b181247a44c5..76a42a8c18e23 100644 --- a/packages/aws-cdk/lib/import.ts +++ b/packages/aws-cdk/lib/import.ts @@ -143,7 +143,7 @@ export class ResourceImporter { public async discoverImportableResources(allowNonAdditions = false): Promise { const currentTemplate = await this.currentTemplate(); - const diff = cfnDiff.diffTemplate(currentTemplate, this.stack.template); + const diff = cfnDiff.fullDiff(currentTemplate, this.stack.template); // Ignore changes to CDKMetadata const resourceChanges = Object.entries(diff.resources.changes) diff --git a/packages/aws-cdk/test/api/deploy-stack.test.ts b/packages/aws-cdk/test/api/deploy-stack.test.ts index 440d95cbff8b2..666d4f43410ec 100644 --- a/packages/aws-cdk/test/api/deploy-stack.test.ts +++ b/packages/aws-cdk/test/api/deploy-stack.test.ts @@ -206,6 +206,25 @@ test('call UpdateStack when method=direct and the stack exists already', async ( expect(cfnMocks.updateStack).toHaveBeenCalled(); }); +test('method=direct and no updates to be performed', async () => { + cfnMocks.updateStack?.mockRejectedValueOnce({ + code: 'ValidationError', + message: 'No updates are to be performed.', + } as never); + + // WHEN + givenStackExists(); + + const ret = await deployStack({ + ...standardDeployStackArguments(), + deploymentMethod: { method: 'direct' }, + force: true, + }); + + // THEN + expect(ret).toEqual(expect.objectContaining({ noOp: true })); +}); + test("does not call tryHotswapDeployment() if 'hotswap' is false", async () => { // WHEN await deployStack({ diff --git a/packages/aws-cdk/test/diff.test.ts b/packages/aws-cdk/test/diff.test.ts index 47a6f5f44515c..a7b5905e12f87 100644 --- a/packages/aws-cdk/test/diff.test.ts +++ b/packages/aws-cdk/test/diff.test.ts @@ -6,6 +6,7 @@ import { CloudFormationStackArtifact } from '@aws-cdk/cx-api'; import { instanceMockFrom, MockCloudExecutable } from './util'; import { Deployments } from '../lib/api/deployments'; import { CdkToolkit } from '../lib/cdk-toolkit'; +import * as cfn from '../lib/api/util/cloudformation'; let cloudExecutable: MockCloudExecutable; let cloudFormation: jest.Mocked; @@ -332,6 +333,46 @@ Resources expect(exitCode).toBe(0); }); + + test('diff falls back to non-changeset diff for nested stacks', async () => { + // GIVEN + const changeSetSpy = jest.spyOn(cfn, 'waitForChangeSet'); + const buffer = new StringWritable(); + + // WHEN + const exitCode = await toolkit.diff({ + stackNames: ['Parent'], + stream: buffer, + changeSet: true, + }); + + // THEN + const plainTextOutput = buffer.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '') + .replace(/[ \t]+$/mg, ''); + expect(plainTextOutput.trim()).toEqual(`Stack Parent +Resources +[~] AWS::CloudFormation::Stack AdditionChild + └─ [~] Resources + └─ [~] .SomeResource: + └─ [+] Added: .Properties +[~] AWS::CloudFormation::Stack DeletionChild + └─ [~] Resources + └─ [~] .SomeResource: + └─ [-] Removed: .Properties +[~] AWS::CloudFormation::Stack ChangedChild + └─ [~] Resources + └─ [~] .SomeResource: + └─ [~] .Properties: + └─ [~] .Prop: + ├─ [-] old-value + └─ [+] new-value + + +✨ Number of stacks with differences: 4`); + + expect(exitCode).toBe(0); + expect(changeSetSpy).not.toHaveBeenCalled(); + }); }); class StringWritable extends Writable { diff --git a/packages/awslint/package.json b/packages/awslint/package.json index af3b31f1bad82..77852e5d00703 100644 --- a/packages/awslint/package.json +++ b/packages/awslint/package.json @@ -31,12 +31,12 @@ "@types/fs-extra": "^9.0.13", "@types/jest": "^29.5.11", "@types/yargs": "^15.0.19", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "eslint": "^7.32.0", "eslint-import-resolver-node": "^0.3.9", "eslint-import-resolver-typescript": "^2.7.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^24.7.0", "jest": "^29.7.0", "typescript": "~5.1.6" diff --git a/tools/@aws-cdk/cdk-build-tools/package.json b/tools/@aws-cdk/cdk-build-tools/package.json index 0425000850005..9d42a82b12805 100644 --- a/tools/@aws-cdk/cdk-build-tools/package.json +++ b/tools/@aws-cdk/cdk-build-tools/package.json @@ -47,14 +47,14 @@ "@aws-cdk/eslint-plugin": "0.0.0", "@aws-cdk/yarn-cling": "0.0.0", "@aws-cdk/node-bundle": "0.0.0", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "awslint": "0.0.0", "chalk": "^4", "eslint": "^7.32.0", "eslint-import-resolver-node": "^0.3.9", "eslint-import-resolver-typescript": "^2.7.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^24.7.0", "fs-extra": "^9.1.0", "glob": "^7.2.3", @@ -86,4 +86,4 @@ "ubergen": { "exclude": true } -} +} \ No newline at end of file diff --git a/tools/@aws-cdk/eslint-plugin/package.json b/tools/@aws-cdk/eslint-plugin/package.json index 537021e7f50ae..49d9245a6981a 100644 --- a/tools/@aws-cdk/eslint-plugin/package.json +++ b/tools/@aws-cdk/eslint-plugin/package.json @@ -22,7 +22,7 @@ "typescript": "~5.1.6" }, "dependencies": { - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/parser": "^6.18.0", "eslint": "^7.32.0", "fs-extra": "^9.1.0" }, diff --git a/tools/@aws-cdk/lazify/package.json b/tools/@aws-cdk/lazify/package.json index f84cd226867e2..094d43c472a3d 100644 --- a/tools/@aws-cdk/lazify/package.json +++ b/tools/@aws-cdk/lazify/package.json @@ -30,4 +30,4 @@ }, "main": "lib/index.js", "license": "Apache-2.0" -} +} \ No newline at end of file diff --git a/tools/@aws-cdk/node-bundle/package.json b/tools/@aws-cdk/node-bundle/package.json index 4dacec9b14182..8425029c7d0bb 100644 --- a/tools/@aws-cdk/node-bundle/package.json +++ b/tools/@aws-cdk/node-bundle/package.json @@ -17,12 +17,12 @@ "@types/license-checker": "^25.0.6", "@types/madge": "^5.0.3", "@types/node": "^16", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "eslint": "^8", "eslint-import-resolver-node": "^0.3.9", "eslint-import-resolver-typescript": "^2.7.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "jest": "^29", "jest-junit": "^15", "npm-check-updates": "^16", @@ -87,4 +87,4 @@ }, "types": "lib/index.d.ts", "private": true -} +} \ No newline at end of file diff --git a/tools/@aws-cdk/pkglint/bin/pkglint.ts b/tools/@aws-cdk/pkglint/bin/pkglint.ts index 8a5866af20c1e..05d00b71d8ad6 100644 --- a/tools/@aws-cdk/pkglint/bin/pkglint.ts +++ b/tools/@aws-cdk/pkglint/bin/pkglint.ts @@ -1,9 +1,8 @@ #!/usr/bin/env node import * as path from 'path'; import * as yargs from 'yargs'; -import { findPackageJsons, ValidationRule } from '../lib'; +//import { findPackageJsons, ValidationRule } from '../lib'; -/* eslint-disable @typescript-eslint/no-shadow */ const argv = yargs .env('PKGLINT_') .usage('$0 [directory]') @@ -20,6 +19,7 @@ if (typeof(directory) !== 'string') { argv.directory = path.resolve(directory, process.cwd()); async function main(): Promise { + /* const ruleClasses = require('../lib/rules'); // eslint-disable-line @typescript-eslint/no-require-imports const rules: ValidationRule[] = Object.keys(ruleClasses).map(key => new ruleClasses[key]()).filter(obj => obj instanceof ValidationRule); @@ -37,6 +37,7 @@ async function main(): Promise { if (pkgs.some(p => p.hasReports)) { throw new Error('Some package.json files had errors'); } + */ } main().catch((e) => { diff --git a/tools/@aws-cdk/pkglint/package.json b/tools/@aws-cdk/pkglint/package.json index 0f65942f7848a..07fd03e5a6f9f 100644 --- a/tools/@aws-cdk/pkglint/package.json +++ b/tools/@aws-cdk/pkglint/package.json @@ -43,12 +43,12 @@ "@types/jest": "^29.5.11", "@types/semver": "^7.5.6", "@types/yargs": "^15.0.19", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", "eslint": "^7.32.0", "eslint-import-resolver-node": "^0.3.9", "eslint-import-resolver-typescript": "^2.7.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^24.7.0", "jest": "^29.7.0", "typescript": "~5.1.6" diff --git a/tools/@aws-cdk/prlint/package.json b/tools/@aws-cdk/prlint/package.json index a0769d0f4a6d1..4773d5b771e6c 100644 --- a/tools/@aws-cdk/prlint/package.json +++ b/tools/@aws-cdk/prlint/package.json @@ -29,7 +29,7 @@ "eslint": "^7.32.0", "eslint-import-resolver-node": "^0.3.9", "eslint-import-resolver-typescript": "^2.7.1", - "eslint-plugin-import": "^2.29.0", + "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^24.7.0" }, "jest": { diff --git a/tools/@aws-cdk/spec2cdk/lib/cfn2ts/index.ts b/tools/@aws-cdk/spec2cdk/lib/cfn2ts/index.ts index 144194e69ee26..b14a03c1a057c 100644 --- a/tools/@aws-cdk/spec2cdk/lib/cfn2ts/index.ts +++ b/tools/@aws-cdk/spec2cdk/lib/cfn2ts/index.ts @@ -162,11 +162,11 @@ export async function generateAll( }, ); - Object.keys(moduleMap).map(async (moduleName) => { + await Promise.all(Object.keys(moduleMap).map(async (moduleName) => { // Add generated resources and files to module in map moduleMap[moduleName].resources = generated.modules[moduleName].map((m) => m.resources).reduce(mergeObjects, {}); moduleMap[moduleName].files = generated.modules[moduleName].flatMap((m) => m.outputFiles); - }); + })); return moduleMap; } diff --git a/tools/@aws-cdk/spec2cdk/package.json b/tools/@aws-cdk/spec2cdk/package.json index 5b9139a5f0430..bea9f963fdca3 100644 --- a/tools/@aws-cdk/spec2cdk/package.json +++ b/tools/@aws-cdk/spec2cdk/package.json @@ -32,9 +32,9 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-cdk/aws-service-spec": "^0.0.38", + "@aws-cdk/aws-service-spec": "^0.0.40", "@aws-cdk/service-spec-importers": "^0.0.14", - "@aws-cdk/service-spec-types": "^0.0.38", + "@aws-cdk/service-spec-types": "^0.0.40", "@cdklabs/tskb": "^0.0.3", "@cdklabs/typewriter": "^0.0.3", "camelcase": "^6", diff --git a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-function.json b/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-function.json deleted file mode 100644 index 3ea4aac85560f..0000000000000 --- a/tools/@aws-cdk/spec2cdk/temporary-schemas/us-east-1/aws-lambda-function.json +++ /dev/null @@ -1,546 +0,0 @@ -{ - "tagging": { - "taggable": true, - "tagOnCreate": true, - "tagUpdatable": true, - "tagProperty": "/properties/Tags", - "cloudFormationSystemTags": true - }, - "handlers": { - "read": { - "permissions": [ - "lambda:GetFunction", - "lambda:GetFunctionCodeSigningConfig" - ] - }, - "create": { - "permissions": [ - "lambda:CreateFunction", - "lambda:GetFunction", - "lambda:PutFunctionConcurrency", - "iam:PassRole", - "s3:GetObject", - "s3:GetObjectVersion", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs", - "elasticfilesystem:DescribeMountTargets", - "kms:CreateGrant", - "kms:Decrypt", - "kms:Encrypt", - "kms:GenerateDataKey", - "lambda:GetCodeSigningConfig", - "lambda:GetFunctionCodeSigningConfig", - "lambda:GetLayerVersion", - "lambda:GetRuntimeManagementConfig", - "lambda:PutRuntimeManagementConfig", - "lambda:TagResource", - "lambda:GetPolicy", - "lambda:AddPermission", - "lambda:RemovePermission", - "lambda:GetResourcePolicy", - "lambda:PutResourcePolicy" - ] - }, - "update": { - "permissions": [ - "lambda:DeleteFunctionConcurrency", - "lambda:GetFunction", - "lambda:PutFunctionConcurrency", - "lambda:ListTags", - "lambda:TagResource", - "lambda:UntagResource", - "lambda:UpdateFunctionConfiguration", - "lambda:UpdateFunctionCode", - "iam:PassRole", - "s3:GetObject", - "s3:GetObjectVersion", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs", - "elasticfilesystem:DescribeMountTargets", - "kms:CreateGrant", - "kms:Decrypt", - "kms:GenerateDataKey", - "lambda:GetRuntimeManagementConfig", - "lambda:PutRuntimeManagementConfig", - "lambda:PutFunctionCodeSigningConfig", - "lambda:DeleteFunctionCodeSigningConfig", - "lambda:GetCodeSigningConfig", - "lambda:GetFunctionCodeSigningConfig", - "lambda:GetPolicy", - "lambda:AddPermission", - "lambda:RemovePermission", - "lambda:GetResourcePolicy", - "lambda:PutResourcePolicy", - "lambda:DeleteResourcePolicy" - ] - }, - "list": { - "permissions": [ - "lambda:ListFunctions" - ] - }, - "delete": { - "permissions": [ - "lambda:DeleteFunction", - "ec2:DescribeNetworkInterfaces" - ] - } - }, - "typeName": "AWS::Lambda::Function", - "readOnlyProperties": [ - "/properties/SnapStartResponse", - "/properties/SnapStartResponse/ApplyOn", - "/properties/SnapStartResponse/OptimizationStatus", - "/properties/Arn" - ], - "description": "Resource Type definition for AWS::Lambda::Function in region", - "writeOnlyProperties": [ - "/properties/SnapStart", - "/properties/SnapStart/ApplyOn", - "/properties/Code", - "/properties/Code/ImageUri", - "/properties/Code/S3Bucket", - "/properties/Code/S3Key", - "/properties/Code/S3ObjectVersion", - "/properties/Code/ZipFile", - "/properties/Policy" - ], - "createOnlyProperties": [ - "/properties/FunctionName" - ], - "additionalProperties": false, - "primaryIdentifier": [ - "/properties/FunctionName" - ], - "definitions": { - "ImageConfig": { - "additionalProperties": false, - "type": "object", - "properties": { - "WorkingDirectory": { - "description": "WorkingDirectory.", - "type": "string" - }, - "Command": { - "maxItems": 1500, - "uniqueItems": true, - "description": "Command.", - "type": "array", - "items": { - "type": "string" - } - }, - "EntryPoint": { - "maxItems": 1500, - "uniqueItems": true, - "description": "EntryPoint.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "TracingConfig": { - "description": "The function's AWS X-Ray tracing configuration. To sample and record incoming requests, set Mode to Active.", - "additionalProperties": false, - "type": "object", - "properties": { - "Mode": { - "description": "The tracing mode.", - "type": "string", - "enum": [ - "Active", - "PassThrough" - ] - } - } - }, - "VpcConfig": { - "description": "The VPC security groups and subnets that are attached to a Lambda function. When you connect a function to a VPC, Lambda creates an elastic network interface for each combination of security group and subnet in the function's VPC configuration. The function can only access resources and the internet through that VPC.", - "additionalProperties": false, - "type": "object", - "properties": { - "Ipv6AllowedForDualStack": { - "description": "A boolean indicating whether IPv6 protocols will be allowed for dual stack subnets", - "type": "boolean" - }, - "SecurityGroupIds": { - "maxItems": 5, - "uniqueItems": false, - "description": "A list of VPC security groups IDs.", - "type": "array", - "items": { - "type": "string" - } - }, - "SubnetIds": { - "maxItems": 16, - "uniqueItems": false, - "description": "A list of VPC subnet IDs.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "DeadLetterConfig": { - "description": "The dead-letter queue for failed asynchronous invocations.", - "additionalProperties": false, - "type": "object", - "properties": { - "TargetArn": { - "pattern": "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", - "description": "The Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.", - "type": "string" - } - } - }, - "RuntimeManagementConfig": { - "additionalProperties": false, - "type": "object", - "properties": { - "UpdateRuntimeOn": { - "description": "Trigger for runtime update", - "type": "string", - "enum": [ - "Auto", - "FunctionUpdate", - "Manual" - ] - }, - "RuntimeVersionArn": { - "description": "Unique identifier for a runtime version arn", - "type": "string" - } - }, - "required": [ - "UpdateRuntimeOn" - ] - }, - "SnapStart": { - "description": "The function's SnapStart setting. When set to PublishedVersions, Lambda creates a snapshot of the execution environment when you publish a function version.", - "additionalProperties": false, - "type": "object", - "properties": { - "ApplyOn": { - "description": "Applying SnapStart setting on function resource type.", - "type": "string", - "enum": [ - "PublishedVersions", - "None" - ] - } - }, - "required": [ - "ApplyOn" - ] - }, - "SnapStartResponse": { - "description": "The function's SnapStart Response. When set to PublishedVersions, Lambda creates a snapshot of the execution environment when you publish a function version.", - "additionalProperties": false, - "type": "object", - "properties": { - "OptimizationStatus": { - "description": "Indicates whether SnapStart is activated for the specified function version.", - "type": "string", - "enum": [ - "On", - "Off" - ] - }, - "ApplyOn": { - "description": "Applying SnapStart setting on function resource type.", - "type": "string", - "enum": [ - "PublishedVersions", - "None" - ] - } - } - }, - "Code": { - "additionalProperties": false, - "type": "object", - "properties": { - "S3ObjectVersion": { - "minLength": 1, - "description": "For versioned objects, the version of the deployment package object to use.", - "type": "string", - "maxLength": 1024 - }, - "S3Bucket": { - "minLength": 3, - "pattern": "^[0-9A-Za-z\\.\\-_]*(?