From eb8d322d1d37fece6d555b4e2a8359a42243761e Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 1 Feb 2023 08:34:35 +0800 Subject: [PATCH 01/22] add logging property --- .../@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts | 9 +++++++++ .../lib/codepipeline/private/codebuild-factory.ts | 1 + packages/@aws-cdk/pipelines/package.json | 2 ++ 3 files changed, 12 insertions(+) diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 5fae734d240df..66e640eb5bb50 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -305,6 +305,15 @@ export interface CodeBuildOptions { * @default Duration.hours(1) */ readonly timeout?: Duration; + + /** + * Information about logs for the build project. + * + * A project can create logs in Amazon CloudWatch Logs, an S3 bucket, or both. + * + * @default - no log configuration is set + */ + readonly logging?: cb.LoggingOptions; } diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index b8daddc47e0cb..29f6796e36aba 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -429,6 +429,7 @@ export function mergeCodeBuildOptions(...opts: Array Date: Wed, 1 Feb 2023 08:36:54 +0800 Subject: [PATCH 02/22] init integration test --- .../LoggingPipelineStack.assets.json | 19 + .../LoggingPipelineStack.template.json | 1024 +++++++++++ ...efaultTestDeployAssert13FCCE41.assets.json | 19 + ...aultTestDeployAssert13FCCE41.template.json | 36 + .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 213 +++ .../tree.json | 1538 +++++++++++++++++ .../test/integ.pipeline-with-logging.ts | 88 + 9 files changed, 2950 insertions(+) create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json new file mode 100644 index 0000000000000..c628dbba13982 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "29.0.0", + "files": { + "ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e": { + "source": { + "path": "LoggingPipelineStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e.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/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json new file mode 100644 index 0000000000000..e192bf9ba8b3a --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -0,0 +1,1024 @@ +{ + "Resources": { + "MyLogsBucket57652DD1": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucketAEA9A052": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyF53CCC52": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "cdklabs", + "Repo": "aws-cdk-testing-examples", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "Name": "cdklabs_aws-cdk-testing-examples", + "OutputArtifacts": [ + { + "Name": "cdklabs_aws_cdk_testing_examples_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\":\"a5ad4ab67a5c3bdddc13943d0d13135cd0db018636de9e16d889a9f4dc81b525\"}]" + }, + "InputArtifacts": [ + { + "Name": "cdklabs_aws_cdk_testing_examples_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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "SelfMutate", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "UpdatePipeline" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "PipelineMyWavePostStepF4CC34B8" + } + }, + "InputArtifacts": [ + { + "Name": "cdklabs_aws_cdk_testing_examples_Source" + } + ], + "Name": "PostStep", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "MyWave" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "Type": "S3" + }, + "RestartExecutionOnUpdate": true + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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 \"cd typescript\",\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" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3" + } + }, + "PipelineMyWavePostStepRole440B3F64": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", + "Roles": [ + { + "Ref": "PipelineMyWavePostStepRole440B3F64" + } + ] + } + }, + "PipelineMyWavePostStepF4CC34B8": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "PipelineMyWavePostStepRole440B3F64", + "Arn" + ] + }, + "Source": { + "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"export MY_VAR=test\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/MyWave/PostStep", + "EncryptionKey": "alias/aws/s3" + } + }, + "PipelineCodeBuildActionRole226DB0CB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "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": [ + "PipelineMyWavePostStepF4CC34B8", + "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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "Roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationDAA41400": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "EncryptionKey": "alias/aws/s3" + } + } + }, + "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/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json new file mode 100644 index 0000000000000..7bb2d016711af --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -0,0 +1,19 @@ +{ + "version": "29.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out new file mode 100644 index 0000000000000..d8b441d447f8a --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"29.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json new file mode 100644 index 0000000000000..20686b59dcae4 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "29.0.0", + "testCases": { + "PipelineLoggingTest/DefaultTest": { + "stacks": [ + "LoggingPipelineStack" + ], + "assertionStack": "PipelineLoggingTest/DefaultTest/DeployAssert", + "assertionStackName": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json new file mode 100644 index 0000000000000..9ee64faa0e19e --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json @@ -0,0 +1,213 @@ +{ + "version": "29.0.0", + "artifacts": { + "LoggingPipelineStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LoggingPipelineStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LoggingPipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LoggingPipelineStack.template.json", + "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}/ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "LoggingPipelineStack.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": [ + "LoggingPipelineStack.assets" + ], + "metadata": { + "/LoggingPipelineStack/MyLogsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyLogsBucket57652DD1" + } + ], + "/LoggingPipelineStack/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupF5B46931" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketAEA9A052" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketPolicyF53CCC52" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleB27FAA37" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicy7BDC1ABB" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Pipeline9850B417" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRole440B3F64" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepF4CC34B8" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRole226DB0CB" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ], + "/LoggingPipelineStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LoggingPipelineStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LoggingPipelineStack" + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "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": [ + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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": [ + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets" + ], + "metadata": { + "/PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineLoggingTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json new file mode 100644 index 0000000000000..2819cd6c2ee59 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json @@ -0,0 +1,1538 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "LoggingPipelineStack": { + "id": "LoggingPipelineStack", + "path": "LoggingPipelineStack", + "children": { + "MyLogsBucket": { + "id": "MyLogsBucket", + "path": "LoggingPipelineStack/MyLogsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/MyLogsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": {} + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "LogGroup": { + "id": "LogGroup", + "path": "LoggingPipelineStack/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "0.0.0" + } + }, + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline", + "children": { + "ArtifactsBucket": { + "id": "ArtifactsBucket", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms" + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "cdklabs_aws-cdk-testing-examples", + "outputArtifacts": [ + { + "name": "cdklabs_aws_cdk_testing_examples_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "ThirdParty", + "provider": "GitHub" + }, + "configuration": { + "Owner": "cdklabs", + "Repo": "aws-cdk-testing-examples", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "runOrder": 1 + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Synth", + "inputArtifacts": [ + { + "name": "cdklabs_aws_cdk_testing_examples_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\":\"a5ad4ab67a5c3bdddc13943d0d13135cd0db018636de9e16d889a9f4dc81b525\"}]" + }, + "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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + }, + { + "name": "MyWave", + "actions": [ + { + "name": "PostStep", + "inputArtifacts": [ + { + "name": "cdklabs_aws_cdk_testing_examples_Source" + } + ], + "actionTypeId": { + "category": "Build", + "version": "1", + "owner": "AWS", + "provider": "CodeBuild" + }, + "configuration": { + "ProjectName": { + "Ref": "PipelineMyWavePostStepF4CC34B8" + } + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + } + ], + "artifactStore": { + "type": "S3", + "location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + } + }, + "restartExecutionOnUpdate": true + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source", + "children": { + "cdklabs_aws-cdk-testing-examples": { + "id": "cdklabs_aws-cdk-testing-examples", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/cdklabs_aws-cdk-testing-examples", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "Build": { + "id": "Build", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build", + "children": { + "Synth": { + "id": "Synth", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth", + "children": { + "CdkBuildProject": { + "id": "CdkBuildProject", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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 \"cd typescript\",\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}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "encryptionKey": "alias/aws/s3" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline", + "children": { + "SelfMutate": { + "id": "SelfMutate", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "MyWave": { + "id": "MyWave", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave", + "children": { + "PostStep": { + "id": "PostStep", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep", + "children": { + "PostStep": { + "id": "PostStep", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + } + ] + ] + } + ] + }, + { + "Action": [ + "codebuild:BatchPutCodeCoverages", + "codebuild:BatchPutTestCases", + "codebuild:CreateReport", + "codebuild:CreateReportGroup", + "codebuild:UpdateReport" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":report-group/", + { + "Ref": "PipelineMyWavePostStepF4CC34B8" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", + "roles": [ + { + "Ref": "PipelineMyWavePostStepRole440B3F64" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.0", + "imagePullCredentialsType": "CODEBUILD", + "privilegedMode": false, + "computeType": "BUILD_GENERAL1_SMALL" + }, + "serviceRole": { + "Fn::GetAtt": [ + "PipelineMyWavePostStepRole440B3F64", + "Arn" + ] + }, + "source": { + "type": "CODEPIPELINE", + "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"export MY_VAR=test\"\n ]\n }\n }\n}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/MyWave/PostStep", + "encryptionKey": "alias/aws/s3" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "version": "0.0.0" + } + }, + "CodeBuildActionRole": { + "id": "CodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole", + "children": { + "ImportCodeBuildActionRole": { + "id": "ImportCodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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": [ + "PipelineMyWavePostStepF4CC34B8", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineUpdatePipelineSelfMutationDAA41400", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE", + "roles": [ + { + "Ref": "PipelineCodeBuildActionRole226DB0CB" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline", + "children": { + "SelfMutation": { + "id": "SelfMutation", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "encryptionKey": "alias/aws/s3" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/pipelines.CodePipeline", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "LoggingPipelineStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "LoggingPipelineStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PipelineLoggingTest": { + "id": "PipelineLoggingTest", + "path": "PipelineLoggingTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PipelineLoggingTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts new file mode 100644 index 0000000000000..4bf82e2d06302 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -0,0 +1,88 @@ +/// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true +import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as pipelines from '../lib'; + + +const app = new cdk.App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +const stack = new Stack(app, 'LoggingPipelineStack'); + +const bucket = new s3.Bucket(stack, 'MyLogsBucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +const logGroup = new logs.LogGroup(stack, 'LogGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { + codeBuildDefaults: { + logging: { + cloudWatch: { + logGroup: logGroup, + prefix: 'prefix', + enabled: true, + }, + s3: { + encrypted: true, + bucket: bucket, + prefix: 'test', + enabled: true, + }, + }, + }, + synth: new pipelines.CodeBuildStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('cdklabs/aws-cdk-testing-examples', 'main', { + trigger: GitHubTrigger.NONE, + }), + commands: [ + 'cd typescript', + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + }), +}); + +const postStep = new pipelines.CodeBuildStep('PostStep', { + commands: ['export MY_VAR=test'], +}); + +pipeline.addWave('MyWave', { + post: [postStep], +}); + +const testCase = new integ.IntegTest(app, 'PipelineLoggingTest', { + testCases: [stack], +}); + +pipeline.buildPipeline(); +const synthCodeBuildProject = testCase.assertions.awsApiCall('CodeBuild', 'batchGetProjects', { + names: [pipeline.synthProject.projectName], +}); + +synthCodeBuildProject.assertAtPath('Projects.0.LogsConfig.CloudWatchLogs', + ExpectedResult.objectLike({ + groupName: 'string', + status: 'string', + streamName: 'string', + })); + +synthCodeBuildProject.assertAtPath('Projects.0.LogsConfig.S3Logs', + ExpectedResult.objectLike({ + bucketOwnerAccess: 'string', + encryptionDisabled: false, + location: 'string', + status: 'string', + })); + +app.synth(); From b7a33b62b7e1d2e00546211b69aee8b387d28517 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 1 Feb 2023 08:59:28 +0800 Subject: [PATCH 03/22] init merge loggings --- .../pipelines/lib/codepipeline/codebuild-step.ts | 9 +++++++++ .../lib/codepipeline/private/codebuild-factory.ts | 4 +++- .../pipelines/lib/codepipeline/private/logging.ts | 8 ++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/pipelines/lib/codepipeline/private/logging.ts diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index 398756fb6dff1..7f87e5c823858 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -197,6 +197,15 @@ export class CodeBuildStep extends ShellStep { */ readonly timeout?: Duration; + /** + * Information about logs for the build project. + * + * A project can create logs in Amazon CloudWatch Logs, an S3 bucket, or both. + * + * @default - no log configuration is set + */ + readonly logging?: codebuild.LoggingOptions; + private _project?: codebuild.IProject; private _partialBuildSpec?: codebuild.BuildSpec; private readonly exportedVariables = new Set(); diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index 29f6796e36aba..f60cdef0b73dd 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -17,6 +17,7 @@ import { CodeBuildStep } from '../codebuild-step'; import { CodeBuildOptions } from '../codepipeline'; import { ICodePipelineActionFactory, ProduceActionOptions, CodePipelineActionFactoryResult } from '../codepipeline-action-factory'; import { mergeBuildSpecs } from './buildspecs'; +import { mergeLoggings } from './logging'; export interface CodeBuildFactoryProps { /** @@ -162,6 +163,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { subnetSelection: step.subnetSelection, cache: step.cache, timeout: step.timeout, + logging: step.logging, }), }); @@ -429,7 +431,7 @@ export function mergeCodeBuildOptions(...opts: Array Date: Sun, 5 Feb 2023 10:36:46 +0800 Subject: [PATCH 04/22] adjust merge policy --- .../pipelines/lib/codepipeline/codepipeline.ts | 5 +++++ .../codepipeline/private/codebuild-factory.ts | 1 + .../lib/codepipeline/private/logging.ts | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 66e640eb5bb50..223a5496b06b6 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -816,6 +816,11 @@ export class CodePipeline extends PipelineBase { buildImage: cb.LinuxBuildImage.STANDARD_5_0, computeType: cb.ComputeType.SMALL, }, + // logging: { + // cloudWatch: { + // enabled: true, + // }, + // }, }; const typeBasedCustomizations = { diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index f60cdef0b73dd..ef2b88c07ec94 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -304,6 +304,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { buildSpec: projectBuildSpec, role: this.props.role, timeout: projectOptions.timeout, + logging: projectOptions.logging, }); if (this.props.additionalDependable) { diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/logging.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/logging.ts index 4d770c00ca2c6..570e723bbfdbb 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/logging.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/logging.ts @@ -1,8 +1,18 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; -export function mergeLoggings(a: codebuild.LoggingOptions, b?: codebuild.LoggingOptions): codebuild.LoggingOptions; -export function mergeLoggings(a: codebuild.LoggingOptions | undefined, b: codebuild.LoggingOptions): codebuild.LoggingOptions; +export function mergeLoggings(a: codebuild.LoggingOptions, b?: codebuild.LoggingOptions): codebuild.LoggingOptions | undefined; +export function mergeLoggings(a: codebuild.LoggingOptions | undefined, b: codebuild.LoggingOptions): codebuild.LoggingOptions | undefined; export function mergeLoggings(a?: codebuild.LoggingOptions, b?: codebuild.LoggingOptions): codebuild.LoggingOptions | undefined; export function mergeLoggings(a?: codebuild.LoggingOptions, b?: codebuild.LoggingOptions) { - return b ?? a; + const cloudWatch = b?.cloudWatch ?? a?.cloudWatch; + const s3 = b?.s3 ?? a?.s3; + + if (!cloudWatch && !s3) { + return undefined; + } + + return { + cloudWatch: (cloudWatch?.enabled && !cloudWatch?.logGroup) ? undefined : cloudWatch, + s3: s3, + }; } From 1c8bb29b146605272f5732d5a063d549354bdf26 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 5 Feb 2023 10:37:33 +0800 Subject: [PATCH 05/22] update testing --- .../test/codepipeline/codepipeline.test.ts | 43 + .../LoggingPipelineStack.assets.json | 4 +- .../LoggingPipelineStack.template.json | 294 +--- ...efaultTestDeployAssert13FCCE41.assets.json | 17 +- ...aultTestDeployAssert13FCCE41.template.json | 102 ++ .../index.js | 1205 +++++++++++++++++ .../manifest.json | 95 +- .../tree.json | 499 +++---- .../test/integ.pipeline-with-logging.ts | 50 +- 9 files changed, 1671 insertions(+), 638 deletions(-) create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline.test.ts index 246c3173efc0f..d4d58b36c5cc6 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codepipeline.test.ts @@ -2,6 +2,8 @@ import { Template, Annotations, Match } from '@aws-cdk/assertions'; import * as ccommit from '@aws-cdk/aws-codecommit'; import { Pipeline } from '@aws-cdk/aws-codepipeline'; import * as iam from '@aws-cdk/aws-iam'; +import { LogGroup } from '@aws-cdk/aws-logs'; +import { Bucket } from '@aws-cdk/aws-s3'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; import { Stack } from '@aws-cdk/core'; @@ -392,6 +394,47 @@ test('action name is calculated properly if it has cross-stack dependencies', () }); }); +test('Support logging setting from codeBuildDefaults', () => { + // GIVEN + const pipelineStack = new cdk.Stack(app, 'PipelineStack', { env: PIPELINE_ENV }); + const bucket = new Bucket(pipelineStack, 'MyLogsBucket'); + const logGroup = new LogGroup(pipelineStack, 'LogGroup', { + logGroupName: 'TestLogGroup', + }); + new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk', { + codeBuildDefaults: { + logging: { + cloudWatch: { + logGroup: logGroup, + prefix: 'prefix', + enabled: true, + }, + s3: { + encrypted: true, + bucket: bucket, + prefix: 'test', + enabled: true, + }, + }, + }, + }); + + // THEN + const template = Template.fromStack(pipelineStack); + template.hasResourceProperties('AWS::CodeBuild::Project', { + LogsConfig: Match.objectLike({ + CloudWatchLogs: Match.objectLike({ + Status: 'ENABLED', + StreamName: 'prefix', + }), + S3Logs: Match.objectLike({ + EncryptionDisabled: true, + Status: 'ENABLED', + }), + }), + }); +}); + interface ReuseCodePipelineStackProps extends cdk.StackProps { reuseCrossRegionSupportStacks?: boolean; } diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json index c628dbba13982..4f135fb22795c 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -1,7 +1,7 @@ { "version": "29.0.0", "files": { - "ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e": { + "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d": { "source": { "path": "LoggingPipelineStack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e.json", + "objectKey": "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json index e192bf9ba8b3a..69315b1657920 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -1,10 +1,5 @@ { "Resources": { - "MyLogsBucket57652DD1": { - "Type": "AWS::S3::Bucket", - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "LogGroupF5B46931": { "Type": "AWS::Logs::LogGroup", "Properties": { @@ -182,16 +177,16 @@ "Version": "1" }, "Configuration": { - "Owner": "cdklabs", - "Repo": "aws-cdk-testing-examples", + "Owner": "yo-ga", + "Repo": "cdk-playground", "Branch": "main", "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", "PollForSourceChanges": false }, - "Name": "cdklabs_aws-cdk-testing-examples", + "Name": "yo-ga_cdk-playground", "OutputArtifacts": [ { - "Name": "cdklabs_aws_cdk_testing_examples_Source" + "Name": "yo_ga_cdk_playground_Source" } ], "RunOrder": 1 @@ -212,11 +207,11 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"a5ad4ab67a5c3bdddc13943d0d13135cd0db018636de9e16d889a9f4dc81b525\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" }, "InputArtifacts": [ { - "Name": "cdklabs_aws_cdk_testing_examples_Source" + "Name": "yo_ga_cdk_playground_Source" } ], "Name": "Synth", @@ -267,37 +262,6 @@ } ], "Name": "UpdatePipeline" - }, - { - "Actions": [ - { - "ActionTypeId": { - "Category": "Build", - "Owner": "AWS", - "Provider": "CodeBuild", - "Version": "1" - }, - "Configuration": { - "ProjectName": { - "Ref": "PipelineMyWavePostStepF4CC34B8" - } - }, - "InputArtifacts": [ - { - "Name": "cdklabs_aws_cdk_testing_examples_Source" - } - ], - "Name": "PostStep", - "RoleArn": { - "Fn::GetAtt": [ - "PipelineCodeBuildActionRole226DB0CB", - "Arn" - ] - }, - "RunOrder": 1 - } - ], - "Name": "MyWave" } ], "ArtifactStore": { @@ -335,6 +299,19 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, { "Action": [ "logs:CreateLogGroup", @@ -494,198 +471,23 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"cd typescript\",\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}", + "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" }, "Cache": { "Type": "NO_CACHE" }, "Description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", - "EncryptionKey": "alias/aws/s3" - } - }, - "PipelineMyWavePostStepRole440B3F64": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "codebuild.amazonaws.com" - } - } - ], - "Version": "2012-10-17" - } - } - }, - "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "logs:CreateLogGroup", - "logs:CreateLogStream", - "logs:PutLogEvents" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - }, - ":*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - } - ] - ] - } - ] + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" }, - { - "Action": [ - "codebuild:BatchPutCodeCoverages", - "codebuild:BatchPutTestCases", - "codebuild:CreateReport", - "codebuild:CreateReportGroup", - "codebuild:UpdateReport" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":codebuild:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":report-group/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - }, - "-*" - ] - ] - } - }, - { - "Action": [ - "s3:GetBucket*", - "s3:GetObject*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucketAEA9A052", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucketAEA9A052", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", - "Roles": [ - { - "Ref": "PipelineMyWavePostStepRole440B3F64" + "Status": "ENABLED", + "StreamName": "prefix" } - ] - } - }, - "PipelineMyWavePostStepF4CC34B8": { - "Type": "AWS::CodeBuild::Project", - "Properties": { - "Artifacts": { - "Type": "CODEPIPELINE" - }, - "Environment": { - "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:5.0", - "ImagePullCredentialsType": "CODEBUILD", - "PrivilegedMode": false, - "Type": "LINUX_CONTAINER" - }, - "ServiceRole": { - "Fn::GetAtt": [ - "PipelineMyWavePostStepRole440B3F64", - "Arn" - ] - }, - "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"export MY_VAR=test\"\n ]\n }\n }\n}", - "Type": "CODEPIPELINE" - }, - "Cache": { - "Type": "NO_CACHE" - }, - "Description": "Pipeline step LoggingPipelineStack/Pipeline/MyWave/PostStep", - "EncryptionKey": "alias/aws/s3" + } } }, "PipelineCodeBuildActionRole226DB0CB": { @@ -744,12 +546,6 @@ "Arn" ] }, - { - "Fn::GetAtt": [ - "PipelineMyWavePostStepF4CC34B8", - "Arn" - ] - }, { "Fn::GetAtt": [ "PipelineUpdatePipelineSelfMutationDAA41400", @@ -791,6 +587,19 @@ "Properties": { "PolicyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, { "Action": [ "logs:CreateLogGroup", @@ -983,7 +792,26 @@ "Type": "NO_CACHE" }, "Description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", - "EncryptionKey": "alias/aws/s3" + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" + }, + "Status": "ENABLED", + "StreamName": "prefix" + } + } + } + } + }, + "Outputs": { + "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708": { + "Value": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "Export": { + "Name": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" } } }, diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json index 7bb2d016711af..b8c8f481e4bd0 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -1,7 +1,20 @@ { "version": "29.0.0", "files": { - "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "source": { + "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e": { "source": { "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", "packaging": "file" @@ -9,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "objectKey": "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json index ad9d0fb73d1dd..6b245a667b3b9 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -1,4 +1,106 @@ { + "Resources": { + "AwsApiCallCodeBuildbatchGetProjects": { + "Type": "Custom::DeployAssert@SdkCallCodeBuildbatchGetProjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "CodeBuild", + "api": "batchGetProjects", + "expected": "{\"$StringLike\":\"prefix\"}", + "actualPath": "projects.0.logsConfig.cloudWatchLogs.streamName", + "parameters": { + "names": [ + { + "Fn::ImportValue": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "projects.0.logsConfig.cloudWatchLogs.streamName" + ], + "salt": "1675558017986" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "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" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "codebuild:BatchGetProjects" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallCodeBuildbatchGetProjects": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallCodeBuildbatchGetProjects", + "assertion" + ] + } + } + }, "Parameters": { "BootstrapVersion": { "Type": "AWS::SSM::Parameter::Value", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js new file mode 100644 index 0000000000000..58bcb1ef7f38e --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js @@ -0,0 +1,1205 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} + +// ../assertions/lib/private/sparse-matrix.ts +var SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json index 9ee64faa0e19e..356b02defdcda 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json @@ -17,7 +17,7 @@ "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}/ef71b4b02792dbccb299b30e1186788e498e0ff5afae4dd07a3645348575125e.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -33,12 +33,6 @@ "LoggingPipelineStack.assets" ], "metadata": { - "/LoggingPipelineStack/MyLogsBucket/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "MyLogsBucket57652DD1" - } - ], "/LoggingPipelineStack/LogGroup/Resource": [ { "type": "aws:cdk:logicalId", @@ -93,24 +87,6 @@ "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" } ], - "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepRole440B3F64" - } - ], - "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/DefaultPolicy/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D" - } - ], - "/LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepF4CC34B8" - } - ], "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource": [ { "type": "aws:cdk:logicalId", @@ -141,6 +117,12 @@ "data": "PipelineUpdatePipelineSelfMutationDAA41400" } ], + "/LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ], "/LoggingPipelineStack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", @@ -152,6 +134,42 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } + ], + "MyLogsBucket57652DD1": [ + { + "type": "aws:cdk:logicalId", + "data": "MyLogsBucket57652DD1", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepRole440B3F64": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRole440B3F64", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepF4CC34B8": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepF4CC34B8", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } ] }, "displayName": "LoggingPipelineStack" @@ -172,7 +190,7 @@ "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", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -185,9 +203,34 @@ } }, "dependencies": [ + "LoggingPipelineStack", "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets" ], "metadata": { + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], "/PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion": [ { "type": "aws:cdk:logicalId", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json index 2819cd6c2ee59..78b51faf9db72 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json @@ -8,28 +8,6 @@ "id": "LoggingPipelineStack", "path": "LoggingPipelineStack", "children": { - "MyLogsBucket": { - "id": "MyLogsBucket", - "path": "LoggingPipelineStack/MyLogsBucket", - "children": { - "Resource": { - "id": "Resource", - "path": "LoggingPipelineStack/MyLogsBucket/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::S3::Bucket", - "aws:cdk:cloudformation:props": {} - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucket", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-s3.Bucket", - "version": "0.0.0" - } - }, "LogGroup": { "id": "LogGroup", "path": "LoggingPipelineStack/LogGroup", @@ -306,10 +284,10 @@ "name": "Source", "actions": [ { - "name": "cdklabs_aws-cdk-testing-examples", + "name": "yo-ga_cdk-playground", "outputArtifacts": [ { - "name": "cdklabs_aws_cdk_testing_examples_Source" + "name": "yo_ga_cdk_playground_Source" } ], "actionTypeId": { @@ -319,8 +297,8 @@ "provider": "GitHub" }, "configuration": { - "Owner": "cdklabs", - "Repo": "aws-cdk-testing-examples", + "Owner": "yo-ga", + "Repo": "cdk-playground", "Branch": "main", "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", "PollForSourceChanges": false @@ -336,7 +314,7 @@ "name": "Synth", "inputArtifacts": [ { - "name": "cdklabs_aws_cdk_testing_examples_Source" + "name": "yo_ga_cdk_playground_Source" } ], "outputArtifacts": [ @@ -354,7 +332,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"a5ad4ab67a5c3bdddc13943d0d13135cd0db018636de9e16d889a9f4dc81b525\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" }, "runOrder": 1, "roleArn": { @@ -397,37 +375,6 @@ } } ] - }, - { - "name": "MyWave", - "actions": [ - { - "name": "PostStep", - "inputArtifacts": [ - { - "name": "cdklabs_aws_cdk_testing_examples_Source" - } - ], - "actionTypeId": { - "category": "Build", - "version": "1", - "owner": "AWS", - "provider": "CodeBuild" - }, - "configuration": { - "ProjectName": { - "Ref": "PipelineMyWavePostStepF4CC34B8" - } - }, - "runOrder": 1, - "roleArn": { - "Fn::GetAtt": [ - "PipelineCodeBuildActionRole226DB0CB", - "Arn" - ] - } - } - ] } ], "artifactStore": { @@ -448,9 +395,9 @@ "id": "Source", "path": "LoggingPipelineStack/Pipeline/Pipeline/Source", "children": { - "cdklabs_aws-cdk-testing-examples": { - "id": "cdklabs_aws-cdk-testing-examples", - "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/cdklabs_aws-cdk-testing-examples", + "yo-ga_cdk-playground": { + "id": "yo-ga_cdk-playground", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", "constructInfo": { "fqn": "constructs.Construct", "version": "10.1.216" @@ -523,6 +470,19 @@ "aws:cdk:cloudformation:props": { "policyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, { "Action": [ "logs:CreateLogGroup", @@ -703,13 +663,22 @@ }, "source": { "type": "CODEPIPELINE", - "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"cd typescript\",\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}" + "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}" }, "cache": { "type": "NO_CACHE" }, "description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", - "encryptionKey": "alias/aws/s3" + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } } }, "constructInfo": { @@ -752,272 +721,6 @@ "fqn": "constructs.Construct", "version": "10.1.216" } - }, - "MyWave": { - "id": "MyWave", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave", - "children": { - "PostStep": { - "id": "PostStep", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep", - "children": { - "PostStep": { - "id": "PostStep", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep", - "children": { - "Role": { - "id": "Role", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role", - "children": { - "ImportRole": { - "id": "ImportRole", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/ImportRole", - "constructInfo": { - "fqn": "@aws-cdk/core.Resource", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/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/aws-iam.CfnRole", - "version": "0.0.0" - } - }, - "DefaultPolicy": { - "id": "DefaultPolicy", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Role/DefaultPolicy", - "children": { - "Resource": { - "id": "Resource", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/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:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - }, - ":*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":logs:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":log-group:/aws/codebuild/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - } - ] - ] - } - ] - }, - { - "Action": [ - "codebuild:BatchPutCodeCoverages", - "codebuild:BatchPutTestCases", - "codebuild:CreateReport", - "codebuild:CreateReportGroup", - "codebuild:UpdateReport" - ], - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":codebuild:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":report-group/", - { - "Ref": "PipelineMyWavePostStepF4CC34B8" - }, - "-*" - ] - ] - } - }, - { - "Action": [ - "s3:GetBucket*", - "s3:GetObject*", - "s3:List*" - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucketAEA9A052", - "Arn" - ] - }, - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "PipelineArtifactsBucketAEA9A052", - "Arn" - ] - }, - "/*" - ] - ] - } - ] - } - ], - "Version": "2012-10-17" - }, - "policyName": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", - "roles": [ - { - "Ref": "PipelineMyWavePostStepRole440B3F64" - } - ] - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", - "version": "0.0.0" - } - }, - "Resource": { - "id": "Resource", - "path": "LoggingPipelineStack/Pipeline/Pipeline/MyWave/PostStep/PostStep/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", - "aws:cdk:cloudformation:props": { - "artifacts": { - "type": "CODEPIPELINE" - }, - "environment": { - "type": "LINUX_CONTAINER", - "image": "aws/codebuild/standard:5.0", - "imagePullCredentialsType": "CODEBUILD", - "privilegedMode": false, - "computeType": "BUILD_GENERAL1_SMALL" - }, - "serviceRole": { - "Fn::GetAtt": [ - "PipelineMyWavePostStepRole440B3F64", - "Arn" - ] - }, - "source": { - "type": "CODEPIPELINE", - "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"build\": {\n \"commands\": [\n \"export MY_VAR=test\"\n ]\n }\n }\n}" - }, - "cache": { - "type": "NO_CACHE" - }, - "description": "Pipeline step LoggingPipelineStack/Pipeline/MyWave/PostStep", - "encryptionKey": "alias/aws/s3" - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.CfnProject", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.PipelineProject", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.216" - } - } - }, - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.216" - } } }, "constructInfo": { @@ -1108,12 +811,6 @@ "Arn" ] }, - { - "Fn::GetAtt": [ - "PipelineMyWavePostStepF4CC34B8", - "Arn" - ] - }, { "Fn::GetAtt": [ "PipelineUpdatePipelineSelfMutationDAA41400", @@ -1207,6 +904,19 @@ "aws:cdk:cloudformation:props": { "policyDocument": { "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, { "Action": [ "logs:CreateLogGroup", @@ -1419,7 +1129,16 @@ "type": "NO_CACHE" }, "description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", - "encryptionKey": "alias/aws/s3" + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } } }, "constructInfo": { @@ -1445,6 +1164,24 @@ "version": "0.0.0" } }, + "Exports": { + "id": "Exports", + "path": "LoggingPipelineStack/Exports", + "children": { + "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": { + "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "LoggingPipelineStack/BootstrapVersion", @@ -1487,6 +1224,94 @@ "id": "DeployAssert", "path": "PipelineLoggingTest/DefaultTest/DeployAssert", "children": { + "AwsApiCallCodeBuildbatchGetProjects": { + "id": "AwsApiCallCodeBuildbatchGetProjects", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts index 4bf82e2d06302..4f510e7c7553b 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -1,7 +1,7 @@ /// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; import * as logs from '@aws-cdk/aws-logs'; -import * as s3 from '@aws-cdk/aws-s3'; +// import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Stack } from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; @@ -16,9 +16,9 @@ const app = new cdk.App({ }); const stack = new Stack(app, 'LoggingPipelineStack'); -const bucket = new s3.Bucket(stack, 'MyLogsBucket', { - removalPolicy: cdk.RemovalPolicy.DESTROY, -}); +// const bucket = new s3.Bucket(stack, 'MyLogsBucket', { +// removalPolicy: cdk.RemovalPolicy.DESTROY, +// }); const logGroup = new logs.LogGroup(stack, 'LogGroup', { removalPolicy: cdk.RemovalPolicy.DESTROY, @@ -32,20 +32,13 @@ const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { prefix: 'prefix', enabled: true, }, - s3: { - encrypted: true, - bucket: bucket, - prefix: 'test', - enabled: true, - }, }, }, synth: new pipelines.CodeBuildStep('Synth', { - input: pipelines.CodePipelineSource.gitHub('cdklabs/aws-cdk-testing-examples', 'main', { + input: pipelines.CodePipelineSource.gitHub('yo-ga/cdk-playground', 'main', { trigger: GitHubTrigger.NONE, }), commands: [ - 'cd typescript', 'npm ci', 'npm run build', 'npx cdk synth', @@ -53,36 +46,17 @@ const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { }), }); -const postStep = new pipelines.CodeBuildStep('PostStep', { - commands: ['export MY_VAR=test'], -}); - -pipeline.addWave('MyWave', { - post: [postStep], -}); - const testCase = new integ.IntegTest(app, 'PipelineLoggingTest', { testCases: [stack], }); pipeline.buildPipeline(); -const synthCodeBuildProject = testCase.assertions.awsApiCall('CodeBuild', 'batchGetProjects', { - names: [pipeline.synthProject.projectName], -}); - -synthCodeBuildProject.assertAtPath('Projects.0.LogsConfig.CloudWatchLogs', - ExpectedResult.objectLike({ - groupName: 'string', - status: 'string', - streamName: 'string', - })); - -synthCodeBuildProject.assertAtPath('Projects.0.LogsConfig.S3Logs', - ExpectedResult.objectLike({ - bucketOwnerAccess: 'string', - encryptionDisabled: false, - location: 'string', - status: 'string', - })); +testCase.assertions + .awsApiCall('CodeBuild', 'batchGetProjects', { + names: [pipeline.synthProject.projectName], + }) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.status', ExpectedResult.stringLikeRegexp('ENABLED')) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.logGroup', ExpectedResult.stringLikeRegexp(logGroup.logGroupName)) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.streamName', ExpectedResult.stringLikeRegexp('prefix')); app.synth(); From ddda736a166da0ce59dfef02fc7e7533f4c42bf0 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 5 Feb 2023 11:01:36 +0800 Subject: [PATCH 06/22] add readme --- packages/@aws-cdk/pipelines/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 91ec38e0f4184..ff35f320576c9 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -728,6 +728,8 @@ of properties that allow you to customize various aspects of the projects: ```ts declare const vpc: ec2.Vpc; declare const mySecurityGroup: ec2.SecurityGroup; +declare const bucket: s3.Bucket; +declare const logGroup: logs.LogGroup; new pipelines.CodeBuildStep('Synth', { // ...standard ShellStep props... commands: [/* ... */], @@ -764,6 +766,21 @@ new pipelines.CodeBuildStep('Synth', { rolePolicyStatements: [ new iam.PolicyStatement({ /* ... */ }), ], + + // Control logging options + logging: { + cloudWatch: { + logGroup: logGroup, + prefix: 'prefix', + enabled: true, + }, + s3: { + encrypted: true, + bucket: bucket, + prefix: 's3prefix', + enabled: true, + }, + }, }); ``` From 643ea84dec26f1f3824fd5eadb9b542ee5b4af59 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 5 Feb 2023 11:01:50 +0800 Subject: [PATCH 07/22] remove comment --- .../@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts index 4f510e7c7553b..ac6e63effa45b 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -16,10 +16,6 @@ const app = new cdk.App({ }); const stack = new Stack(app, 'LoggingPipelineStack'); -// const bucket = new s3.Bucket(stack, 'MyLogsBucket', { -// removalPolicy: cdk.RemovalPolicy.DESTROY, -// }); - const logGroup = new logs.LogGroup(stack, 'LogGroup', { removalPolicy: cdk.RemovalPolicy.DESTROY, }); From a246aafdc08688415743e5958a3b6eb4beab1dcd Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 5 Feb 2023 11:08:10 +0800 Subject: [PATCH 08/22] add stack verification description --- .../@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts index ac6e63effa45b..5fa8dc92aba2a 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -1,14 +1,16 @@ /// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; import * as logs from '@aws-cdk/aws-logs'; -// import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; import { Stack } from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; import { ExpectedResult } from '@aws-cdk/integ-tests'; import * as pipelines from '../lib'; - +/* + * Stack verification steps: + * * aws codebuild batch-get-projects --names : should return correct cloudwatchlog settings + */ const app = new cdk.App({ context: { '@aws-cdk/core:newStyleStackSynthesis': '1', From b6eced5a684f12fd7fcd1fdde22be5298ea73651 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 8 Feb 2023 23:19:14 +0800 Subject: [PATCH 09/22] remove comment --- packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 31e1c1c4350b8..6e6084180b3c2 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -821,11 +821,6 @@ export class CodePipeline extends PipelineBase { buildImage: cb.LinuxBuildImage.STANDARD_5_0, computeType: cb.ComputeType.SMALL, }, - // logging: { - // cloudWatch: { - // enabled: true, - // }, - // }, }; const typeBasedCustomizations = { From 99a1f4bbbffc3619fdf7278406bc56f1152f1a94 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Fri, 10 Feb 2023 22:35:59 +0800 Subject: [PATCH 10/22] remove unused comment --- packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts index 5fa8dc92aba2a..b4a071e07ed12 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -1,4 +1,3 @@ -/// !cdk-integ PipelineStack pragma:set-context:@aws-cdk/core:newStyleStackSynthesis=true import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; From e72796822863ea9b2d8d515eb6bf8ae174176335 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Tue, 21 Feb 2023 02:56:17 +0800 Subject: [PATCH 11/22] refactor: logging class & interface --- .../lib/codepipeline/codebuild-step.ts | 14 +- .../lib/codepipeline/codepipeline.ts | 158 +++++++++++++++++- .../codepipeline/private/codebuild-factory.ts | 10 +- .../lib/codepipeline/private/logging.ts | 40 +++-- .../test/codepipeline/codepipeline.test.ts | 22 ++- .../test/integ.pipeline-with-logging.ts | 9 +- 6 files changed, 210 insertions(+), 43 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index 7f87e5c823858..86661ec918fbc 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Duration } from '@aws-cdk/core'; import { ShellStep, ShellStepProps } from '../blueprint'; +import { CloudWatchLoggingOption, S3LoggingOptions } from './codepipeline'; import { mergeBuildSpecs } from './private/buildspecs'; import { makeCodePipelineOutput } from './private/outputs'; @@ -198,13 +199,18 @@ export class CodeBuildStep extends ShellStep { readonly timeout?: Duration; /** - * Information about logs for the build project. + * Information about CloudWatch logs for the build project. * - * A project can create logs in Amazon CloudWatch Logs, an S3 bucket, or both. + * @default - Default CloudWatch logging setting + */ + readonly cloudWatchLogging?: CloudWatchLoggingOption; + + /** + * Information about S3 logs for the build project. * - * @default - no log configuration is set + * @default - Default S3 logging setting */ - readonly logging?: codebuild.LoggingOptions; + readonly s3logging?: S3LoggingOptions; private _project?: codebuild.IProject; private _partialBuildSpec?: codebuild.BuildSpec; diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 2d52bdb58ae7f..a9ee6f2238a11 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -5,6 +5,8 @@ import * as cp from '@aws-cdk/aws-codepipeline'; import * as cpa from '@aws-cdk/aws-codepipeline-actions'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; +import { LogGroup } from '@aws-cdk/aws-logs'; +import { IBucket } from '@aws-cdk/aws-s3'; import { Aws, CfnCapabilities, Duration, PhysicalName, Stack, Names } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; @@ -308,15 +310,163 @@ export interface CodeBuildOptions { readonly timeout?: Duration; /** - * Information about logs for the build project. + * Information about CloudWatch logs for the build project. * - * A project can create logs in Amazon CloudWatch Logs, an S3 bucket, or both. + * @default - Default CloudWatch logging setting + */ + readonly cloudWatchLogging?: CloudWatchLoggingOption; + + /** + * Information about S3 logs for the build project. + * + * @default - Default S3 logging setting + */ + readonly s3logging?: S3LoggingOptions; +} + +/** + * Based class representing CodeBuild Logging settings + */ +export abstract class CodeBuildLoggingBase { + /** + * The setting is enable or not. + */ + public enabled?: boolean; + + constructor(enable?: boolean) { + this.enabled = enable; + } +} + +/** + * CodeBuild CloudWatch settings + */ +export class CloudWatchLoggingOption extends CodeBuildLoggingBase { + /** + * Enable CloudWatch Logging settings + * @param logGroup CloudWatch Log group + * @param prefix CloudWatch log group specific prefix + * @returns CodeBuild CloudWatch logging settings + */ + static enable(logGroup?: LogGroup, prefix?: string): CloudWatchLoggingOption { + return new CloudWatchLoggingOption(true, { logGroup, prefix }); + } + + /** + * Disbale CloudWatch Logging settings + * @returns CodeBuild CloudWatch logging settings + */ + static disable(): CodeBuildLoggingBase { + return new CloudWatchLoggingOption(false, {}); + } + + /** + * The Log Group to send logs to + */ + public logGroup?: LogGroup; + + /** + * The prefix of the stream name of the Amazon CloudWatch Logs + */ + public prefix?: string; + + constructor(enabled?: boolean, options: CloudWatchLoggingOptionProps = {}) { + super(enabled); + this.logGroup = options?.logGroup; + this.prefix = options?.prefix; + } +} + +/** + * Properties for CodeBuild CloudWatch logging settings + */ +export interface CloudWatchLoggingOptionProps { + /** + * The Log Group to send logs to + * + * @default - no log group specified + */ + readonly logGroup?: LogGroup; + + /** + * The prefix of the stream name of the Amazon CloudWatch Logs * - * @default - no log configuration is set + * @default - no prefix */ - readonly logging?: cb.LoggingOptions; + readonly prefix?: string; } +/** + * CodeBuild S3 settings + */ +export class S3LoggingOptions extends CodeBuildLoggingBase { + /** + * Enable S3 Logging settings + * @param bucket S3 bucket to save logs + * @param prefix S3 folder to save logs + * @param encrypted S3 object encrypted or not + * @returns CodeBuild S3 logging settings + */ + static enable(bucket: IBucket, prefix?: string, encrypted?: boolean): S3LoggingOptions { + return new S3LoggingOptions(true, { bucket, prefix, encrypted }); + } + + /** + * Disbale S3 Logging settings + * @returns CodeBuild S3 logging settings + */ + static disable(): S3LoggingOptions { + return new S3LoggingOptions(false, {}); + } + + /** + * The S3 Bucket to send logs to + */ + readonly bucket?: IBucket; + + /** + * Encrypt the S3 build log output + */ + readonly encrypted?: boolean; + + /** + * The path prefix for S3 logs + */ + readonly prefix?: string; + + constructor(enabled?: boolean, options: S3LoggingOptionProps = {}) { + super(enabled); + this.bucket = options?.bucket; + this.encrypted = options?.encrypted ?? true; + this.prefix = options?.prefix; + } +} + +/** + * Properties for CodeBuild S3 logging settings + */ +export interface S3LoggingOptionProps { + /** + * The S3 Bucket to send logs to + * + * @default - no bucket + */ + readonly bucket?: IBucket; + + /** + * The path prefix for S3 logs + * + * @default - no prefix + */ + readonly prefix?: string; + + /** + * Encrypt the S3 build log output + * + * @default true + */ + readonly encrypted?: boolean; +} /** * A CDK Pipeline that uses CodePipeline to deploy CDK apps diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index ef2b88c07ec94..7a96026c3c45c 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -17,7 +17,7 @@ import { CodeBuildStep } from '../codebuild-step'; import { CodeBuildOptions } from '../codepipeline'; import { ICodePipelineActionFactory, ProduceActionOptions, CodePipelineActionFactoryResult } from '../codepipeline-action-factory'; import { mergeBuildSpecs } from './buildspecs'; -import { mergeLoggings } from './logging'; +import { exportLoggingSettings } from './logging'; export interface CodeBuildFactoryProps { /** @@ -163,7 +163,8 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { subnetSelection: step.subnetSelection, cache: step.cache, timeout: step.timeout, - logging: step.logging, + cloudWatchLogging: step.cloudWatchLogging, + s3logging: step.s3logging, }), }); @@ -304,7 +305,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { buildSpec: projectBuildSpec, role: this.props.role, timeout: projectOptions.timeout, - logging: projectOptions.logging, + logging: exportLoggingSettings(projectOptions), }); if (this.props.additionalDependable) { @@ -432,8 +433,9 @@ export function mergeCodeBuildOptions(...opts: Array { }); new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk', { codeBuildDefaults: { - logging: { - cloudWatch: { - logGroup: logGroup, - prefix: 'prefix', - enabled: true, - }, - s3: { - encrypted: true, - bucket: bucket, - prefix: 'test', - enabled: true, - }, + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + enabled: true, + }, + s3logging: { + encrypted: true, + bucket: bucket, + prefix: 'test', + enabled: true, }, }, }); diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts index b4a071e07ed12..ed4e611beaa36 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-with-logging.ts @@ -23,12 +23,9 @@ const logGroup = new logs.LogGroup(stack, 'LogGroup', { const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { codeBuildDefaults: { - logging: { - cloudWatch: { - logGroup: logGroup, - prefix: 'prefix', - enabled: true, - }, + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', }, }, synth: new pipelines.CodeBuildStep('Synth', { From 068b134ed85b0bd2a12b60e66e1c0868c3f531eb Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 26 Mar 2023 23:02:10 +0800 Subject: [PATCH 12/22] fix: import order --- .../pipelines/lib/codepipeline/codebuild-step.ts | 1 - .../pipelines/lib/codepipeline/codepipeline.ts | 12 ++++++------ .../lib/codepipeline/private/codebuild-factory.ts | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index dc180df48d1ce..86661ec918fbc 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -6,7 +6,6 @@ import { ShellStep, ShellStepProps } from '../blueprint'; import { CloudWatchLoggingOption, S3LoggingOptions } from './codepipeline'; import { mergeBuildSpecs } from './private/buildspecs'; import { makeCodePipelineOutput } from './private/outputs'; -import { ShellStep, ShellStepProps } from '../blueprint'; /** * Construction props for a CodeBuildStep diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index 94389fd5b320d..a9ee6f2238a11 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -10,12 +10,6 @@ import { IBucket } from '@aws-cdk/aws-s3'; import { Aws, CfnCapabilities, Duration, PhysicalName, Stack, Names } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; -import { ArtifactMap } from './artifact-map'; -import { CodeBuildStep } from './codebuild-step'; -import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; -import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; -import { namespaceStepOutputs } from './private/outputs'; -import { StackOutputsMap } from './stack-outputs-map'; import { AssetType, FileSet, IFileSetProducer, ManualApprovalStep, ShellStep, StackAsset, StackDeployment, Step } from '../blueprint'; import { DockerCredential, dockerCredentialsInstallCommands, DockerCredentialUsage } from '../docker-credentials'; import { GraphNodeCollection, isGraph, AGraphNode, PipelineGraph } from '../helpers-internal'; @@ -28,6 +22,12 @@ import { toPosixPath } from '../private/fs'; import { actionName, stackVariableNamespace } from '../private/identifiers'; import { enumerate, flatten, maybeSuffix, noUndefined } from '../private/javascript'; import { writeTemplateConfiguration } from '../private/template-configuration'; +import { ArtifactMap } from './artifact-map'; +import { CodeBuildStep } from './codebuild-step'; +import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; +import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; +import { namespaceStepOutputs } from './private/outputs'; +import { StackOutputsMap } from './stack-outputs-map'; /** diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index 51396d00c6788..7a96026c3c45c 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -7,7 +7,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Stack, Token } from '@aws-cdk/core'; import { Construct, IDependable, Node } from 'constructs'; -import { mergeBuildSpecs } from './buildspecs'; import { FileSetLocation, ShellStep, StackOutputReference } from '../../blueprint'; import { StepOutput } from '../../helpers-internal/step-output'; import { cloudAssemblyBuildSpecDir, obtainScope } from '../../private/construct-internals'; From fa62b63131d1f05a3d76231b5f3e06941cd8fb62 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 26 Mar 2023 23:14:37 +0800 Subject: [PATCH 13/22] fix: yarn build fix --- packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts | 2 +- .../@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts | 4 ++-- .../@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/blueprint/step.ts | 2 +- .../pipelines/lib/codepipeline/codepipeline-source.ts | 2 +- .../lib/codepipeline/confirm-permissions-broadening.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts | 2 +- .../pipelines/lib/helpers-internal/pipeline-graph.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts | 6 +++--- packages/@aws-cdk/pipelines/lib/legacy/stage.ts | 4 ++-- .../pipelines/lib/legacy/synths/simple-synth-action.ts | 2 +- .../test/blueprint/helpers-internal/dependencies.test.ts | 2 +- .../pipelines/test/blueprint/helpers-internal/graph.test.ts | 2 +- packages/@aws-cdk/pipelines/test/docker-credentials.test.ts | 2 +- .../pipelines/test/integ.pipeline-without-prepare.ts | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts index c0cc99c1f0281..574c0f45f5bb3 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts @@ -1,8 +1,8 @@ import { CfnOutput, Stack } from '@aws-cdk/core'; +import { mapValues } from '../private/javascript'; import { FileSet, IFileSetProducer } from './file-set'; import { StackDeployment } from './stack-deployment'; import { Step } from './step'; -import { mapValues } from '../private/javascript'; /** * Construction properties for a `ShellStep`. diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts b/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts index 66adb5f738847..b3e88cbfe026e 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts @@ -1,10 +1,10 @@ import * as path from 'path'; import { parse as parseUrl } from 'url'; import * as cxapi from '@aws-cdk/cx-api'; -import { AssetType } from './asset-type'; -import { Step } from './step'; import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; import { isAssetManifest } from '../private/cloud-assembly-internals'; +import { AssetType } from './asset-type'; +import { Step } from './step'; /** * Properties for a `StackDeployment` diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts b/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts index 82b8e54d3f678..0761f03b6a01b 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts @@ -1,9 +1,9 @@ import * as cdk from '@aws-cdk/core'; import { CloudFormationStackArtifact } from '@aws-cdk/cx-api'; -import { StackDeployment } from './stack-deployment'; -import { StackSteps, Step } from './step'; import { isStackArtifact } from '../private/cloud-assembly-internals'; import { pipelineSynth } from '../private/construct-internals'; +import { StackDeployment } from './stack-deployment'; +import { StackSteps, Step } from './step'; /** * Properties for a `StageDeployment` diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts index bdf561ce4b7c0..93f4bc046c7a9 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts @@ -1,7 +1,7 @@ import { Stack, Token } from '@aws-cdk/core'; +import { StepOutput } from '../helpers-internal/step-output'; import { FileSet, IFileSetProducer } from './file-set'; import { StackOutputReference } from './shell-step'; -import { StepOutput } from '../helpers-internal/step-output'; /** * A generic Step which can be added to a Pipeline diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts index 234ea74237326..6bb82e57408fb 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts @@ -8,9 +8,9 @@ import * as iam from '@aws-cdk/aws-iam'; import { IBucket } from '@aws-cdk/aws-s3'; import { Fn, SecretValue, Token } from '@aws-cdk/core'; import { Node } from 'constructs'; +import { FileSet, Step } from '../blueprint'; import { CodePipelineActionFactoryResult, ProduceActionOptions, ICodePipelineActionFactory } from './codepipeline-action-factory'; import { makeCodePipelineOutput } from './private/outputs'; -import { FileSet, Step } from '../blueprint'; /** * Factory for CodePipeline source steps diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts index b14dee628d988..95b66267be25c 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts @@ -3,10 +3,10 @@ import * as cpa from '@aws-cdk/aws-codepipeline-actions'; import * as sns from '@aws-cdk/aws-sns'; import { Stage } from '@aws-cdk/core'; import { Node } from 'constructs'; -import { CodePipeline } from './codepipeline'; -import { CodePipelineActionFactoryResult, ICodePipelineActionFactory, ProduceActionOptions } from './codepipeline-action-factory'; import { Step } from '../blueprint'; import { ApplicationSecurityCheck } from '../private/application-security-check'; +import { CodePipeline } from './codepipeline'; +import { CodePipelineActionFactoryResult, ICodePipelineActionFactory, ProduceActionOptions } from './codepipeline-action-factory'; /** * Properties for a `PermissionsBroadeningCheck` diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts index a1f18309652f6..b7c42c6b7aada 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts @@ -1,8 +1,8 @@ /** * A library for nested graphs */ -import { topoSort } from './toposort'; import { addAll, extract, flatMap, isDefined } from '../private/javascript'; +import { topoSort } from './toposort'; export interface GraphNodeProps { readonly data?: A; diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts index cad9fe7769c1a..cc245cd58e4d4 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts @@ -1,7 +1,7 @@ -import { DependencyBuilders, Graph, GraphNode, GraphNodeCollection } from './graph'; -import { PipelineQueries } from './pipeline-queries'; import { AssetType, FileSet, StackAsset, StackDeployment, StageDeployment, Step, Wave } from '../blueprint'; import { PipelineBase } from '../main/pipeline-base'; +import { DependencyBuilders, Graph, GraphNode, GraphNodeCollection } from './graph'; +import { PipelineQueries } from './pipeline-queries'; export interface PipelineGraphProps { /** diff --git a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts index a7c224bde5611..dd3ba4fadf7fb 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts @@ -5,9 +5,6 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Annotations, App, CfnOutput, PhysicalName, Stack, Stage } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions'; -import { AddStageOptions, AssetPublishingCommand, BaseStageOptions, CdkStage, StackOutput } from './stage'; -import { SimpleSynthAction } from './synths'; import { AssetType } from '../blueprint/asset-type'; import { dockerCredentialsInstallCommands, DockerCredential, DockerCredentialUsage } from '../docker-credentials'; import { ApplicationSecurityCheck } from '../private/application-security-check'; @@ -15,6 +12,9 @@ import { AssetSingletonRole } from '../private/asset-singleton-role'; import { CachedFnSub } from '../private/cached-fnsub'; import { preferredCliVersion } from '../private/cli-version'; import { appOf, assemblyBuilderOf } from '../private/construct-internals'; +import { DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions'; +import { AddStageOptions, AssetPublishingCommand, BaseStageOptions, CdkStage, StackOutput } from './stage'; +import { SimpleSynthAction } from './synths'; const CODE_BUILD_LENGTH_LIMIT = 100; /** diff --git a/packages/@aws-cdk/pipelines/lib/legacy/stage.ts b/packages/@aws-cdk/pipelines/lib/legacy/stage.ts index 4bba0ef8aa1f9..7fcab18e803e9 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/stage.ts @@ -6,13 +6,13 @@ import * as sns from '@aws-cdk/aws-sns'; import { Stage, Aspects } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct, Node } from 'constructs'; -import { DeployCdkStackAction } from './actions'; -import { CdkPipeline } from './pipeline'; import { AssetType } from '../blueprint/asset-type'; import { ApplicationSecurityCheck } from '../private/application-security-check'; import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; import { pipelineSynth } from '../private/construct-internals'; import { topologicalSort } from '../private/toposort'; +import { DeployCdkStackAction } from './actions'; +import { CdkPipeline } from './pipeline'; /** * Construction properties for a CdkStage diff --git a/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts b/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts index 960b7c22ef417..dd4eb77ba5a29 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts @@ -8,9 +8,9 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { copyEnvironmentVariables, filterEmpty } from './_util'; import { dockerCredentialsInstallCommands, DockerCredential, DockerCredentialUsage } from '../../docker-credentials'; import { toPosixPath } from '../../private/fs'; +import { copyEnvironmentVariables, filterEmpty } from './_util'; const DEFAULT_OUTPUT_DIR = 'cdk.out'; diff --git a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts index e284b54e1a517..9610472554301 100644 --- a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts +++ b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts @@ -1,5 +1,5 @@ -import { mkGraph, nodeNames } from './util'; import { GraphNode } from '../../../lib/helpers-internal'; +import { mkGraph, nodeNames } from './util'; describe('with nested graphs', () => { const graph = mkGraph('G', G => { diff --git a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts index b3bbc83e25626..30a022e347932 100644 --- a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts +++ b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts @@ -1,6 +1,6 @@ -import { mkGraph } from './util'; import { GraphNode } from '../../../lib/helpers-internal'; import { flatten } from '../../../lib/private/javascript'; +import { mkGraph } from './util'; test('"uniqueId" renders a graph-wide unique id for each node', () => { diff --git a/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts b/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts index 8527f45cb85e3..902c13a4129b7 100644 --- a/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts +++ b/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts @@ -4,9 +4,9 @@ import * as ecr from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { DockerAssetApp, TestApp } from './testhelpers'; import * as cdkp from '../lib'; import { ShellStep } from '../lib'; +import { DockerAssetApp, TestApp } from './testhelpers'; let app: cdk.App; let stack: cdk.Stack; diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts index 948c03b0acf3a..a48438ad2cbec 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts @@ -4,8 +4,8 @@ import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack, StackProps, RemovalPolicy, Stage, StageProps, DefaultStackSynthesizer } from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; import { Construct } from 'constructs'; -import { PlainStackApp } from './testhelpers'; import * as pipelines from '../lib'; +import { PlainStackApp } from './testhelpers'; class MyStage extends Stage { constructor(scope: Construct, id: string, props?: StageProps) { From af0a783e02be0eccfd81692c5a3dacb46018f105 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 26 Mar 2023 23:43:05 +0800 Subject: [PATCH 14/22] feat: support #23676 --- .../lib/codepipeline/codebuild-step.ts | 18 +- .../LoggingPipelineStack.assets.json | 19 + .../LoggingPipelineStack.template.json | 830 ++++++++++ .../LoggingPipelineStackPipelineCC71B91B.dot | 24 + ...efaultTestDeployAssert13FCCE41.assets.json | 32 + ...aultTestDeployAssert13FCCE41.template.json | 138 ++ .../index.js | 1205 +++++++++++++++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 220 +++ .../tree.json | 1341 +++++++++++++++++ .../test/integ.pipeline-synth-with-logging.ts | 54 + 12 files changed, 3893 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.ts diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index 86661ec918fbc..2d0febdbd5043 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -109,6 +109,20 @@ export interface CodeBuildStepProps extends ShellStepProps { * @default Duration.hours(1) */ readonly timeout?: Duration; + + /** + * Information about CloudWatch logs for the build project. + * + * @default - Default CloudWatch logging setting + */ + readonly cloudWatchLogging?: CloudWatchLoggingOption; + + /** + * Information about S3 logs for the build project. + * + * @default - Disable S3 logging setting + */ + readonly s3logging?: S3LoggingOptions; } /** @@ -208,7 +222,7 @@ export class CodeBuildStep extends ShellStep { /** * Information about S3 logs for the build project. * - * @default - Default S3 logging setting + * @default - Disable S3 logging setting */ readonly s3logging?: S3LoggingOptions; @@ -231,6 +245,8 @@ export class CodeBuildStep extends ShellStep { this.rolePolicyStatements = props.rolePolicyStatements; this.securityGroups = props.securityGroups; this.timeout = props.timeout; + this.cloudWatchLogging = props.cloudWatchLogging; + this.s3logging = props.s3logging; } /** diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json new file mode 100644 index 0000000000000..0ca113a71c59b --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "30.1.0", + "files": { + "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589": { + "source": { + "path": "LoggingPipelineStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json new file mode 100644 index 0000000000000..4abd26d34611a --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -0,0 +1,830 @@ +{ + "Resources": { + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucketAEA9A052": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyF53CCC52": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "Name": "yo-ga_cdk-playground", + "OutputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "InputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "SelfMutate", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "UpdatePipeline" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "Type": "S3" + }, + "RestartExecutionOnUpdate": true + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "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:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" + }, + "Status": "ENABLED", + "StreamName": "prefix" + } + } + } + }, + "PipelineCodeBuildActionRole226DB0CB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "Roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationDAA41400": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "EncryptionKey": "alias/aws/s3" + } + } + }, + "Outputs": { + "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708": { + "Value": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "Export": { + "Name": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + } + }, + "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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot new file mode 100644 index 0000000000000..2500438a82d14 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot @@ -0,0 +1,24 @@ +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 LoggingPipelineStackPipelineCC71B91B.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.yo-ga/cdk-playground" -> "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 Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"Source.yo-ga/cdk-playground"; +"BEGIN Source" -> "Source.yo-ga/cdk-playground"; +"Source.yo-ga/cdk-playground" -> "END Source"; +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json new file mode 100644 index 0000000000000..3a7c06ce92a8d --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -0,0 +1,32 @@ +{ + "version": "30.1.0", + "files": { + "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "source": { + "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24": { + "source": { + "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json new file mode 100644 index 0000000000000..70bad9ad5346e --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "AwsApiCallCodeBuildbatchGetProjects": { + "Type": "Custom::DeployAssert@SdkCallCodeBuildbatchGetProjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "CodeBuild", + "api": "batchGetProjects", + "expected": "{\"$StringLike\":\"prefix\"}", + "actualPath": "projects.0.logsConfig.cloudWatchLogs.streamName", + "parameters": { + "names": [ + { + "Fn::ImportValue": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "projects.0.logsConfig.cloudWatchLogs.streamName" + ], + "salt": "1679844588674" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "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" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "codebuild:BatchGetProjects" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallCodeBuildbatchGetProjects": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallCodeBuildbatchGetProjects", + "assertion" + ] + } + } + }, + "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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js new file mode 100644 index 0000000000000..58bcb1ef7f38e --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js @@ -0,0 +1,1205 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} + +// ../assertions/lib/private/sparse-matrix.ts +var SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b72fef144f05c --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"30.1.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json new file mode 100644 index 0000000000000..a755dc3f6c3de --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "30.1.0", + "testCases": { + "PipelineLoggingTest/DefaultTest": { + "stacks": [ + "LoggingPipelineStack" + ], + "assertionStack": "PipelineLoggingTest/DefaultTest/DeployAssert", + "assertionStackName": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json new file mode 100644 index 0000000000000..18826d152a8df --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json @@ -0,0 +1,220 @@ +{ + "version": "30.1.0", + "artifacts": { + "LoggingPipelineStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LoggingPipelineStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LoggingPipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LoggingPipelineStack.template.json", + "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}/f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "LoggingPipelineStack.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": [ + "LoggingPipelineStack.assets" + ], + "metadata": { + "/LoggingPipelineStack/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupF5B46931" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketAEA9A052" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketPolicyF53CCC52" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleB27FAA37" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicy7BDC1ABB" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Pipeline9850B417" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRole226DB0CB" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ], + "/LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ], + "/LoggingPipelineStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LoggingPipelineStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LoggingPipelineStack" + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "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}/254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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": [ + "LoggingPipelineStack", + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets" + ], + "metadata": { + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineLoggingTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json new file mode 100644 index 0000000000000..a58aeb80e8960 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json @@ -0,0 +1,1341 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "LoggingPipelineStack": { + "id": "LoggingPipelineStack", + "path": "LoggingPipelineStack", + "children": { + "LogGroup": { + "id": "LogGroup", + "path": "LoggingPipelineStack/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "0.0.0" + } + }, + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline", + "children": { + "ArtifactsBucket": { + "id": "ArtifactsBucket", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms" + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "yo-ga_cdk-playground", + "outputArtifacts": [ + { + "name": "yo_ga_cdk_playground_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "ThirdParty", + "provider": "GitHub" + }, + "configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "runOrder": 1 + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Synth", + "inputArtifacts": [ + { + "name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + } + ], + "artifactStore": { + "type": "S3", + "location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + } + }, + "restartExecutionOnUpdate": true + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source", + "children": { + "yo-ga_cdk-playground": { + "id": "yo-ga_cdk-playground", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "Build": { + "id": "Build", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build", + "children": { + "Synth": { + "id": "Synth", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth", + "children": { + "CdkBuildProject": { + "id": "CdkBuildProject", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline", + "children": { + "SelfMutate": { + "id": "SelfMutate", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "version": "0.0.0" + } + }, + "CodeBuildActionRole": { + "id": "CodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole", + "children": { + "ImportCodeBuildActionRole": { + "id": "ImportCodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline", + "children": { + "SelfMutation": { + "id": "SelfMutation", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "encryptionKey": "alias/aws/s3" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/pipelines.CodePipeline", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "LoggingPipelineStack/Exports", + "children": { + "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": { + "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "LoggingPipelineStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "LoggingPipelineStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PipelineLoggingTest": { + "id": "PipelineLoggingTest", + "path": "PipelineLoggingTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PipelineLoggingTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert", + "children": { + "AwsApiCallCodeBuildbatchGetProjects": { + "id": "AwsApiCallCodeBuildbatchGetProjects", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.ts new file mode 100644 index 0000000000000..79c0bff487e00 --- /dev/null +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-synth-with-logging.ts @@ -0,0 +1,54 @@ +import { GitHubTrigger } from '@aws-cdk/aws-codepipeline-actions'; +import * as logs from '@aws-cdk/aws-logs'; +import * as cdk from '@aws-cdk/core'; +import { Stack } from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as pipelines from '../lib'; + +/* + * Stack verification steps: + * * aws codebuild batch-get-projects --names : should return correct cloudwatchlog settings + */ +const app = new cdk.App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +const stack = new Stack(app, 'LoggingPipelineStack'); + +const logGroup = new logs.LogGroup(stack, 'LogGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { + synth: new pipelines.CodeBuildStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('yo-ga/cdk-playground', 'main', { + trigger: GitHubTrigger.NONE, + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + }, + }), +}); + +const testCase = new integ.IntegTest(app, 'PipelineLoggingTest', { + testCases: [stack], +}); + +pipeline.buildPipeline(); +testCase.assertions + .awsApiCall('CodeBuild', 'batchGetProjects', { + names: [pipeline.synthProject.projectName], + }) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.status', ExpectedResult.stringLikeRegexp('ENABLED')) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.logGroup', ExpectedResult.stringLikeRegexp(logGroup.logGroupName)) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.streamName', ExpectedResult.stringLikeRegexp('prefix')); + +app.synth(); From 05cd3fff3cc20c53ac1aa7c3fc0e97fb04e1fad8 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Sun, 26 Mar 2023 23:43:54 +0800 Subject: [PATCH 15/22] chore: update README --- packages/@aws-cdk/pipelines/README.md | 33 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/@aws-cdk/pipelines/README.md b/packages/@aws-cdk/pipelines/README.md index 3f6a0d910e4e5..6c6ecc365e085 100644 --- a/packages/@aws-cdk/pipelines/README.md +++ b/packages/@aws-cdk/pipelines/README.md @@ -768,18 +768,14 @@ new pipelines.CodeBuildStep('Synth', { ], // Control logging options - logging: { - cloudWatch: { - logGroup: logGroup, - prefix: 'prefix', - enabled: true, - }, - s3: { - encrypted: true, - bucket: bucket, - prefix: 's3prefix', - enabled: true, - }, + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + }, + s3Logging: { + encrypted: true, + bucket: bucket, + prefix: 's3prefix', }, }); ``` @@ -791,6 +787,8 @@ or just for the synth, asset publishing, and self-mutation projects by passing ` ```ts declare const vpc: ec2.Vpc; declare const mySecurityGroup: ec2.SecurityGroup; +declare const bucket: s3.Bucket; +declare const logGroup: logs.LogGroup; new pipelines.CodePipeline(this, 'Pipeline', { // Standard CodePipeline properties synth: new pipelines.ShellStep('Synth', { @@ -826,6 +824,17 @@ new pipelines.CodePipeline(this, 'Pipeline', { rolePolicy: [ new iam.PolicyStatement({ /* ... */ }), ], + + // Control logging options + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + }, + s3Logging: { + encrypted: true, + bucket: bucket, + prefix: 's3prefix', + }, }, synthCodeBuildDefaults: { /* ... */ }, From 0e970f5fe798f5f1b73cf2ffa1c43264bfdfa522 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Mon, 27 Mar 2023 07:17:35 +0800 Subject: [PATCH 16/22] fix: eslint --- .../@aws-cdk/pipelines/lib/blueprint/shell-step.ts | 2 +- .../pipelines/lib/blueprint/stack-deployment.ts | 4 ++-- .../pipelines/lib/blueprint/stage-deployment.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/blueprint/step.ts | 2 +- .../pipelines/lib/codepipeline/codebuild-step.ts | 2 +- .../lib/codepipeline/codepipeline-source.ts | 2 +- .../pipelines/lib/codepipeline/codepipeline.ts | 12 ++++++------ .../codepipeline/confirm-permissions-broadening.ts | 4 ++-- .../lib/codepipeline/private/codebuild-factory.ts | 4 ++-- .../@aws-cdk/pipelines/lib/helpers-internal/graph.ts | 2 +- .../pipelines/lib/helpers-internal/pipeline-graph.ts | 4 ++-- packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts | 6 +++--- packages/@aws-cdk/pipelines/lib/legacy/stage.ts | 4 ++-- .../lib/legacy/synths/simple-synth-action.ts | 2 +- .../blueprint/helpers-internal/dependencies.test.ts | 2 +- .../test/blueprint/helpers-internal/graph.test.ts | 2 +- .../pipelines/test/docker-credentials.test.ts | 2 +- .../pipelines/test/integ.pipeline-without-prepare.ts | 2 +- 18 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts index 574c0f45f5bb3..c0cc99c1f0281 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/shell-step.ts @@ -1,8 +1,8 @@ import { CfnOutput, Stack } from '@aws-cdk/core'; -import { mapValues } from '../private/javascript'; import { FileSet, IFileSetProducer } from './file-set'; import { StackDeployment } from './stack-deployment'; import { Step } from './step'; +import { mapValues } from '../private/javascript'; /** * Construction properties for a `ShellStep`. diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts b/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts index b3e88cbfe026e..66adb5f738847 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/stack-deployment.ts @@ -1,10 +1,10 @@ import * as path from 'path'; import { parse as parseUrl } from 'url'; import * as cxapi from '@aws-cdk/cx-api'; -import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; -import { isAssetManifest } from '../private/cloud-assembly-internals'; import { AssetType } from './asset-type'; import { Step } from './step'; +import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; +import { isAssetManifest } from '../private/cloud-assembly-internals'; /** * Properties for a `StackDeployment` diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts b/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts index 0761f03b6a01b..82b8e54d3f678 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/stage-deployment.ts @@ -1,9 +1,9 @@ import * as cdk from '@aws-cdk/core'; import { CloudFormationStackArtifact } from '@aws-cdk/cx-api'; -import { isStackArtifact } from '../private/cloud-assembly-internals'; -import { pipelineSynth } from '../private/construct-internals'; import { StackDeployment } from './stack-deployment'; import { StackSteps, Step } from './step'; +import { isStackArtifact } from '../private/cloud-assembly-internals'; +import { pipelineSynth } from '../private/construct-internals'; /** * Properties for a `StageDeployment` diff --git a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts index 93f4bc046c7a9..bdf561ce4b7c0 100644 --- a/packages/@aws-cdk/pipelines/lib/blueprint/step.ts +++ b/packages/@aws-cdk/pipelines/lib/blueprint/step.ts @@ -1,7 +1,7 @@ import { Stack, Token } from '@aws-cdk/core'; -import { StepOutput } from '../helpers-internal/step-output'; import { FileSet, IFileSetProducer } from './file-set'; import { StackOutputReference } from './shell-step'; +import { StepOutput } from '../helpers-internal/step-output'; /** * A generic Step which can be added to a Pipeline diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index 2d0febdbd5043..560b1b68158f1 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -2,10 +2,10 @@ import * as codebuild from '@aws-cdk/aws-codebuild'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Duration } from '@aws-cdk/core'; -import { ShellStep, ShellStepProps } from '../blueprint'; import { CloudWatchLoggingOption, S3LoggingOptions } from './codepipeline'; import { mergeBuildSpecs } from './private/buildspecs'; import { makeCodePipelineOutput } from './private/outputs'; +import { ShellStep, ShellStepProps } from '../blueprint'; /** * Construction props for a CodeBuildStep diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts index 6bb82e57408fb..234ea74237326 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline-source.ts @@ -8,9 +8,9 @@ import * as iam from '@aws-cdk/aws-iam'; import { IBucket } from '@aws-cdk/aws-s3'; import { Fn, SecretValue, Token } from '@aws-cdk/core'; import { Node } from 'constructs'; -import { FileSet, Step } from '../blueprint'; import { CodePipelineActionFactoryResult, ProduceActionOptions, ICodePipelineActionFactory } from './codepipeline-action-factory'; import { makeCodePipelineOutput } from './private/outputs'; +import { FileSet, Step } from '../blueprint'; /** * Factory for CodePipeline source steps diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts index a9ee6f2238a11..94389fd5b320d 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codepipeline.ts @@ -10,6 +10,12 @@ import { IBucket } from '@aws-cdk/aws-s3'; import { Aws, CfnCapabilities, Duration, PhysicalName, Stack, Names } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct } from 'constructs'; +import { ArtifactMap } from './artifact-map'; +import { CodeBuildStep } from './codebuild-step'; +import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; +import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; +import { namespaceStepOutputs } from './private/outputs'; +import { StackOutputsMap } from './stack-outputs-map'; import { AssetType, FileSet, IFileSetProducer, ManualApprovalStep, ShellStep, StackAsset, StackDeployment, Step } from '../blueprint'; import { DockerCredential, dockerCredentialsInstallCommands, DockerCredentialUsage } from '../docker-credentials'; import { GraphNodeCollection, isGraph, AGraphNode, PipelineGraph } from '../helpers-internal'; @@ -22,12 +28,6 @@ import { toPosixPath } from '../private/fs'; import { actionName, stackVariableNamespace } from '../private/identifiers'; import { enumerate, flatten, maybeSuffix, noUndefined } from '../private/javascript'; import { writeTemplateConfiguration } from '../private/template-configuration'; -import { ArtifactMap } from './artifact-map'; -import { CodeBuildStep } from './codebuild-step'; -import { CodePipelineActionFactoryResult, ICodePipelineActionFactory } from './codepipeline-action-factory'; -import { CodeBuildFactory, mergeCodeBuildOptions } from './private/codebuild-factory'; -import { namespaceStepOutputs } from './private/outputs'; -import { StackOutputsMap } from './stack-outputs-map'; /** diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts index 95b66267be25c..b14dee628d988 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/confirm-permissions-broadening.ts @@ -3,10 +3,10 @@ import * as cpa from '@aws-cdk/aws-codepipeline-actions'; import * as sns from '@aws-cdk/aws-sns'; import { Stage } from '@aws-cdk/core'; import { Node } from 'constructs'; -import { Step } from '../blueprint'; -import { ApplicationSecurityCheck } from '../private/application-security-check'; import { CodePipeline } from './codepipeline'; import { CodePipelineActionFactoryResult, ICodePipelineActionFactory, ProduceActionOptions } from './codepipeline-action-factory'; +import { Step } from '../blueprint'; +import { ApplicationSecurityCheck } from '../private/application-security-check'; /** * Properties for a `PermissionsBroadeningCheck` diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts index 7a96026c3c45c..3dd07aac135e2 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -7,6 +7,8 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Stack, Token } from '@aws-cdk/core'; import { Construct, IDependable, Node } from 'constructs'; +import { mergeBuildSpecs } from './buildspecs'; +import { exportLoggingSettings } from './logging'; import { FileSetLocation, ShellStep, StackOutputReference } from '../../blueprint'; import { StepOutput } from '../../helpers-internal/step-output'; import { cloudAssemblyBuildSpecDir, obtainScope } from '../../private/construct-internals'; @@ -16,8 +18,6 @@ import { ArtifactMap } from '../artifact-map'; import { CodeBuildStep } from '../codebuild-step'; import { CodeBuildOptions } from '../codepipeline'; import { ICodePipelineActionFactory, ProduceActionOptions, CodePipelineActionFactoryResult } from '../codepipeline-action-factory'; -import { mergeBuildSpecs } from './buildspecs'; -import { exportLoggingSettings } from './logging'; export interface CodeBuildFactoryProps { /** diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts index b7c42c6b7aada..a1f18309652f6 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/graph.ts @@ -1,8 +1,8 @@ /** * A library for nested graphs */ -import { addAll, extract, flatMap, isDefined } from '../private/javascript'; import { topoSort } from './toposort'; +import { addAll, extract, flatMap, isDefined } from '../private/javascript'; export interface GraphNodeProps { readonly data?: A; diff --git a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts index cc245cd58e4d4..cad9fe7769c1a 100644 --- a/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts +++ b/packages/@aws-cdk/pipelines/lib/helpers-internal/pipeline-graph.ts @@ -1,7 +1,7 @@ -import { AssetType, FileSet, StackAsset, StackDeployment, StageDeployment, Step, Wave } from '../blueprint'; -import { PipelineBase } from '../main/pipeline-base'; import { DependencyBuilders, Graph, GraphNode, GraphNodeCollection } from './graph'; import { PipelineQueries } from './pipeline-queries'; +import { AssetType, FileSet, StackAsset, StackDeployment, StageDeployment, Step, Wave } from '../blueprint'; +import { PipelineBase } from '../main/pipeline-base'; export interface PipelineGraphProps { /** diff --git a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts index dd3ba4fadf7fb..a7c224bde5611 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/pipeline.ts @@ -5,6 +5,9 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import { Annotations, App, CfnOutput, PhysicalName, Stack, Stage } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions'; +import { AddStageOptions, AssetPublishingCommand, BaseStageOptions, CdkStage, StackOutput } from './stage'; +import { SimpleSynthAction } from './synths'; import { AssetType } from '../blueprint/asset-type'; import { dockerCredentialsInstallCommands, DockerCredential, DockerCredentialUsage } from '../docker-credentials'; import { ApplicationSecurityCheck } from '../private/application-security-check'; @@ -12,9 +15,6 @@ import { AssetSingletonRole } from '../private/asset-singleton-role'; import { CachedFnSub } from '../private/cached-fnsub'; import { preferredCliVersion } from '../private/cli-version'; import { appOf, assemblyBuilderOf } from '../private/construct-internals'; -import { DeployCdkStackAction, PublishAssetsAction, UpdatePipelineAction } from './actions'; -import { AddStageOptions, AssetPublishingCommand, BaseStageOptions, CdkStage, StackOutput } from './stage'; -import { SimpleSynthAction } from './synths'; const CODE_BUILD_LENGTH_LIMIT = 100; /** diff --git a/packages/@aws-cdk/pipelines/lib/legacy/stage.ts b/packages/@aws-cdk/pipelines/lib/legacy/stage.ts index 7fcab18e803e9..4bba0ef8aa1f9 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/stage.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/stage.ts @@ -6,13 +6,13 @@ import * as sns from '@aws-cdk/aws-sns'; import { Stage, Aspects } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import { Construct, Node } from 'constructs'; +import { DeployCdkStackAction } from './actions'; +import { CdkPipeline } from './pipeline'; import { AssetType } from '../blueprint/asset-type'; import { ApplicationSecurityCheck } from '../private/application-security-check'; import { AssetManifestReader, DockerImageManifestEntry, FileManifestEntry } from '../private/asset-manifest'; import { pipelineSynth } from '../private/construct-internals'; import { topologicalSort } from '../private/toposort'; -import { DeployCdkStackAction } from './actions'; -import { CdkPipeline } from './pipeline'; /** * Construction properties for a CdkStage diff --git a/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts b/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts index dd4eb77ba5a29..960b7c22ef417 100644 --- a/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts +++ b/packages/@aws-cdk/pipelines/lib/legacy/synths/simple-synth-action.ts @@ -8,9 +8,9 @@ import * as events from '@aws-cdk/aws-events'; import * as iam from '@aws-cdk/aws-iam'; import { Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; +import { copyEnvironmentVariables, filterEmpty } from './_util'; import { dockerCredentialsInstallCommands, DockerCredential, DockerCredentialUsage } from '../../docker-credentials'; import { toPosixPath } from '../../private/fs'; -import { copyEnvironmentVariables, filterEmpty } from './_util'; const DEFAULT_OUTPUT_DIR = 'cdk.out'; diff --git a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts index 9610472554301..e284b54e1a517 100644 --- a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts +++ b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/dependencies.test.ts @@ -1,5 +1,5 @@ -import { GraphNode } from '../../../lib/helpers-internal'; import { mkGraph, nodeNames } from './util'; +import { GraphNode } from '../../../lib/helpers-internal'; describe('with nested graphs', () => { const graph = mkGraph('G', G => { diff --git a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts index 30a022e347932..b3bbc83e25626 100644 --- a/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts +++ b/packages/@aws-cdk/pipelines/test/blueprint/helpers-internal/graph.test.ts @@ -1,6 +1,6 @@ +import { mkGraph } from './util'; import { GraphNode } from '../../../lib/helpers-internal'; import { flatten } from '../../../lib/private/javascript'; -import { mkGraph } from './util'; test('"uniqueId" renders a graph-wide unique id for each node', () => { diff --git a/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts b/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts index 902c13a4129b7..8527f45cb85e3 100644 --- a/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts +++ b/packages/@aws-cdk/pipelines/test/docker-credentials.test.ts @@ -4,9 +4,9 @@ import * as ecr from '@aws-cdk/aws-ecr'; import * as iam from '@aws-cdk/aws-iam'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; +import { DockerAssetApp, TestApp } from './testhelpers'; import * as cdkp from '../lib'; import { ShellStep } from '../lib'; -import { DockerAssetApp, TestApp } from './testhelpers'; let app: cdk.App; let stack: cdk.Stack; diff --git a/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts b/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts index a48438ad2cbec..948c03b0acf3a 100644 --- a/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts +++ b/packages/@aws-cdk/pipelines/test/integ.pipeline-without-prepare.ts @@ -4,8 +4,8 @@ import * as s3 from '@aws-cdk/aws-s3'; import { App, Stack, StackProps, RemovalPolicy, Stage, StageProps, DefaultStackSynthesizer } from '@aws-cdk/core'; import * as integ from '@aws-cdk/integ-tests'; import { Construct } from 'constructs'; -import * as pipelines from '../lib'; import { PlainStackApp } from './testhelpers'; +import * as pipelines from '../lib'; class MyStage extends Stage { constructor(scope: Construct, id: string, props?: StageProps) { From d88ba34bd992d3b9d3a5696230ad145f4efc70f7 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 5 Apr 2023 19:01:13 +0800 Subject: [PATCH 17/22] fix: correct merge --- .../pipelines/lib/codepipeline/codebuild-step.ts | 2 +- .../aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codebuild-step.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codebuild-step.ts index 6871fb88a16cf..eba48a97825d5 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codebuild-step.ts @@ -1,5 +1,5 @@ import * as codebuild from '../../../aws-codebuild'; -import * as ec2 from '../../..//aws-ec2'; +import * as ec2 from '../../../aws-ec2'; import * as iam from '../../../aws-iam'; import { Duration } from '../../../core'; import { CloudWatchLoggingOption, S3LoggingOptions } from './codepipeline'; diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts index 357019bbb4f49..e351a5ba90ce0 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts @@ -8,7 +8,7 @@ import * as iam from '../../../aws-iam'; import { LogGroup } from '../../../aws-logs'; import { IBucket } from '../../../aws-s3'; import { Aws, CfnCapabilities, Duration, PhysicalName, Stack, Names } from '../../../core'; -import * as cxapi from '@aws-cdk/cx-api'; +import * as cxapi from '../../../cx-api'; import { Construct } from 'constructs'; import { ArtifactMap } from './artifact-map'; import { CodeBuildStep } from './codebuild-step'; @@ -148,7 +148,7 @@ export interface CodePipelineProps { /** * Customize the CodeBuild projects created for this pipeline * - * @default - All projects run non-privileged build, SMALL instance, LinuxBuildImage.STANDARD_5_0 + * @default - All projects run non-privileged build, SMALL instance, LinuxBuildImage.STANDARD_6_0 */ readonly codeBuildDefaults?: CodeBuildOptions; @@ -993,7 +993,7 @@ export class CodePipeline extends PipelineBase { private codeBuildDefaultsFor(nodeType: CodeBuildProjectType): CodeBuildOptions | undefined { const defaultOptions: CodeBuildOptions = { buildEnvironment: { - buildImage: cb.LinuxBuildImage.STANDARD_5_0, + buildImage: CDKP_DEFAULT_CODEBUILD_IMAGE, computeType: cb.ComputeType.SMALL, }, }; From 972f5382b836217c748d0e26594d05bb6fbc1639 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 5 Apr 2023 19:38:48 +0800 Subject: [PATCH 18/22] fix: add inte test back --- .../LoggingPipelineStack.assets.json | 19 + .../LoggingPipelineStack.template.json | 830 ++++++++++ .../LoggingPipelineStackPipelineCC71B91B.dot | 24 + ...efaultTestDeployAssert13FCCE41.assets.json | 32 + ...aultTestDeployAssert13FCCE41.template.json | 138 ++ .../index.js | 1205 +++++++++++++++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 220 +++ .../tree.json | 1341 ++++++++++++++++ .../test/integ.pipeline-synth-with-logging.ts | 54 + .../LoggingPipelineStack.assets.json | 19 + .../LoggingPipelineStack.template.json | 852 +++++++++++ ...efaultTestDeployAssert13FCCE41.assets.json | 32 + ...aultTestDeployAssert13FCCE41.template.json | 138 ++ .../index.js | 1205 +++++++++++++++ .../cdk.out | 1 + .../integ.json | 12 + .../manifest.json | 256 ++++ .../tree.json | 1363 +++++++++++++++++ .../test/integ.pipeline-with-logging.ts | 56 + 21 files changed, 7810 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json new file mode 100644 index 0000000000000..0ca113a71c59b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "30.1.0", + "files": { + "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589": { + "source": { + "path": "LoggingPipelineStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.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.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json new file mode 100644 index 0000000000000..4abd26d34611a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -0,0 +1,830 @@ +{ + "Resources": { + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucketAEA9A052": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyF53CCC52": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "Name": "yo-ga_cdk-playground", + "OutputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "InputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "SelfMutate", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "UpdatePipeline" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "Type": "S3" + }, + "RestartExecutionOnUpdate": true + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "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:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" + }, + "Status": "ENABLED", + "StreamName": "prefix" + } + } + } + }, + "PipelineCodeBuildActionRole226DB0CB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "Roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationDAA41400": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "EncryptionKey": "alias/aws/s3" + } + } + }, + "Outputs": { + "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708": { + "Value": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "Export": { + "Name": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + } + }, + "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.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot new file mode 100644 index 0000000000000..2500438a82d14 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot @@ -0,0 +1,24 @@ +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 LoggingPipelineStackPipelineCC71B91B.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.yo-ga/cdk-playground" -> "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 Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"Source.yo-ga/cdk-playground"; +"BEGIN Source" -> "Source.yo-ga/cdk-playground"; +"Source.yo-ga/cdk-playground" -> "END Source"; +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json new file mode 100644 index 0000000000000..3a7c06ce92a8d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -0,0 +1,32 @@ +{ + "version": "30.1.0", + "files": { + "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "source": { + "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24": { + "source": { + "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.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.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json new file mode 100644 index 0000000000000..70bad9ad5346e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "AwsApiCallCodeBuildbatchGetProjects": { + "Type": "Custom::DeployAssert@SdkCallCodeBuildbatchGetProjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "CodeBuild", + "api": "batchGetProjects", + "expected": "{\"$StringLike\":\"prefix\"}", + "actualPath": "projects.0.logsConfig.cloudWatchLogs.streamName", + "parameters": { + "names": [ + { + "Fn::ImportValue": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "projects.0.logsConfig.cloudWatchLogs.streamName" + ], + "salt": "1679844588674" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "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" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "codebuild:BatchGetProjects" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallCodeBuildbatchGetProjects": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallCodeBuildbatchGetProjects", + "assertion" + ] + } + } + }, + "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.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js new file mode 100644 index 0000000000000..58bcb1ef7f38e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js @@ -0,0 +1,1205 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} + +// ../assertions/lib/private/sparse-matrix.ts +var SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out new file mode 100644 index 0000000000000..b72fef144f05c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"30.1.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json new file mode 100644 index 0000000000000..a755dc3f6c3de --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "30.1.0", + "testCases": { + "PipelineLoggingTest/DefaultTest": { + "stacks": [ + "LoggingPipelineStack" + ], + "assertionStack": "PipelineLoggingTest/DefaultTest/DeployAssert", + "assertionStackName": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json new file mode 100644 index 0000000000000..18826d152a8df --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json @@ -0,0 +1,220 @@ +{ + "version": "30.1.0", + "artifacts": { + "LoggingPipelineStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LoggingPipelineStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LoggingPipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LoggingPipelineStack.template.json", + "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}/f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "LoggingPipelineStack.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": [ + "LoggingPipelineStack.assets" + ], + "metadata": { + "/LoggingPipelineStack/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupF5B46931" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketAEA9A052" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketPolicyF53CCC52" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleB27FAA37" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicy7BDC1ABB" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Pipeline9850B417" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRole226DB0CB" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ], + "/LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ], + "/LoggingPipelineStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LoggingPipelineStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "LoggingPipelineStack" + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "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}/254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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": [ + "LoggingPipelineStack", + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets" + ], + "metadata": { + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineLoggingTest/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.pipeline-synth-with-logging.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json new file mode 100644 index 0000000000000..a58aeb80e8960 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json @@ -0,0 +1,1341 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "LoggingPipelineStack": { + "id": "LoggingPipelineStack", + "path": "LoggingPipelineStack", + "children": { + "LogGroup": { + "id": "LogGroup", + "path": "LoggingPipelineStack/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "0.0.0" + } + }, + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline", + "children": { + "ArtifactsBucket": { + "id": "ArtifactsBucket", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms" + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "yo-ga_cdk-playground", + "outputArtifacts": [ + { + "name": "yo_ga_cdk_playground_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "ThirdParty", + "provider": "GitHub" + }, + "configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "runOrder": 1 + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Synth", + "inputArtifacts": [ + { + "name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + } + ], + "artifactStore": { + "type": "S3", + "location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + } + }, + "restartExecutionOnUpdate": true + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source", + "children": { + "yo-ga_cdk-playground": { + "id": "yo-ga_cdk-playground", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "Build": { + "id": "Build", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build", + "children": { + "Synth": { + "id": "Synth", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth", + "children": { + "CdkBuildProject": { + "id": "CdkBuildProject", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline", + "children": { + "SelfMutate": { + "id": "SelfMutate", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "version": "0.0.0" + } + }, + "CodeBuildActionRole": { + "id": "CodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole", + "children": { + "ImportCodeBuildActionRole": { + "id": "ImportCodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline", + "children": { + "SelfMutation": { + "id": "SelfMutation", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "encryptionKey": "alias/aws/s3" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/pipelines.CodePipeline", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "LoggingPipelineStack/Exports", + "children": { + "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": { + "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "LoggingPipelineStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "LoggingPipelineStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PipelineLoggingTest": { + "id": "PipelineLoggingTest", + "path": "PipelineLoggingTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PipelineLoggingTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert", + "children": { + "AwsApiCallCodeBuildbatchGetProjects": { + "id": "AwsApiCallCodeBuildbatchGetProjects", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts new file mode 100644 index 0000000000000..1d5a95fe7b964 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts @@ -0,0 +1,54 @@ +import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as cdk from 'aws-cdk-lib/core'; +import { Stack } from 'aws-cdk-lib/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as pipelines from 'aws-cdk-lib/pipelines'; + +/* + * Stack verification steps: + * * aws codebuild batch-get-projects --names : should return correct cloudwatchlog settings + */ +const app = new cdk.App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +const stack = new Stack(app, 'LoggingPipelineStack'); + +const logGroup = new logs.LogGroup(stack, 'LogGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { + synth: new pipelines.CodeBuildStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('yo-ga/cdk-playground', 'main', { + trigger: GitHubTrigger.NONE, + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + }, + }), +}); + +const testCase = new integ.IntegTest(app, 'PipelineLoggingTest', { + testCases: [stack], +}); + +pipeline.buildPipeline(); +testCase.assertions + .awsApiCall('CodeBuild', 'batchGetProjects', { + names: [pipeline.synthProject.projectName], + }) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.status', ExpectedResult.stringLikeRegexp('ENABLED')) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.logGroup', ExpectedResult.stringLikeRegexp(logGroup.logGroupName)) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.streamName', ExpectedResult.stringLikeRegexp('prefix')); + +app.synth(); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json new file mode 100644 index 0000000000000..4f135fb22795c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "29.0.0", + "files": { + "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d": { + "source": { + "path": "LoggingPipelineStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.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.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json new file mode 100644 index 0000000000000..69315b1657920 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -0,0 +1,852 @@ +{ + "Resources": { + "LogGroupF5B46931": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucketAEA9A052": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyF53CCC52": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "Roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "Pipeline9850B417": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "ThirdParty", + "Provider": "GitHub", + "Version": "1" + }, + "Configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "Name": "yo-ga_cdk-playground", + "OutputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "InputArtifacts": [ + { + "Name": "yo_ga_cdk_playground_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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "InputArtifacts": [ + { + "Name": "Synth_Output" + } + ], + "Name": "SelfMutate", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "UpdatePipeline" + } + ], + "ArtifactStore": { + "Location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "Type": "S3" + }, + "RestartExecutionOnUpdate": true + }, + "DependsOn": [ + "PipelineRoleDefaultPolicy7BDC1ABB", + "PipelineRoleB27FAA37" + ] + }, + "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:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "Roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "PipelineBuildSynthCdkBuildProject6BEFA8E6": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" + }, + "Status": "ENABLED", + "StreamName": "prefix" + } + } + } + }, + "PipelineCodeBuildActionRole226DB0CB": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "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:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "Roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "PipelineUpdatePipelineSelfMutationDAA41400": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "Description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "EncryptionKey": "alias/aws/s3", + "LogsConfig": { + "CloudWatchLogs": { + "GroupName": { + "Ref": "LogGroupF5B46931" + }, + "Status": "ENABLED", + "StreamName": "prefix" + } + } + } + } + }, + "Outputs": { + "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708": { + "Value": { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + "Export": { + "Name": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + } + }, + "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.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json new file mode 100644 index 0000000000000..b8c8f481e4bd0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -0,0 +1,32 @@ +{ + "version": "29.0.0", + "files": { + "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "source": { + "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e": { + "source": { + "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.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.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json new file mode 100644 index 0000000000000..6b245a667b3b9 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -0,0 +1,138 @@ +{ + "Resources": { + "AwsApiCallCodeBuildbatchGetProjects": { + "Type": "Custom::DeployAssert@SdkCallCodeBuildbatchGetProjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "CodeBuild", + "api": "batchGetProjects", + "expected": "{\"$StringLike\":\"prefix\"}", + "actualPath": "projects.0.logsConfig.cloudWatchLogs.streamName", + "parameters": { + "names": [ + { + "Fn::ImportValue": "LoggingPipelineStack:ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ] + }, + "flattenResponse": "true", + "outputPaths": [ + "projects.0.logsConfig.cloudWatchLogs.streamName" + ], + "salt": "1675558017986" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "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" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "codebuild:BatchGetProjects" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + } + }, + "Outputs": { + "AssertionResultsAwsApiCallCodeBuildbatchGetProjects": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallCodeBuildbatchGetProjects", + "assertion" + ] + } + } + }, + "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.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js new file mode 100644 index 0000000000000..58bcb1ef7f38e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js @@ -0,0 +1,1205 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} + +// ../assertions/lib/private/sparse-matrix.ts +var SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out new file mode 100644 index 0000000000000..d8b441d447f8a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"29.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json new file mode 100644 index 0000000000000..20686b59dcae4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "29.0.0", + "testCases": { + "PipelineLoggingTest/DefaultTest": { + "stacks": [ + "LoggingPipelineStack" + ], + "assertionStack": "PipelineLoggingTest/DefaultTest/DeployAssert", + "assertionStackName": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json new file mode 100644 index 0000000000000..356b02defdcda --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json @@ -0,0 +1,256 @@ +{ + "version": "29.0.0", + "artifacts": { + "LoggingPipelineStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "LoggingPipelineStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "LoggingPipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "LoggingPipelineStack.template.json", + "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}/d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "LoggingPipelineStack.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": [ + "LoggingPipelineStack.assets" + ], + "metadata": { + "/LoggingPipelineStack/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "LogGroupF5B46931" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketAEA9A052" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketPolicyF53CCC52" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleB27FAA37" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicy7BDC1ABB" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Pipeline9850B417" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C" + } + ], + "/LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRole226DB0CB" + } + ], + "/LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineCodeBuildActionRoleDefaultPolicy1D62A6FE" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E" + } + ], + "/LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineUpdatePipelineSelfMutationDAA41400" + } + ], + "/LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefPipelineBuildSynthCdkBuildProject6BEFA8E65A914708" + } + ], + "/LoggingPipelineStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/LoggingPipelineStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ], + "MyLogsBucket57652DD1": [ + { + "type": "aws:cdk:logicalId", + "data": "MyLogsBucket57652DD1", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepRole440B3F64": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRole440B3F64", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ], + "PipelineMyWavePostStepF4CC34B8": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineMyWavePostStepF4CC34B8", + "trace": [ + "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" + ] + } + ] + }, + "displayName": "LoggingPipelineStack" + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", + "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}/09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.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": [ + "LoggingPipelineStack", + "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets" + ], + "metadata": { + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallCodeBuildbatchGetProjects" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PipelineLoggingTest/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.pipeline-with-logging.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json new file mode 100644 index 0000000000000..78b51faf9db72 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json @@ -0,0 +1,1363 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "LoggingPipelineStack": { + "id": "LoggingPipelineStack", + "path": "LoggingPipelineStack", + "children": { + "LogGroup": { + "id": "LogGroup", + "path": "LoggingPipelineStack/LogGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/LogGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Logs::LogGroup", + "aws:cdk:cloudformation:props": { + "retentionInDays": 731 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-logs.LogGroup", + "version": "0.0.0" + } + }, + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline", + "children": { + "Pipeline": { + "id": "Pipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline", + "children": { + "ArtifactsBucket": { + "id": "ArtifactsBucket", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms" + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/ArtifactsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "PipelineArtifactsBucketAEA9A052" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.Bucket", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicy7BDC1ABB", + "roles": [ + { + "Ref": "PipelineRoleB27FAA37" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleB27FAA37", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "yo-ga_cdk-playground", + "outputArtifacts": [ + { + "name": "yo_ga_cdk_playground_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "ThirdParty", + "provider": "GitHub" + }, + "configuration": { + "Owner": "yo-ga", + "Repo": "cdk-playground", + "Branch": "main", + "OAuthToken": "{{resolve:secretsmanager:github-token:SecretString:::}}", + "PollForSourceChanges": false + }, + "runOrder": 1 + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Synth", + "inputArtifacts": [ + { + "name": "yo_ga_cdk_playground_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\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + }, + "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\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineCodeBuildActionRole226DB0CB", + "Arn" + ] + } + } + ] + } + ], + "artifactStore": { + "type": "S3", + "location": { + "Ref": "PipelineArtifactsBucketAEA9A052" + } + }, + "restartExecutionOnUpdate": true + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source", + "children": { + "yo-ga_cdk-playground": { + "id": "yo-ga_cdk-playground", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "Build": { + "id": "Build", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build", + "children": { + "Synth": { + "id": "Synth", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth", + "children": { + "CdkBuildProject": { + "id": "CdkBuildProject", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildSynthCdkBuildProjectRoleDefaultPolicyFB6C941C", + "roles": [ + { + "Ref": "PipelineBuildSynthCdkBuildProjectRole231EEA2A" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/Build/Synth", + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline", + "children": { + "SelfMutate": { + "id": "SelfMutate", + "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "version": "0.0.0" + } + }, + "CodeBuildActionRole": { + "id": "CodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole", + "children": { + "ImportCodeBuildActionRole": { + "id": "ImportCodeBuildActionRole", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Condition": { + "Bool": { + "aws:ViaAWSService": "codepipeline.amazonaws.com" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "UpdatePipeline": { + "id": "UpdatePipeline", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline", + "children": { + "SelfMutation": { + "id": "SelfMutation", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation", + "children": { + "Role": { + "id": "Role", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/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/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "LogGroupF5B46931", + "Arn" + ] + } + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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:", + { + "Ref": "AWS::Partition" + }, + ":codebuild:", + { + "Ref": "AWS::Region" + }, + ":", + { + "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::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucketAEA9A052", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineUpdatePipelineSelfMutationRoleDefaultPolicyA225DA4E", + "roles": [ + { + "Ref": "PipelineUpdatePipelineSelfMutationRole57E559E8" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:5.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@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + }, + "cache": { + "type": "NO_CACHE" + }, + "description": "Pipeline step LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutate", + "encryptionKey": "alias/aws/s3", + "logsConfig": { + "cloudWatchLogs": { + "status": "ENABLED", + "groupName": { + "Ref": "LogGroupF5B46931" + }, + "streamName": "prefix" + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/pipelines.CodePipeline", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "LoggingPipelineStack/Exports", + "children": { + "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}": { + "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "LoggingPipelineStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "LoggingPipelineStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PipelineLoggingTest": { + "id": "PipelineLoggingTest", + "path": "PipelineLoggingTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PipelineLoggingTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert", + "children": { + "AwsApiCallCodeBuildbatchGetProjects": { + "id": "AwsApiCallCodeBuildbatchGetProjects", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default", + "children": { + "Default": { + "id": "Default", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PipelineLoggingTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts new file mode 100644 index 0000000000000..376b87e7e4c43 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts @@ -0,0 +1,56 @@ +import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; +import * as logs from 'aws-cdk-lib/aws-logs'; +import * as cdk from 'aws-cdk-lib/core'; +import { Stack } from 'aws-cdk-lib/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as pipelines from 'aws-cdk-lib/pipelines'; + +/* + * Stack verification steps: + * * aws codebuild batch-get-projects --names : should return correct cloudwatchlog settings + */ +const app = new cdk.App({ + context: { + '@aws-cdk/core:newStyleStackSynthesis': '1', + }, +}); +const stack = new Stack(app, 'LoggingPipelineStack'); + +const logGroup = new logs.LogGroup(stack, 'LogGroup', { + removalPolicy: cdk.RemovalPolicy.DESTROY, +}); + +const pipeline = new pipelines.CodePipeline(stack, 'Pipeline', { + codeBuildDefaults: { + cloudWatchLogging: { + logGroup: logGroup, + prefix: 'prefix', + }, + }, + synth: new pipelines.CodeBuildStep('Synth', { + input: pipelines.CodePipelineSource.gitHub('yo-ga/cdk-playground', 'main', { + trigger: GitHubTrigger.NONE, + }), + commands: [ + 'npm ci', + 'npm run build', + 'npx cdk synth', + ], + }), +}); + +const testCase = new integ.IntegTest(app, 'PipelineLoggingTest', { + testCases: [stack], +}); + +pipeline.buildPipeline(); +testCase.assertions + .awsApiCall('CodeBuild', 'batchGetProjects', { + names: [pipeline.synthProject.projectName], + }) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.status', ExpectedResult.stringLikeRegexp('ENABLED')) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.logGroup', ExpectedResult.stringLikeRegexp(logGroup.logGroupName)) + .assertAtPath('projects.0.logsConfig.cloudWatchLogs.streamName', ExpectedResult.stringLikeRegexp('prefix')); + +app.synth(); From 67e6021781980ba99f066e2e659034142d03f5c9 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 5 Apr 2023 20:35:23 +0800 Subject: [PATCH 19/22] use alpha --- .../test/pipelines/test/integ.pipeline-synth-with-logging.ts | 4 ++-- .../test/pipelines/test/integ.pipeline-with-logging.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts index 1d5a95fe7b964..a6eaab525dc10 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts @@ -2,8 +2,8 @@ import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib/core'; import { Stack } from 'aws-cdk-lib/core'; -import * as integ from '@aws-cdk/integ-tests'; -import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { ExpectedResult } from '@aws-cdk/integ-tests-alpha'; import * as pipelines from 'aws-cdk-lib/pipelines'; /* diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts index 376b87e7e4c43..11c610fc20700 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts @@ -2,8 +2,8 @@ import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib/core'; import { Stack } from 'aws-cdk-lib/core'; -import * as integ from '@aws-cdk/integ-tests'; -import { ExpectedResult } from '@aws-cdk/integ-tests'; +import * as integ from '@aws-cdk/integ-tests-alpha'; +import { ExpectedResult } from '@aws-cdk/integ-tests-alpha'; import * as pipelines from 'aws-cdk-lib/pipelines'; /* From 42663edea7a40a1809eba5637efa2b701ffe98b0 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 5 Apr 2023 21:28:02 +0800 Subject: [PATCH 20/22] fix import --- .../test/pipelines/test/integ.pipeline-synth-with-logging.ts | 2 +- .../test/pipelines/test/integ.pipeline-with-logging.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts index a6eaab525dc10..bdfa30e2517e1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.ts @@ -1,10 +1,10 @@ -import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib/core'; import { Stack } from 'aws-cdk-lib/core'; import * as integ from '@aws-cdk/integ-tests-alpha'; import { ExpectedResult } from '@aws-cdk/integ-tests-alpha'; import * as pipelines from 'aws-cdk-lib/pipelines'; +import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions'; /* * Stack verification steps: diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts index 11c610fc20700..a08351e8a30e2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.ts @@ -1,10 +1,10 @@ -import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions/lib'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib/core'; import { Stack } from 'aws-cdk-lib/core'; import * as integ from '@aws-cdk/integ-tests-alpha'; import { ExpectedResult } from '@aws-cdk/integ-tests-alpha'; import * as pipelines from 'aws-cdk-lib/pipelines'; +import { GitHubTrigger } from 'aws-cdk-lib/aws-codepipeline-actions'; /* * Stack verification steps: From cc1bce383cfaa7349fd3f1add1dbb99d4fec7d9b Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Thu, 6 Apr 2023 07:30:23 +0800 Subject: [PATCH 21/22] update: integ test --- .../LoggingPipelineStack.assets.json | 6 +- .../LoggingPipelineStack.template.json | 10 +- ...efaultTestDeployAssert13FCCE41.assets.json | 12 +- ...aultTestDeployAssert13FCCE41.template.json | 4 +- .../index.js | 1205 --------------- .../index.js | 1295 +++++++++++++++++ .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 6 +- .../tree.json | 136 +- .../LoggingPipelineStack.assets.json | 6 +- .../LoggingPipelineStack.template.json | 10 +- .../LoggingPipelineStackPipelineCC71B91B.dot | 24 + ...efaultTestDeployAssert13FCCE41.assets.json | 12 +- ...aultTestDeployAssert13FCCE41.template.json | 4 +- .../index.js | 1205 --------------- .../index.js | 1295 +++++++++++++++++ .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 42 +- .../tree.json | 136 +- 21 files changed, 2792 insertions(+), 2624 deletions(-) delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json index 0ca113a71c59b..16c0ab64db239 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -1,7 +1,7 @@ { - "version": "30.1.0", + "version": "31.0.0", "files": { - "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589": { + "dfc70c4ff9a8f0e9e6714db37d5863fe96ab9ba43e8a9252e22aeefa869ae198": { "source": { "path": "LoggingPipelineStack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.json", + "objectKey": "dfc70c4ff9a8f0e9e6714db37d5863fe96ab9ba43e8a9252e22aeefa869ae198.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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json index 4abd26d34611a..f9f5cd619ba8b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -207,7 +207,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"09deb76d97fe89f2ccd364ad1eedc7ebc7c010be6bf79da68c34f358446cd134\"}]" }, "InputArtifacts": [ { @@ -244,7 +244,7 @@ "ProjectName": { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ce51e1ab714754e2ab37829a20a38519516c34704aa0e357ce6938dabff698d2\"}]" }, "InputArtifacts": [ { @@ -459,7 +459,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:5.0", + "Image": "aws/codebuild/standard:6.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -760,7 +760,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:5.0", + "Image": "aws/codebuild/standard:6.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -772,7 +772,7 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "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 LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", "Type": "CODEPIPELINE" }, "Cache": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json index 3a7c06ce92a8d..3f570c7fca701 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -1,20 +1,20 @@ { - "version": "30.1.0", + "version": "31.0.0", "files": { - "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3": { "source": { - "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "path": "asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "objectKey": "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24": { + "91e19e7dc2c20dcb7264c5c69eb0e35cd2c7eb10d0c140af8d4d5b55428d6d95": { "source": { "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.json", + "objectKey": "91e19e7dc2c20dcb7264c5c69eb0e35cd2c7eb10d0c140af8d4d5b55428d6d95.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/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json index 70bad9ad5346e..ab7a3cef34fb2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -24,7 +24,7 @@ "outputPaths": [ "projects.0.logsConfig.cloudWatchLogs.streamName" ], - "salt": "1679844588674" + "salt": "1680737118048" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -78,7 +78,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + "S3Key": "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.zip" }, "Timeout": 120, "Handler": "index.handler", diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js deleted file mode 100644 index 58bcb1ef7f38e..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js +++ /dev/null @@ -1,1205 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// lib/assertions/providers/lambda-handler/index.ts -var lambda_handler_exports = {}; -__export(lambda_handler_exports, { - handler: () => handler, - isComplete: () => isComplete, - onTimeout: () => onTimeout -}); -module.exports = __toCommonJS(lambda_handler_exports); - -// ../assertions/lib/matcher.ts -var Matcher = class { - /** - * Check whether the provided object is a subtype of the `IMatcher`. - */ - static isMatcher(x) { - return x && x instanceof Matcher; - } -}; -var MatchResult = class { - constructor(target) { - this.failuresHere = /* @__PURE__ */ new Map(); - this.captures = /* @__PURE__ */ new Map(); - this.finalized = false; - this.innerMatchFailures = /* @__PURE__ */ new Map(); - this._hasFailed = false; - this._failCount = 0; - this._cost = 0; - this.target = target; - } - /** - * DEPRECATED - * @deprecated use recordFailure() - */ - push(matcher, path, message) { - return this.recordFailure({ matcher, path, message }); - } - /** - * Record a new failure into this result at a specific path. - */ - recordFailure(failure) { - const failKey = failure.path.join("."); - let list = this.failuresHere.get(failKey); - if (!list) { - list = []; - this.failuresHere.set(failKey, list); - } - this._failCount += 1; - this._cost += failure.cost ?? 1; - list.push(failure); - this._hasFailed = true; - return this; - } - /** Whether the match is a success */ - get isSuccess() { - return !this._hasFailed; - } - /** Does the result contain any failures. If not, the result is a success */ - hasFailed() { - return this._hasFailed; - } - /** The number of failures */ - get failCount() { - return this._failCount; - } - /** The cost of the failures so far */ - get failCost() { - return this._cost; - } - /** - * Compose the results of a previous match as a subtree. - * @param id the id of the parent tree. - */ - compose(id, inner) { - if (inner.hasFailed()) { - this._hasFailed = true; - this._failCount += inner.failCount; - this._cost += inner._cost; - this.innerMatchFailures.set(id, inner); - } - inner.captures.forEach((vals, capture) => { - vals.forEach((value) => this.recordCapture({ capture, value })); - }); - return this; - } - /** - * Prepare the result to be analyzed. - * This API *must* be called prior to analyzing these results. - */ - finished() { - if (this.finalized) { - return this; - } - if (this.failCount === 0) { - this.captures.forEach((vals, cap) => cap._captured.push(...vals)); - } - this.finalized = true; - return this; - } - /** - * Render the failed match in a presentable way - * - * Prefer using `renderMismatch` over this method. It is left for backwards - * compatibility for test suites that expect it, but `renderMismatch()` will - * produce better output. - */ - toHumanStrings() { - const failures = new Array(); - debugger; - recurse(this, []); - return failures.map((r) => { - const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; - return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; - }); - function recurse(x, prefix) { - for (const fail of Array.from(x.failuresHere.values()).flat()) { - failures.push({ - matcher: fail.matcher, - message: fail.message, - path: [...prefix, ...fail.path] - }); - } - for (const [key, inner] of x.innerMatchFailures.entries()) { - recurse(inner, [...prefix, key]); - } - } - } - /** - * Do a deep render of the match result, showing the structure mismatches in context - */ - renderMismatch() { - if (!this.hasFailed()) { - return ""; - } - const parts = new Array(); - const indents = new Array(); - emitFailures(this, ""); - recurse(this); - return moveMarkersToFront(parts.join("").trimEnd()); - function emit(x) { - if (x === void 0) { - debugger; - } - parts.push(x.replace(/\n/g, ` -${indents.join("")}`)); - } - function emitFailures(r, path, scrapSet) { - for (const fail of r.failuresHere.get(path) ?? []) { - emit(`!! ${fail.message} -`); - } - scrapSet == null ? void 0 : scrapSet.delete(path); - } - function recurse(r) { - const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); - if (Array.isArray(r.target)) { - indents.push(" "); - emit("[\n"); - for (const [first, i] of enumFirst(range(r.target.length))) { - if (!first) { - emit(",\n"); - } - emitFailures(r, `${i}`, remainingFailures); - const innerMatcher = r.innerMatchFailures.get(`${i}`); - if (innerMatcher) { - emitFailures(innerMatcher, ""); - recurseComparingValues(innerMatcher, r.target[i]); - } else { - emit(renderAbridged(r.target[i])); - } - } - emitRemaining(); - indents.pop(); - emit("\n]"); - return; - } - if (r.target && typeof r.target === "object") { - indents.push(" "); - emit("{\n"); - const keys = Array.from(/* @__PURE__ */ new Set([ - ...Object.keys(r.target), - ...Array.from(remainingFailures) - ])).sort(); - for (const [first, key] of enumFirst(keys)) { - if (!first) { - emit(",\n"); - } - emitFailures(r, key, remainingFailures); - const innerMatcher = r.innerMatchFailures.get(key); - if (innerMatcher) { - emitFailures(innerMatcher, ""); - emit(`${jsonify(key)}: `); - recurseComparingValues(innerMatcher, r.target[key]); - } else { - emit(`${jsonify(key)}: `); - emit(renderAbridged(r.target[key])); - } - } - emitRemaining(); - indents.pop(); - emit("\n}"); - return; - } - emitRemaining(); - emit(jsonify(r.target)); - function emitRemaining() { - if (remainingFailures.size > 0) { - emit("\n"); - } - for (const key of remainingFailures) { - emitFailures(r, key); - } - } - } - function recurseComparingValues(inner, actualValue) { - if (inner.target === actualValue) { - return recurse(inner); - } - emit(renderAbridged(actualValue)); - emit(" <*> "); - recurse(inner); - } - function renderAbridged(x) { - if (Array.isArray(x)) { - switch (x.length) { - case 0: - return "[]"; - case 1: - return `[ ${renderAbridged(x[0])} ]`; - case 2: - if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { - return `[ ${x.map(renderAbridged).join(", ")} ]`; - } - return "[ ... ]"; - default: - return "[ ... ]"; - } - } - if (x && typeof x === "object") { - const keys = Object.keys(x); - switch (keys.length) { - case 0: - return "{}"; - case 1: - return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; - default: - return "{ ... }"; - } - } - return jsonify(x); - } - function jsonify(x) { - return JSON.stringify(x) ?? "undefined"; - } - function moveMarkersToFront(x) { - const re = /^(\s+)!!/gm; - return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); - } - } - /** - * Record a capture against in this match result. - */ - recordCapture(options) { - let values = this.captures.get(options.capture); - if (values === void 0) { - values = []; - } - values.push(options.value); - this.captures.set(options.capture, values); - } -}; -function* range(n) { - for (let i = 0; i < n; i++) { - yield i; - } -} -function* enumFirst(xs) { - let first = true; - for (const x of xs) { - yield [first, x]; - first = false; - } -} - -// ../assertions/lib/private/matchers/absent.ts -var AbsentMatch = class extends Matcher { - constructor(name) { - super(); - this.name = name; - } - test(actual) { - const result = new MatchResult(actual); - if (actual !== void 0) { - result.recordFailure({ - matcher: this, - path: [], - message: `Received ${actual}, but key should be absent` - }); - } - return result; - } -}; - -// ../assertions/lib/private/sorting.ts -function sortKeyComparator(keyFn) { - return (a, b) => { - const ak = keyFn(a); - const bk = keyFn(b); - for (let i = 0; i < ak.length && i < bk.length; i++) { - const av = ak[i]; - const bv = bk[i]; - let diff = 0; - if (typeof av === "number" && typeof bv === "number") { - diff = av - bv; - } else if (typeof av === "string" && typeof bv === "string") { - diff = av.localeCompare(bv); - } - if (diff !== 0) { - return diff; - } - } - return bk.length - ak.length; - }; -} - -// ../assertions/lib/private/sparse-matrix.ts -var SparseMatrix = class { - constructor() { - this.matrix = /* @__PURE__ */ new Map(); - } - get(row, col) { - var _a; - return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); - } - row(row) { - var _a; - return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); - } - set(row, col, value) { - let r = this.matrix.get(row); - if (!r) { - r = /* @__PURE__ */ new Map(); - this.matrix.set(row, r); - } - r.set(col, value); - } -}; - -// ../assertions/lib/private/type.ts -function getType(obj) { - return Array.isArray(obj) ? "array" : typeof obj; -} - -// ../assertions/lib/match.ts -var Match = class { - /** - * Use this matcher in the place of a field's value, if the field must not be present. - */ - static absent() { - return new AbsentMatch("absent"); - } - /** - * Matches the specified pattern with the array found in the same relative path of the target. - * The set of elements (or matchers) must be in the same order as would be found. - * @param pattern the pattern to match - */ - static arrayWith(pattern) { - return new ArrayMatch("arrayWith", pattern); - } - /** - * Matches the specified pattern with the array found in the same relative path of the target. - * The set of elements (or matchers) must match exactly and in order. - * @param pattern the pattern to match - */ - static arrayEquals(pattern) { - return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); - } - /** - * Deep exact matching of the specified pattern to the target. - * @param pattern the pattern to match - */ - static exact(pattern) { - return new LiteralMatch("exact", pattern, { partialObjects: false }); - } - /** - * Matches the specified pattern to an object found in the same relative path of the target. - * The keys and their values (or matchers) must be present in the target but the target can be a superset. - * @param pattern the pattern to match - */ - static objectLike(pattern) { - return new ObjectMatch("objectLike", pattern); - } - /** - * Matches the specified pattern to an object found in the same relative path of the target. - * The keys and their values (or matchers) must match exactly with the target. - * @param pattern the pattern to match - */ - static objectEquals(pattern) { - return new ObjectMatch("objectEquals", pattern, { partial: false }); - } - /** - * Matches any target which does NOT follow the specified pattern. - * @param pattern the pattern to NOT match - */ - static not(pattern) { - return new NotMatch("not", pattern); - } - /** - * Matches any string-encoded JSON and applies the specified pattern after parsing it. - * @param pattern the pattern to match after parsing the encoded JSON. - */ - static serializedJson(pattern) { - return new SerializedJson("serializedJson", pattern); - } - /** - * Matches any non-null value at the target. - */ - static anyValue() { - return new AnyMatch("anyValue"); - } - /** - * Matches targets according to a regular expression - */ - static stringLikeRegexp(pattern) { - return new StringLikeRegexpMatch("stringLikeRegexp", pattern); - } -}; -var LiteralMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.partialObjects = options.partialObjects ?? false; - if (Matcher.isMatcher(this.pattern)) { - throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); - } - } - test(actual) { - if (Array.isArray(this.pattern)) { - return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); - } - if (typeof this.pattern === "object") { - return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); - } - const result = new MatchResult(actual); - if (typeof this.pattern !== typeof actual) { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` - }); - return result; - } - if (actual !== this.pattern) { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected ${this.pattern} but received ${actual}` - }); - } - return result; - } -}; -var ArrayMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.subsequence = options.subsequence ?? true; - this.partialObjects = options.partialObjects ?? false; - } - test(actual) { - if (!Array.isArray(actual)) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected type array but received ${getType(actual)}` - }); - } - return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); - } - testFullArray(actual) { - const result = new MatchResult(actual); - let i = 0; - for (; i < this.pattern.length && i < actual.length; i++) { - const patternElement = this.pattern[i]; - const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); - const innerResult = matcher.test(actual[i]); - result.compose(`${i}`, innerResult); - } - if (i < this.pattern.length) { - result.recordFailure({ - matcher: this, - message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, - path: [`${i}`] - }); - } - if (i < actual.length) { - result.recordFailure({ - matcher: this, - message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, - path: [`${i}`] - }); - } - return result; - } - testSubsequence(actual) { - const result = new MatchResult(actual); - let patternIdx = 0; - let actualIdx = 0; - const matches = new SparseMatrix(); - while (patternIdx < this.pattern.length && actualIdx < actual.length) { - const patternElement = this.pattern[patternIdx]; - const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); - const matcherName = matcher.name; - if (matcherName == "absent" || matcherName == "anyValue") { - throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); - } - const innerResult = matcher.test(actual[actualIdx]); - matches.set(patternIdx, actualIdx, innerResult); - actualIdx++; - if (innerResult.isSuccess) { - result.compose(`${actualIdx}`, innerResult); - patternIdx++; - } - } - if (patternIdx < this.pattern.length) { - for (let spi = 0; spi < patternIdx; spi++) { - const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); - if (!foundMatch) { - continue; - } - const [index] = foundMatch; - result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ - matcher: this, - message: `arrayWith pattern ${spi} matched here`, - path: [], - cost: 0 - // This is an informational message so it would be unfair to assign it cost - })); - } - const failedMatches = matches.row(patternIdx); - failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); - if (failedMatches.length > 0) { - const [index, innerResult] = failedMatches[0]; - result.recordFailure({ - matcher: this, - message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, - path: [`${index}`], - cost: 0 - // Informational message - }); - result.compose(`${index}`, innerResult); - } else { - result.recordFailure({ - matcher: this, - message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, - path: [`${actual.length}`] - }); - } - } - return result; - } -}; -var ObjectMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.partial = options.partial ?? true; - } - test(actual) { - if (typeof actual !== "object" || Array.isArray(actual)) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected type object but received ${getType(actual)}` - }); - } - const result = new MatchResult(actual); - if (!this.partial) { - for (const a of Object.keys(actual)) { - if (!(a in this.pattern)) { - result.recordFailure({ - matcher: this, - path: [a], - message: `Unexpected key ${a}` - }); - } - } - } - for (const [patternKey, patternVal] of Object.entries(this.pattern)) { - if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { - result.recordFailure({ - matcher: this, - path: [patternKey], - message: `Missing key '${patternKey}'` - }); - continue; - } - const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); - const inner = matcher.test(actual[patternKey]); - result.compose(patternKey, inner); - } - return result; - } -}; -var SerializedJson = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - if (getType(actual) !== "string") { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected JSON as a string but found ${getType(actual)}` - }); - } - let parsed; - try { - parsed = JSON.parse(actual); - } catch (err) { - if (err instanceof SyntaxError) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Invalid JSON string: ${actual}` - }); - } else { - throw err; - } - } - const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); - const innerResult = matcher.test(parsed); - if (innerResult.hasFailed()) { - innerResult.recordFailure({ - matcher: this, - path: [], - message: "Encoded JSON value does not match" - }); - } - return innerResult; - } -}; -var NotMatch = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); - const innerResult = matcher.test(actual); - const result = new MatchResult(actual); - if (innerResult.failCount === 0) { - result.recordFailure({ - matcher: this, - path: [], - message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` - }); - } - return result; - } -}; -var AnyMatch = class extends Matcher { - constructor(name) { - super(); - this.name = name; - } - test(actual) { - const result = new MatchResult(actual); - if (actual == null) { - result.recordFailure({ - matcher: this, - path: [], - message: "Expected a value but found none" - }); - } - return result; - } -}; -var StringLikeRegexpMatch = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - const result = new MatchResult(actual); - const regex = new RegExp(this.pattern, "gm"); - if (typeof actual !== "string") { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected a string, but got '${typeof actual}'` - }); - } - if (!regex.test(actual)) { - result.recordFailure({ - matcher: this, - path: [], - message: `String '${actual}' did not match pattern '${this.pattern}'` - }); - } - return result; - } -}; - -// lib/assertions/providers/lambda-handler/base.ts -var https = __toESM(require("https")); -var url = __toESM(require("url")); -var AWS = __toESM(require("aws-sdk")); -var CustomResourceHandler = class { - constructor(event, context) { - this.event = event; - this.context = context; - this.timedOut = false; - this.timeout = setTimeout(async () => { - await this.respond({ - status: "FAILED", - reason: "Lambda Function Timeout", - data: this.context.logStreamName - }); - this.timedOut = true; - }, context.getRemainingTimeInMillis() - 1200); - this.event = event; - this.physicalResourceId = extractPhysicalResourceId(event); - } - /** - * Handles executing the custom resource event. If `stateMachineArn` is present - * in the props then trigger the waiter statemachine - */ - async handle() { - try { - if ("stateMachineArn" in this.event.ResourceProperties) { - const req = { - stateMachineArn: this.event.ResourceProperties.stateMachineArn, - name: this.event.RequestId, - input: JSON.stringify(this.event) - }; - await this.startExecution(req); - return; - } else { - const response = await this.processEvent(this.event.ResourceProperties); - return response; - } - } catch (e) { - console.log(e); - throw e; - } finally { - clearTimeout(this.timeout); - } - } - /** - * Handle async requests from the waiter state machine - */ - async handleIsComplete() { - try { - const result = await this.processEvent(this.event.ResourceProperties); - return result; - } catch (e) { - console.log(e); - return; - } finally { - clearTimeout(this.timeout); - } - } - /** - * Start a step function state machine which will wait for the request - * to be successful. - */ - async startExecution(req) { - try { - const sfn = new AWS.StepFunctions(); - await sfn.startExecution(req).promise(); - } finally { - clearTimeout(this.timeout); - } - } - respond(response) { - if (this.timedOut) { - return; - } - const cfResponse = { - Status: response.status, - Reason: response.reason, - PhysicalResourceId: this.physicalResourceId, - StackId: this.event.StackId, - RequestId: this.event.RequestId, - LogicalResourceId: this.event.LogicalResourceId, - NoEcho: false, - Data: response.data - }; - const responseBody = JSON.stringify(cfResponse); - console.log("Responding to CloudFormation", responseBody); - const parsedUrl = url.parse(this.event.ResponseURL); - const requestOptions = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: "PUT", - headers: { "content-type": "", "content-length": responseBody.length } - }; - return new Promise((resolve, reject) => { - try { - const request2 = https.request(requestOptions, resolve); - request2.on("error", reject); - request2.write(responseBody); - request2.end(); - } catch (e) { - reject(e); - } finally { - clearTimeout(this.timeout); - } - }); - } -}; -function extractPhysicalResourceId(event) { - switch (event.RequestType) { - case "Create": - return event.LogicalResourceId; - case "Update": - case "Delete": - return event.PhysicalResourceId; - } -} - -// lib/assertions/providers/lambda-handler/assertion.ts -var AssertionHandler = class extends CustomResourceHandler { - async processEvent(request2) { - let actual = decodeCall(request2.actual); - const expected = decodeCall(request2.expected); - let result; - const matcher = new MatchCreator(expected).getMatcher(); - console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); - const matchResult = matcher.test(actual); - matchResult.finished(); - if (matchResult.hasFailed()) { - result = { - failed: true, - assertion: JSON.stringify({ - status: "fail", - message: matchResult.renderMismatch() - }) - }; - if (request2.failDeployment) { - throw new Error(result.assertion); - } - } else { - result = { - assertion: JSON.stringify({ - status: "success" - }) - }; - } - return result; - } -}; -var MatchCreator = class { - constructor(obj) { - this.parsedObj = { - matcher: obj - }; - } - /** - * Return a Matcher that can be tested against the actual results. - * This will convert the encoded matchers into their corresponding - * assertions matcher. - * - * For example: - * - * ExpectedResult.objectLike({ - * Messages: [{ - * Body: Match.objectLike({ - * Elements: Match.arrayWith([{ Asdf: 3 }]), - * Payload: Match.serializedJson({ key: 'value' }), - * }), - * }], - * }); - * - * Will be encoded as: - * { - * $ObjectLike: { - * Messages: [{ - * Body: { - * $ObjectLike: { - * Elements: { - * $ArrayWith: [{ Asdf: 3 }], - * }, - * Payload: { - * $SerializedJson: { key: 'value' } - * } - * }, - * }, - * }], - * }, - * } - * - * Which can then be parsed by this function. For each key (recursively) - * the parser will check if the value has one of the encoded matchers as a key - * and if so, it will set the value as the Matcher. So, - * - * { - * Body: { - * $ObjectLike: { - * Elements: { - * $ArrayWith: [{ Asdf: 3 }], - * }, - * Payload: { - * $SerializedJson: { key: 'value' } - * } - * }, - * }, - * } - * - * Will be converted to - * { - * Body: Match.objectLike({ - * Elements: Match.arrayWith([{ Asdf: 3 }]), - * Payload: Match.serializedJson({ key: 'value' }), - * }), - * } - */ - getMatcher() { - try { - const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { - const nested = Object.keys(v)[0]; - switch (nested) { - case "$ArrayWith": - return Match.arrayWith(v[nested]); - case "$ObjectLike": - return Match.objectLike(v[nested]); - case "$StringLike": - return Match.stringLikeRegexp(v[nested]); - case "$SerializedJson": - return Match.serializedJson(v[nested]); - default: - return v; - } - }); - if (Matcher.isMatcher(final.matcher)) { - return final.matcher; - } - return Match.exact(final.matcher); - } catch { - return Match.exact(this.parsedObj.matcher); - } - } -}; -function decodeCall(call) { - if (!call) { - return void 0; - } - try { - const parsed = JSON.parse(call); - return parsed; - } catch (e) { - return call; - } -} - -// lib/assertions/providers/lambda-handler/utils.ts -function decode(object) { - return JSON.parse(JSON.stringify(object), (_k, v) => { - switch (v) { - case "TRUE:BOOLEAN": - return true; - case "FALSE:BOOLEAN": - return false; - default: - return v; - } - }); -} - -// lib/assertions/providers/lambda-handler/sdk.ts -function flatten(object) { - return Object.assign( - {}, - ...function _flatten(child, path = []) { - return [].concat(...Object.keys(child).map((key) => { - let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; - if (typeof childKey === "string") { - childKey = isJsonString(childKey); - } - return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; - })); - }(object) - ); -} -var AwsApiCallHandler = class extends CustomResourceHandler { - async processEvent(request2) { - const AWS2 = require("aws-sdk"); - console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); - if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { - throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); - } - const service = new AWS2[request2.service](); - const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); - console.log(`SDK response received ${JSON.stringify(response)}`); - delete response.ResponseMetadata; - const respond = { - apiCallResponse: response - }; - const flatData = { - ...flatten(respond) - }; - let resp = respond; - if (request2.outputPaths) { - resp = filterKeys(flatData, request2.outputPaths); - } else if (request2.flattenResponse === "true") { - resp = flatData; - } - console.log(`Returning result ${JSON.stringify(resp)}`); - return resp; - } -}; -function filterKeys(object, searchStrings) { - return Object.entries(object).reduce((filteredObject, [key, value]) => { - for (const searchString of searchStrings) { - if (key.startsWith(`apiCallResponse.${searchString}`)) { - filteredObject[key] = value; - } - } - return filteredObject; - }, {}); -} -function isJsonString(value) { - try { - return JSON.parse(value); - } catch { - return value; - } -} - -// lib/assertions/providers/lambda-handler/types.ts -var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; -var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; - -// lib/assertions/providers/lambda-handler/index.ts -async function handler(event, context) { - console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); - const provider = createResourceHandler(event, context); - try { - if (event.RequestType === "Delete") { - await provider.respond({ - status: "SUCCESS", - reason: "OK" - }); - return; - } - const result = await provider.handle(); - if ("stateMachineArn" in event.ResourceProperties) { - console.info('Found "stateMachineArn", waiter statemachine started'); - return; - } else if ("expected" in event.ResourceProperties) { - console.info('Found "expected", testing assertions'); - const actualPath = event.ResourceProperties.actualPath; - const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; - const assertion = new AssertionHandler({ - ...event, - ResourceProperties: { - ServiceToken: event.ServiceToken, - actual, - expected: event.ResourceProperties.expected - } - }, context); - try { - const assertionResult = await assertion.handle(); - await provider.respond({ - status: "SUCCESS", - reason: "OK", - // return both the result of the API call _and_ the assertion results - data: { - ...assertionResult, - ...result - } - }); - return; - } catch (e) { - await provider.respond({ - status: "FAILED", - reason: e.message ?? "Internal Error" - }); - return; - } - } - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: result - }); - } catch (e) { - await provider.respond({ - status: "FAILED", - reason: e.message ?? "Internal Error" - }); - return; - } - return; -} -async function onTimeout(timeoutEvent) { - const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); - const provider = createResourceHandler(isCompleteRequest, standardContext); - await provider.respond({ - status: "FAILED", - reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) - }); -} -async function isComplete(event, context) { - console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); - const provider = createResourceHandler(event, context); - try { - const result = await provider.handleIsComplete(); - const actualPath = event.ResourceProperties.actualPath; - if (result) { - const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; - if ("expected" in event.ResourceProperties) { - const assertion = new AssertionHandler({ - ...event, - ResourceProperties: { - ServiceToken: event.ServiceToken, - actual, - expected: event.ResourceProperties.expected - } - }, context); - const assertionResult = await assertion.handleIsComplete(); - if (!(assertionResult == null ? void 0 : assertionResult.failed)) { - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: { - ...assertionResult, - ...result - } - }); - return; - } else { - console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); - throw new Error(JSON.stringify(event)); - } - } - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: result - }); - } else { - console.log("No result"); - throw new Error(JSON.stringify(event)); - } - return; - } catch (e) { - console.log(e); - throw new Error(JSON.stringify(event)); - } -} -function createResourceHandler(event, context) { - if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { - return new AwsApiCallHandler(event, context); - } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { - return new AssertionHandler(event, context); - } else { - throw new Error(`Unsupported resource type "${event.ResourceType}`); - } -} -var standardContext = { - getRemainingTimeInMillis: () => 9e4 -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - handler, - isComplete, - onTimeout -}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js new file mode 100644 index 0000000000000..a54f75c9c3747 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js @@ -0,0 +1,1295 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// ../../aws-cdk-lib/assertions/lib/matcher.ts +var matcher_exports = {}; +__export(matcher_exports, { + MatchResult: () => MatchResult, + Matcher: () => Matcher +}); +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} +var Matcher, MatchResult; +var init_matcher = __esm({ + "../../aws-cdk-lib/assertions/lib/matcher.ts"() { + "use strict"; + Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } + }; + MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/matchers/absent.ts +var AbsentMatch; +var init_absent = __esm({ + "../../aws-cdk-lib/assertions/lib/private/matchers/absent.ts"() { + "use strict"; + init_matcher(); + AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} +var init_sorting = __esm({ + "../../aws-cdk-lib/assertions/lib/private/sorting.ts"() { + "use strict"; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/sparse-matrix.ts +var SparseMatrix; +var init_sparse_matrix = __esm({ + "../../aws-cdk-lib/assertions/lib/private/sparse-matrix.ts"() { + "use strict"; + SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} +var init_type = __esm({ + "../../aws-cdk-lib/assertions/lib/private/type.ts"() { + "use strict"; + } +}); + +// ../../aws-cdk-lib/assertions/lib/match.ts +var match_exports = {}; +__export(match_exports, { + Match: () => Match +}); +var Match, LiteralMatch, ArrayMatch, ObjectMatch, SerializedJson, NotMatch, AnyMatch, StringLikeRegexpMatch; +var init_match = __esm({ + "../../aws-cdk-lib/assertions/lib/match.ts"() { + "use strict"; + init_matcher(); + init_absent(); + init_sorting(); + init_sparse_matrix(); + init_type(); + Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } + }; + LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } + }; + ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } + }; + ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } + }; + SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } + }; + NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } + }; + AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } + }; + StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/helpers-internal/index.js +var require_helpers_internal = __commonJS({ + "../../aws-cdk-lib/assertions/lib/helpers-internal/index.js"(exports) { + "use strict"; + var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) { + if (k2 === void 0) + k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m[k]; + } }; + } + Object.defineProperty(o, k2, desc); + } : function(o, m, k, k2) { + if (k2 === void 0) + k2 = k; + o[k2] = m[k]; + }); + var __exportStar = exports && exports.__exportStar || function(m, exports2) { + for (var p in m) + if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) + __createBinding(exports2, m, p); + }; + Object.defineProperty(exports, "__esModule", { value: true }); + __exportStar((init_match(), __toCommonJS(match_exports)), exports); + __exportStar((init_matcher(), __toCommonJS(matcher_exports)), exports); + } +}); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// lib/assertions/providers/lambda-handler/assertion.ts +var import_helpers_internal = __toESM(require_helpers_internal()); + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { + "content-type": "", + "content-length": Buffer.byteLength(responseBody, "utf8") + } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return import_helpers_internal.Match.arrayWith(v[nested]); + case "$ObjectLike": + return import_helpers_internal.Match.objectLike(v[nested]); + case "$StringLike": + return import_helpers_internal.Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return import_helpers_internal.Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (import_helpers_internal.Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return import_helpers_internal.Match.exact(final.matcher); + } catch { + return import_helpers_internal.Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out index b72fef144f05c..7925065efbcc4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"30.1.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json index a755dc3f6c3de..b72a2ee3c195f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "testCases": { "PipelineLoggingTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json index 18826d152a8df..defbd9528f9d4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "30.1.0", + "version": "31.0.0", "artifacts": { "LoggingPipelineStack.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,7 @@ "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}/f68e0a7a763e7df66be60ce11401ef6682fb14da625923ce92cc13934c5cc589.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/dfc70c4ff9a8f0e9e6714db37d5863fe96ab9ba43e8a9252e22aeefa869ae198.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -154,7 +154,7 @@ "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}/254d01d650c5ed91b6980efe129f306244f8798f972278d7371cc42f21865d24.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/91e19e7dc2c20dcb7264c5c69eb0e35cd2c7eb10d0c140af8d4d5b55428d6d95.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json index a58aeb80e8960..e21db7f1da4a9 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-synth-with-logging.js.snapshot/tree.json @@ -22,13 +22,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "fqn": "aws-cdk-lib.aws_logs.CfnLogGroup", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-logs.LogGroup", + "fqn": "aws-cdk-lib.aws_logs.LogGroup", "version": "0.0.0" } }, @@ -68,7 +68,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucket", + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", "version": "0.0.0" } }, @@ -127,19 +127,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.Bucket", + "fqn": "aws-cdk-lib.aws_s3.Bucket", "version": "0.0.0" } }, @@ -151,7 +151,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -176,7 +176,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -251,19 +251,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -332,7 +332,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"09deb76d97fe89f2ccd364ad1eedc7ebc7c010be6bf79da68c34f358446cd134\"}]" }, "runOrder": 1, "roleArn": { @@ -364,7 +364,7 @@ "ProjectName": { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ce51e1ab714754e2ab37829a20a38519516c34704aa0e357ce6938dabff698d2\"}]" }, "runOrder": 1, "roleArn": { @@ -387,7 +387,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "fqn": "aws-cdk-lib.aws_codepipeline.CfnPipeline", "version": "0.0.0" } }, @@ -400,13 +400,13 @@ "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "Build": { @@ -429,7 +429,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -454,7 +454,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -623,19 +623,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -650,7 +650,7 @@ }, "environment": { "type": "LINUX_CONTAINER", - "image": "aws/codebuild/standard:5.0", + "image": "aws/codebuild/standard:6.0", "imagePullCredentialsType": "CODEBUILD", "privilegedMode": false, "computeType": "BUILD_GENERAL1_SMALL" @@ -682,26 +682,26 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "UpdatePipeline": { @@ -713,18 +713,18 @@ "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "fqn": "aws-cdk-lib.aws_codepipeline.Pipeline", "version": "0.0.0" } }, @@ -736,7 +736,7 @@ "id": "ImportCodeBuildActionRole", "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -781,7 +781,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -831,19 +831,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -863,7 +863,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -888,7 +888,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -1070,19 +1070,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -1097,7 +1097,7 @@ }, "environment": { "type": "LINUX_CONTAINER", - "image": "aws/codebuild/standard:5.0", + "image": "aws/codebuild/standard:6.0", "imagePullCredentialsType": "CODEBUILD", "privilegedMode": false, "computeType": "BUILD_GENERAL1_SMALL" @@ -1110,7 +1110,7 @@ }, "source": { "type": "CODEPIPELINE", - "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + "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 LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" }, "cache": { "type": "NO_CACHE" @@ -1120,25 +1120,25 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/pipelines.CodePipeline", + "fqn": "aws-cdk-lib.pipelines.CodePipeline", "version": "0.0.0" } }, @@ -1150,21 +1150,21 @@ "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", + "fqn": "aws-cdk-lib.CfnOutput", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "LoggingPipelineStack/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, @@ -1172,13 +1172,13 @@ "id": "CheckBootstrapVersion", "path": "LoggingPipelineStack/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" } }, @@ -1195,7 +1195,7 @@ "path": "PipelineLoggingTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "DeployAssert": { @@ -1215,12 +1215,12 @@ "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "fqn": "@aws-cdk/integ-tests-alpha.AssertionsProvider", "version": "0.0.0" } }, @@ -1232,13 +1232,13 @@ "id": "Default", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.CustomResource", + "fqn": "aws-cdk-lib.CustomResource", "version": "0.0.0" } }, @@ -1246,13 +1246,13 @@ "id": "AssertionResults", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", + "fqn": "aws-cdk-lib.CfnOutput", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "fqn": "@aws-cdk/integ-tests-alpha.AwsApiCall", "version": "0.0.0" } }, @@ -1264,7 +1264,7 @@ "id": "Staging", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", "constructInfo": { - "fqn": "@aws-cdk/core.AssetStaging", + "fqn": "aws-cdk-lib.AssetStaging", "version": "0.0.0" } }, @@ -1272,7 +1272,7 @@ "id": "Role", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } }, @@ -1280,21 +1280,21 @@ "id": "Handler", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, @@ -1302,25 +1302,25 @@ "id": "CheckBootstrapVersion", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/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" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTest", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", "version": "0.0.0" } }, @@ -1329,12 +1329,12 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "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/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json index 4f135fb22795c..86f8088581759 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.assets.json @@ -1,7 +1,7 @@ { - "version": "29.0.0", + "version": "31.0.0", "files": { - "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d": { + "4a35016ef98a88e56544daa6522d8130aa3d67e5a192b48740c3ad131e63903a": { "source": { "path": "LoggingPipelineStack.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.json", + "objectKey": "4a35016ef98a88e56544daa6522d8130aa3d67e5a192b48740c3ad131e63903a.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/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json index 69315b1657920..a87a6ed8a99d7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStack.template.json @@ -207,7 +207,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"09deb76d97fe89f2ccd364ad1eedc7ebc7c010be6bf79da68c34f358446cd134\"}]" }, "InputArtifacts": [ { @@ -244,7 +244,7 @@ "ProjectName": { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ce51e1ab714754e2ab37829a20a38519516c34704aa0e357ce6938dabff698d2\"}]" }, "InputArtifacts": [ { @@ -459,7 +459,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:5.0", + "Image": "aws/codebuild/standard:6.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -773,7 +773,7 @@ }, "Environment": { "ComputeType": "BUILD_GENERAL1_SMALL", - "Image": "aws/codebuild/standard:5.0", + "Image": "aws/codebuild/standard:6.0", "ImagePullCredentialsType": "CODEBUILD", "PrivilegedMode": false, "Type": "LINUX_CONTAINER" @@ -785,7 +785,7 @@ ] }, "Source": { - "BuildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", + "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 LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}", "Type": "CODEPIPELINE" }, "Cache": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot new file mode 100644 index 0000000000000..2500438a82d14 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/LoggingPipelineStackPipelineCC71B91B.dot @@ -0,0 +1,24 @@ +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 LoggingPipelineStackPipelineCC71B91B.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.yo-ga/cdk-playground" -> "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 Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"END Source" [shape="cds", style="filled", fillcolor="#b7deff"]; +"Source.yo-ga/cdk-playground"; +"BEGIN Source" -> "Source.yo-ga/cdk-playground"; +"Source.yo-ga/cdk-playground" -> "END Source"; +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json index b8c8f481e4bd0..9ee5ddfbf2151 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.assets.json @@ -1,20 +1,20 @@ { - "version": "29.0.0", + "version": "31.0.0", "files": { - "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4": { + "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3": { "source": { - "path": "asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle", + "path": "asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip", + "objectKey": "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e": { + "6f53cbd31cd9a3668892ac45658c0a89a94af7ab7db1c6b5b74e44d8cfde6b2b": { "source": { "path": "PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.json", + "objectKey": "6f53cbd31cd9a3668892ac45658c0a89a94af7ab7db1c6b5b74e44d8cfde6b2b.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/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json index 6b245a667b3b9..c41a5ef4ddb54 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/PipelineLoggingTestDefaultTestDeployAssert13FCCE41.template.json @@ -24,7 +24,7 @@ "outputPaths": [ "projects.0.logsConfig.cloudWatchLogs.streamName" ], - "salt": "1675558017986" + "salt": "1680736902141" }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" @@ -78,7 +78,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.zip" + "S3Key": "ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.zip" }, "Timeout": 120, "Handler": "index.handler", diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js deleted file mode 100644 index 58bcb1ef7f38e..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.73c20a669c041469f7fc3fc03d574b093b5b97e7c716f76c1e8117e6163e4dc4.bundle/index.js +++ /dev/null @@ -1,1205 +0,0 @@ -"use strict"; -var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// lib/assertions/providers/lambda-handler/index.ts -var lambda_handler_exports = {}; -__export(lambda_handler_exports, { - handler: () => handler, - isComplete: () => isComplete, - onTimeout: () => onTimeout -}); -module.exports = __toCommonJS(lambda_handler_exports); - -// ../assertions/lib/matcher.ts -var Matcher = class { - /** - * Check whether the provided object is a subtype of the `IMatcher`. - */ - static isMatcher(x) { - return x && x instanceof Matcher; - } -}; -var MatchResult = class { - constructor(target) { - this.failuresHere = /* @__PURE__ */ new Map(); - this.captures = /* @__PURE__ */ new Map(); - this.finalized = false; - this.innerMatchFailures = /* @__PURE__ */ new Map(); - this._hasFailed = false; - this._failCount = 0; - this._cost = 0; - this.target = target; - } - /** - * DEPRECATED - * @deprecated use recordFailure() - */ - push(matcher, path, message) { - return this.recordFailure({ matcher, path, message }); - } - /** - * Record a new failure into this result at a specific path. - */ - recordFailure(failure) { - const failKey = failure.path.join("."); - let list = this.failuresHere.get(failKey); - if (!list) { - list = []; - this.failuresHere.set(failKey, list); - } - this._failCount += 1; - this._cost += failure.cost ?? 1; - list.push(failure); - this._hasFailed = true; - return this; - } - /** Whether the match is a success */ - get isSuccess() { - return !this._hasFailed; - } - /** Does the result contain any failures. If not, the result is a success */ - hasFailed() { - return this._hasFailed; - } - /** The number of failures */ - get failCount() { - return this._failCount; - } - /** The cost of the failures so far */ - get failCost() { - return this._cost; - } - /** - * Compose the results of a previous match as a subtree. - * @param id the id of the parent tree. - */ - compose(id, inner) { - if (inner.hasFailed()) { - this._hasFailed = true; - this._failCount += inner.failCount; - this._cost += inner._cost; - this.innerMatchFailures.set(id, inner); - } - inner.captures.forEach((vals, capture) => { - vals.forEach((value) => this.recordCapture({ capture, value })); - }); - return this; - } - /** - * Prepare the result to be analyzed. - * This API *must* be called prior to analyzing these results. - */ - finished() { - if (this.finalized) { - return this; - } - if (this.failCount === 0) { - this.captures.forEach((vals, cap) => cap._captured.push(...vals)); - } - this.finalized = true; - return this; - } - /** - * Render the failed match in a presentable way - * - * Prefer using `renderMismatch` over this method. It is left for backwards - * compatibility for test suites that expect it, but `renderMismatch()` will - * produce better output. - */ - toHumanStrings() { - const failures = new Array(); - debugger; - recurse(this, []); - return failures.map((r) => { - const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; - return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; - }); - function recurse(x, prefix) { - for (const fail of Array.from(x.failuresHere.values()).flat()) { - failures.push({ - matcher: fail.matcher, - message: fail.message, - path: [...prefix, ...fail.path] - }); - } - for (const [key, inner] of x.innerMatchFailures.entries()) { - recurse(inner, [...prefix, key]); - } - } - } - /** - * Do a deep render of the match result, showing the structure mismatches in context - */ - renderMismatch() { - if (!this.hasFailed()) { - return ""; - } - const parts = new Array(); - const indents = new Array(); - emitFailures(this, ""); - recurse(this); - return moveMarkersToFront(parts.join("").trimEnd()); - function emit(x) { - if (x === void 0) { - debugger; - } - parts.push(x.replace(/\n/g, ` -${indents.join("")}`)); - } - function emitFailures(r, path, scrapSet) { - for (const fail of r.failuresHere.get(path) ?? []) { - emit(`!! ${fail.message} -`); - } - scrapSet == null ? void 0 : scrapSet.delete(path); - } - function recurse(r) { - const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); - if (Array.isArray(r.target)) { - indents.push(" "); - emit("[\n"); - for (const [first, i] of enumFirst(range(r.target.length))) { - if (!first) { - emit(",\n"); - } - emitFailures(r, `${i}`, remainingFailures); - const innerMatcher = r.innerMatchFailures.get(`${i}`); - if (innerMatcher) { - emitFailures(innerMatcher, ""); - recurseComparingValues(innerMatcher, r.target[i]); - } else { - emit(renderAbridged(r.target[i])); - } - } - emitRemaining(); - indents.pop(); - emit("\n]"); - return; - } - if (r.target && typeof r.target === "object") { - indents.push(" "); - emit("{\n"); - const keys = Array.from(/* @__PURE__ */ new Set([ - ...Object.keys(r.target), - ...Array.from(remainingFailures) - ])).sort(); - for (const [first, key] of enumFirst(keys)) { - if (!first) { - emit(",\n"); - } - emitFailures(r, key, remainingFailures); - const innerMatcher = r.innerMatchFailures.get(key); - if (innerMatcher) { - emitFailures(innerMatcher, ""); - emit(`${jsonify(key)}: `); - recurseComparingValues(innerMatcher, r.target[key]); - } else { - emit(`${jsonify(key)}: `); - emit(renderAbridged(r.target[key])); - } - } - emitRemaining(); - indents.pop(); - emit("\n}"); - return; - } - emitRemaining(); - emit(jsonify(r.target)); - function emitRemaining() { - if (remainingFailures.size > 0) { - emit("\n"); - } - for (const key of remainingFailures) { - emitFailures(r, key); - } - } - } - function recurseComparingValues(inner, actualValue) { - if (inner.target === actualValue) { - return recurse(inner); - } - emit(renderAbridged(actualValue)); - emit(" <*> "); - recurse(inner); - } - function renderAbridged(x) { - if (Array.isArray(x)) { - switch (x.length) { - case 0: - return "[]"; - case 1: - return `[ ${renderAbridged(x[0])} ]`; - case 2: - if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { - return `[ ${x.map(renderAbridged).join(", ")} ]`; - } - return "[ ... ]"; - default: - return "[ ... ]"; - } - } - if (x && typeof x === "object") { - const keys = Object.keys(x); - switch (keys.length) { - case 0: - return "{}"; - case 1: - return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; - default: - return "{ ... }"; - } - } - return jsonify(x); - } - function jsonify(x) { - return JSON.stringify(x) ?? "undefined"; - } - function moveMarkersToFront(x) { - const re = /^(\s+)!!/gm; - return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); - } - } - /** - * Record a capture against in this match result. - */ - recordCapture(options) { - let values = this.captures.get(options.capture); - if (values === void 0) { - values = []; - } - values.push(options.value); - this.captures.set(options.capture, values); - } -}; -function* range(n) { - for (let i = 0; i < n; i++) { - yield i; - } -} -function* enumFirst(xs) { - let first = true; - for (const x of xs) { - yield [first, x]; - first = false; - } -} - -// ../assertions/lib/private/matchers/absent.ts -var AbsentMatch = class extends Matcher { - constructor(name) { - super(); - this.name = name; - } - test(actual) { - const result = new MatchResult(actual); - if (actual !== void 0) { - result.recordFailure({ - matcher: this, - path: [], - message: `Received ${actual}, but key should be absent` - }); - } - return result; - } -}; - -// ../assertions/lib/private/sorting.ts -function sortKeyComparator(keyFn) { - return (a, b) => { - const ak = keyFn(a); - const bk = keyFn(b); - for (let i = 0; i < ak.length && i < bk.length; i++) { - const av = ak[i]; - const bv = bk[i]; - let diff = 0; - if (typeof av === "number" && typeof bv === "number") { - diff = av - bv; - } else if (typeof av === "string" && typeof bv === "string") { - diff = av.localeCompare(bv); - } - if (diff !== 0) { - return diff; - } - } - return bk.length - ak.length; - }; -} - -// ../assertions/lib/private/sparse-matrix.ts -var SparseMatrix = class { - constructor() { - this.matrix = /* @__PURE__ */ new Map(); - } - get(row, col) { - var _a; - return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); - } - row(row) { - var _a; - return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); - } - set(row, col, value) { - let r = this.matrix.get(row); - if (!r) { - r = /* @__PURE__ */ new Map(); - this.matrix.set(row, r); - } - r.set(col, value); - } -}; - -// ../assertions/lib/private/type.ts -function getType(obj) { - return Array.isArray(obj) ? "array" : typeof obj; -} - -// ../assertions/lib/match.ts -var Match = class { - /** - * Use this matcher in the place of a field's value, if the field must not be present. - */ - static absent() { - return new AbsentMatch("absent"); - } - /** - * Matches the specified pattern with the array found in the same relative path of the target. - * The set of elements (or matchers) must be in the same order as would be found. - * @param pattern the pattern to match - */ - static arrayWith(pattern) { - return new ArrayMatch("arrayWith", pattern); - } - /** - * Matches the specified pattern with the array found in the same relative path of the target. - * The set of elements (or matchers) must match exactly and in order. - * @param pattern the pattern to match - */ - static arrayEquals(pattern) { - return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); - } - /** - * Deep exact matching of the specified pattern to the target. - * @param pattern the pattern to match - */ - static exact(pattern) { - return new LiteralMatch("exact", pattern, { partialObjects: false }); - } - /** - * Matches the specified pattern to an object found in the same relative path of the target. - * The keys and their values (or matchers) must be present in the target but the target can be a superset. - * @param pattern the pattern to match - */ - static objectLike(pattern) { - return new ObjectMatch("objectLike", pattern); - } - /** - * Matches the specified pattern to an object found in the same relative path of the target. - * The keys and their values (or matchers) must match exactly with the target. - * @param pattern the pattern to match - */ - static objectEquals(pattern) { - return new ObjectMatch("objectEquals", pattern, { partial: false }); - } - /** - * Matches any target which does NOT follow the specified pattern. - * @param pattern the pattern to NOT match - */ - static not(pattern) { - return new NotMatch("not", pattern); - } - /** - * Matches any string-encoded JSON and applies the specified pattern after parsing it. - * @param pattern the pattern to match after parsing the encoded JSON. - */ - static serializedJson(pattern) { - return new SerializedJson("serializedJson", pattern); - } - /** - * Matches any non-null value at the target. - */ - static anyValue() { - return new AnyMatch("anyValue"); - } - /** - * Matches targets according to a regular expression - */ - static stringLikeRegexp(pattern) { - return new StringLikeRegexpMatch("stringLikeRegexp", pattern); - } -}; -var LiteralMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.partialObjects = options.partialObjects ?? false; - if (Matcher.isMatcher(this.pattern)) { - throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); - } - } - test(actual) { - if (Array.isArray(this.pattern)) { - return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); - } - if (typeof this.pattern === "object") { - return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); - } - const result = new MatchResult(actual); - if (typeof this.pattern !== typeof actual) { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` - }); - return result; - } - if (actual !== this.pattern) { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected ${this.pattern} but received ${actual}` - }); - } - return result; - } -}; -var ArrayMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.subsequence = options.subsequence ?? true; - this.partialObjects = options.partialObjects ?? false; - } - test(actual) { - if (!Array.isArray(actual)) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected type array but received ${getType(actual)}` - }); - } - return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); - } - testFullArray(actual) { - const result = new MatchResult(actual); - let i = 0; - for (; i < this.pattern.length && i < actual.length; i++) { - const patternElement = this.pattern[i]; - const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); - const innerResult = matcher.test(actual[i]); - result.compose(`${i}`, innerResult); - } - if (i < this.pattern.length) { - result.recordFailure({ - matcher: this, - message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, - path: [`${i}`] - }); - } - if (i < actual.length) { - result.recordFailure({ - matcher: this, - message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, - path: [`${i}`] - }); - } - return result; - } - testSubsequence(actual) { - const result = new MatchResult(actual); - let patternIdx = 0; - let actualIdx = 0; - const matches = new SparseMatrix(); - while (patternIdx < this.pattern.length && actualIdx < actual.length) { - const patternElement = this.pattern[patternIdx]; - const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); - const matcherName = matcher.name; - if (matcherName == "absent" || matcherName == "anyValue") { - throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); - } - const innerResult = matcher.test(actual[actualIdx]); - matches.set(patternIdx, actualIdx, innerResult); - actualIdx++; - if (innerResult.isSuccess) { - result.compose(`${actualIdx}`, innerResult); - patternIdx++; - } - } - if (patternIdx < this.pattern.length) { - for (let spi = 0; spi < patternIdx; spi++) { - const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); - if (!foundMatch) { - continue; - } - const [index] = foundMatch; - result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ - matcher: this, - message: `arrayWith pattern ${spi} matched here`, - path: [], - cost: 0 - // This is an informational message so it would be unfair to assign it cost - })); - } - const failedMatches = matches.row(patternIdx); - failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); - if (failedMatches.length > 0) { - const [index, innerResult] = failedMatches[0]; - result.recordFailure({ - matcher: this, - message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, - path: [`${index}`], - cost: 0 - // Informational message - }); - result.compose(`${index}`, innerResult); - } else { - result.recordFailure({ - matcher: this, - message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, - path: [`${actual.length}`] - }); - } - } - return result; - } -}; -var ObjectMatch = class extends Matcher { - constructor(name, pattern, options = {}) { - super(); - this.name = name; - this.pattern = pattern; - this.partial = options.partial ?? true; - } - test(actual) { - if (typeof actual !== "object" || Array.isArray(actual)) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected type object but received ${getType(actual)}` - }); - } - const result = new MatchResult(actual); - if (!this.partial) { - for (const a of Object.keys(actual)) { - if (!(a in this.pattern)) { - result.recordFailure({ - matcher: this, - path: [a], - message: `Unexpected key ${a}` - }); - } - } - } - for (const [patternKey, patternVal] of Object.entries(this.pattern)) { - if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { - result.recordFailure({ - matcher: this, - path: [patternKey], - message: `Missing key '${patternKey}'` - }); - continue; - } - const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); - const inner = matcher.test(actual[patternKey]); - result.compose(patternKey, inner); - } - return result; - } -}; -var SerializedJson = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - if (getType(actual) !== "string") { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Expected JSON as a string but found ${getType(actual)}` - }); - } - let parsed; - try { - parsed = JSON.parse(actual); - } catch (err) { - if (err instanceof SyntaxError) { - return new MatchResult(actual).recordFailure({ - matcher: this, - path: [], - message: `Invalid JSON string: ${actual}` - }); - } else { - throw err; - } - } - const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); - const innerResult = matcher.test(parsed); - if (innerResult.hasFailed()) { - innerResult.recordFailure({ - matcher: this, - path: [], - message: "Encoded JSON value does not match" - }); - } - return innerResult; - } -}; -var NotMatch = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); - const innerResult = matcher.test(actual); - const result = new MatchResult(actual); - if (innerResult.failCount === 0) { - result.recordFailure({ - matcher: this, - path: [], - message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` - }); - } - return result; - } -}; -var AnyMatch = class extends Matcher { - constructor(name) { - super(); - this.name = name; - } - test(actual) { - const result = new MatchResult(actual); - if (actual == null) { - result.recordFailure({ - matcher: this, - path: [], - message: "Expected a value but found none" - }); - } - return result; - } -}; -var StringLikeRegexpMatch = class extends Matcher { - constructor(name, pattern) { - super(); - this.name = name; - this.pattern = pattern; - } - test(actual) { - const result = new MatchResult(actual); - const regex = new RegExp(this.pattern, "gm"); - if (typeof actual !== "string") { - result.recordFailure({ - matcher: this, - path: [], - message: `Expected a string, but got '${typeof actual}'` - }); - } - if (!regex.test(actual)) { - result.recordFailure({ - matcher: this, - path: [], - message: `String '${actual}' did not match pattern '${this.pattern}'` - }); - } - return result; - } -}; - -// lib/assertions/providers/lambda-handler/base.ts -var https = __toESM(require("https")); -var url = __toESM(require("url")); -var AWS = __toESM(require("aws-sdk")); -var CustomResourceHandler = class { - constructor(event, context) { - this.event = event; - this.context = context; - this.timedOut = false; - this.timeout = setTimeout(async () => { - await this.respond({ - status: "FAILED", - reason: "Lambda Function Timeout", - data: this.context.logStreamName - }); - this.timedOut = true; - }, context.getRemainingTimeInMillis() - 1200); - this.event = event; - this.physicalResourceId = extractPhysicalResourceId(event); - } - /** - * Handles executing the custom resource event. If `stateMachineArn` is present - * in the props then trigger the waiter statemachine - */ - async handle() { - try { - if ("stateMachineArn" in this.event.ResourceProperties) { - const req = { - stateMachineArn: this.event.ResourceProperties.stateMachineArn, - name: this.event.RequestId, - input: JSON.stringify(this.event) - }; - await this.startExecution(req); - return; - } else { - const response = await this.processEvent(this.event.ResourceProperties); - return response; - } - } catch (e) { - console.log(e); - throw e; - } finally { - clearTimeout(this.timeout); - } - } - /** - * Handle async requests from the waiter state machine - */ - async handleIsComplete() { - try { - const result = await this.processEvent(this.event.ResourceProperties); - return result; - } catch (e) { - console.log(e); - return; - } finally { - clearTimeout(this.timeout); - } - } - /** - * Start a step function state machine which will wait for the request - * to be successful. - */ - async startExecution(req) { - try { - const sfn = new AWS.StepFunctions(); - await sfn.startExecution(req).promise(); - } finally { - clearTimeout(this.timeout); - } - } - respond(response) { - if (this.timedOut) { - return; - } - const cfResponse = { - Status: response.status, - Reason: response.reason, - PhysicalResourceId: this.physicalResourceId, - StackId: this.event.StackId, - RequestId: this.event.RequestId, - LogicalResourceId: this.event.LogicalResourceId, - NoEcho: false, - Data: response.data - }; - const responseBody = JSON.stringify(cfResponse); - console.log("Responding to CloudFormation", responseBody); - const parsedUrl = url.parse(this.event.ResponseURL); - const requestOptions = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: "PUT", - headers: { "content-type": "", "content-length": responseBody.length } - }; - return new Promise((resolve, reject) => { - try { - const request2 = https.request(requestOptions, resolve); - request2.on("error", reject); - request2.write(responseBody); - request2.end(); - } catch (e) { - reject(e); - } finally { - clearTimeout(this.timeout); - } - }); - } -}; -function extractPhysicalResourceId(event) { - switch (event.RequestType) { - case "Create": - return event.LogicalResourceId; - case "Update": - case "Delete": - return event.PhysicalResourceId; - } -} - -// lib/assertions/providers/lambda-handler/assertion.ts -var AssertionHandler = class extends CustomResourceHandler { - async processEvent(request2) { - let actual = decodeCall(request2.actual); - const expected = decodeCall(request2.expected); - let result; - const matcher = new MatchCreator(expected).getMatcher(); - console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); - const matchResult = matcher.test(actual); - matchResult.finished(); - if (matchResult.hasFailed()) { - result = { - failed: true, - assertion: JSON.stringify({ - status: "fail", - message: matchResult.renderMismatch() - }) - }; - if (request2.failDeployment) { - throw new Error(result.assertion); - } - } else { - result = { - assertion: JSON.stringify({ - status: "success" - }) - }; - } - return result; - } -}; -var MatchCreator = class { - constructor(obj) { - this.parsedObj = { - matcher: obj - }; - } - /** - * Return a Matcher that can be tested against the actual results. - * This will convert the encoded matchers into their corresponding - * assertions matcher. - * - * For example: - * - * ExpectedResult.objectLike({ - * Messages: [{ - * Body: Match.objectLike({ - * Elements: Match.arrayWith([{ Asdf: 3 }]), - * Payload: Match.serializedJson({ key: 'value' }), - * }), - * }], - * }); - * - * Will be encoded as: - * { - * $ObjectLike: { - * Messages: [{ - * Body: { - * $ObjectLike: { - * Elements: { - * $ArrayWith: [{ Asdf: 3 }], - * }, - * Payload: { - * $SerializedJson: { key: 'value' } - * } - * }, - * }, - * }], - * }, - * } - * - * Which can then be parsed by this function. For each key (recursively) - * the parser will check if the value has one of the encoded matchers as a key - * and if so, it will set the value as the Matcher. So, - * - * { - * Body: { - * $ObjectLike: { - * Elements: { - * $ArrayWith: [{ Asdf: 3 }], - * }, - * Payload: { - * $SerializedJson: { key: 'value' } - * } - * }, - * }, - * } - * - * Will be converted to - * { - * Body: Match.objectLike({ - * Elements: Match.arrayWith([{ Asdf: 3 }]), - * Payload: Match.serializedJson({ key: 'value' }), - * }), - * } - */ - getMatcher() { - try { - const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { - const nested = Object.keys(v)[0]; - switch (nested) { - case "$ArrayWith": - return Match.arrayWith(v[nested]); - case "$ObjectLike": - return Match.objectLike(v[nested]); - case "$StringLike": - return Match.stringLikeRegexp(v[nested]); - case "$SerializedJson": - return Match.serializedJson(v[nested]); - default: - return v; - } - }); - if (Matcher.isMatcher(final.matcher)) { - return final.matcher; - } - return Match.exact(final.matcher); - } catch { - return Match.exact(this.parsedObj.matcher); - } - } -}; -function decodeCall(call) { - if (!call) { - return void 0; - } - try { - const parsed = JSON.parse(call); - return parsed; - } catch (e) { - return call; - } -} - -// lib/assertions/providers/lambda-handler/utils.ts -function decode(object) { - return JSON.parse(JSON.stringify(object), (_k, v) => { - switch (v) { - case "TRUE:BOOLEAN": - return true; - case "FALSE:BOOLEAN": - return false; - default: - return v; - } - }); -} - -// lib/assertions/providers/lambda-handler/sdk.ts -function flatten(object) { - return Object.assign( - {}, - ...function _flatten(child, path = []) { - return [].concat(...Object.keys(child).map((key) => { - let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; - if (typeof childKey === "string") { - childKey = isJsonString(childKey); - } - return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; - })); - }(object) - ); -} -var AwsApiCallHandler = class extends CustomResourceHandler { - async processEvent(request2) { - const AWS2 = require("aws-sdk"); - console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); - if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { - throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); - } - const service = new AWS2[request2.service](); - const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); - console.log(`SDK response received ${JSON.stringify(response)}`); - delete response.ResponseMetadata; - const respond = { - apiCallResponse: response - }; - const flatData = { - ...flatten(respond) - }; - let resp = respond; - if (request2.outputPaths) { - resp = filterKeys(flatData, request2.outputPaths); - } else if (request2.flattenResponse === "true") { - resp = flatData; - } - console.log(`Returning result ${JSON.stringify(resp)}`); - return resp; - } -}; -function filterKeys(object, searchStrings) { - return Object.entries(object).reduce((filteredObject, [key, value]) => { - for (const searchString of searchStrings) { - if (key.startsWith(`apiCallResponse.${searchString}`)) { - filteredObject[key] = value; - } - } - return filteredObject; - }, {}); -} -function isJsonString(value) { - try { - return JSON.parse(value); - } catch { - return value; - } -} - -// lib/assertions/providers/lambda-handler/types.ts -var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; -var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; - -// lib/assertions/providers/lambda-handler/index.ts -async function handler(event, context) { - console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); - const provider = createResourceHandler(event, context); - try { - if (event.RequestType === "Delete") { - await provider.respond({ - status: "SUCCESS", - reason: "OK" - }); - return; - } - const result = await provider.handle(); - if ("stateMachineArn" in event.ResourceProperties) { - console.info('Found "stateMachineArn", waiter statemachine started'); - return; - } else if ("expected" in event.ResourceProperties) { - console.info('Found "expected", testing assertions'); - const actualPath = event.ResourceProperties.actualPath; - const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; - const assertion = new AssertionHandler({ - ...event, - ResourceProperties: { - ServiceToken: event.ServiceToken, - actual, - expected: event.ResourceProperties.expected - } - }, context); - try { - const assertionResult = await assertion.handle(); - await provider.respond({ - status: "SUCCESS", - reason: "OK", - // return both the result of the API call _and_ the assertion results - data: { - ...assertionResult, - ...result - } - }); - return; - } catch (e) { - await provider.respond({ - status: "FAILED", - reason: e.message ?? "Internal Error" - }); - return; - } - } - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: result - }); - } catch (e) { - await provider.respond({ - status: "FAILED", - reason: e.message ?? "Internal Error" - }); - return; - } - return; -} -async function onTimeout(timeoutEvent) { - const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); - const provider = createResourceHandler(isCompleteRequest, standardContext); - await provider.respond({ - status: "FAILED", - reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) - }); -} -async function isComplete(event, context) { - console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); - const provider = createResourceHandler(event, context); - try { - const result = await provider.handleIsComplete(); - const actualPath = event.ResourceProperties.actualPath; - if (result) { - const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; - if ("expected" in event.ResourceProperties) { - const assertion = new AssertionHandler({ - ...event, - ResourceProperties: { - ServiceToken: event.ServiceToken, - actual, - expected: event.ResourceProperties.expected - } - }, context); - const assertionResult = await assertion.handleIsComplete(); - if (!(assertionResult == null ? void 0 : assertionResult.failed)) { - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: { - ...assertionResult, - ...result - } - }); - return; - } else { - console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); - throw new Error(JSON.stringify(event)); - } - } - await provider.respond({ - status: "SUCCESS", - reason: "OK", - data: result - }); - } else { - console.log("No result"); - throw new Error(JSON.stringify(event)); - } - return; - } catch (e) { - console.log(e); - throw new Error(JSON.stringify(event)); - } -} -function createResourceHandler(event, context) { - if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { - return new AwsApiCallHandler(event, context); - } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { - return new AssertionHandler(event, context); - } else { - throw new Error(`Unsupported resource type "${event.ResourceType}`); - } -} -var standardContext = { - getRemainingTimeInMillis: () => 9e4 -}; -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - handler, - isComplete, - onTimeout -}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js new file mode 100644 index 0000000000000..a54f75c9c3747 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/asset.ae370e1010629b78f494346f49ceef3ab2875718f20e6c808114e6aa770c7bf3.bundle/index.js @@ -0,0 +1,1295 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// ../../aws-cdk-lib/assertions/lib/matcher.ts +var matcher_exports = {}; +__export(matcher_exports, { + MatchResult: () => MatchResult, + Matcher: () => Matcher +}); +function* range(n) { + for (let i = 0; i < n; i++) { + yield i; + } +} +function* enumFirst(xs) { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} +var Matcher, MatchResult; +var init_matcher = __esm({ + "../../aws-cdk-lib/assertions/lib/matcher.ts"() { + "use strict"; + Matcher = class { + /** + * Check whether the provided object is a subtype of the `IMatcher`. + */ + static isMatcher(x) { + return x && x instanceof Matcher; + } + }; + MatchResult = class { + constructor(target) { + this.failuresHere = /* @__PURE__ */ new Map(); + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.innerMatchFailures = /* @__PURE__ */ new Map(); + this._hasFailed = false; + this._failCount = 0; + this._cost = 0; + this.target = target; + } + /** + * DEPRECATED + * @deprecated use recordFailure() + */ + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + /** + * Record a new failure into this result at a specific path. + */ + recordFailure(failure) { + const failKey = failure.path.join("."); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; + return this; + } + /** Whether the match is a success */ + get isSuccess() { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ + hasFailed() { + return this._hasFailed; + } + /** The number of failures */ + get failCount() { + return this._failCount; + } + /** The cost of the failures so far */ + get failCost() { + return this._cost; + } + /** + * Compose the results of a previous match as a subtree. + * @param id the id of the parent tree. + */ + compose(id, inner) { + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + /** + * Prepare the result to be analyzed. + * This API *must* be called prior to analyzing these results. + */ + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + /** + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. + */ + toHumanStrings() { + const failures = new Array(); + debugger; + recurse(this, []); + return failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at /${r.path.join("/")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + function recurse(x, prefix) { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path] + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + renderMismatch() { + if (!this.hasFailed()) { + return ""; + } + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ""); + recurse(this); + return moveMarkersToFront(parts.join("").trimEnd()); + function emit(x) { + if (x === void 0) { + debugger; + } + parts.push(x.replace(/\n/g, ` +${indents.join("")}`)); + } + function emitFailures(r, path, scrapSet) { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message} +`); + } + scrapSet == null ? void 0 : scrapSet.delete(path); + } + function recurse(r) { + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter((x) => x !== "")); + if (Array.isArray(r.target)) { + indents.push(" "); + emit("[\n"); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { + emit(",\n"); + } + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + emitRemaining(); + indents.pop(); + emit("\n]"); + return; + } + if (r.target && typeof r.target === "object") { + indents.push(" "); + emit("{\n"); + const keys = Array.from(/* @__PURE__ */ new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures) + ])).sort(); + for (const [first, key] of enumFirst(keys)) { + if (!first) { + emit(",\n"); + } + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + emitFailures(innerMatcher, ""); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + emitRemaining(); + indents.pop(); + emit("\n}"); + return; + } + emitRemaining(); + emit(jsonify(r.target)); + function emitRemaining() { + if (remainingFailures.size > 0) { + emit("\n"); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + function recurseComparingValues(inner, actualValue) { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(" <*> "); + recurse(inner); + } + function renderAbridged(x) { + if (Array.isArray(x)) { + switch (x.length) { + case 0: + return "[]"; + case 1: + return `[ ${renderAbridged(x[0])} ]`; + case 2: + if (x.every((e) => ["number", "boolean", "string"].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(", ")} ]`; + } + return "[ ... ]"; + default: + return "[ ... ]"; + } + } + if (x && typeof x === "object") { + const keys = Object.keys(x); + switch (keys.length) { + case 0: + return "{}"; + case 1: + return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: + return "{ ... }"; + } + } + return jsonify(x); + } + function jsonify(x) { + return JSON.stringify(x) ?? "undefined"; + } + function moveMarkersToFront(x) { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces) => `!!${spaces.substring(0, spaces.length - 2)}`); + } + } + /** + * Record a capture against in this match result. + */ + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/matchers/absent.ts +var AbsentMatch; +var init_absent = __esm({ + "../../aws-cdk-lib/assertions/lib/private/matchers/absent.ts"() { + "use strict"; + init_matcher(); + AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/sorting.ts +function sortKeyComparator(keyFn) { + return (a, b) => { + const ak = keyFn(a); + const bk = keyFn(b); + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + let diff = 0; + if (typeof av === "number" && typeof bv === "number") { + diff = av - bv; + } else if (typeof av === "string" && typeof bv === "string") { + diff = av.localeCompare(bv); + } + if (diff !== 0) { + return diff; + } + } + return bk.length - ak.length; + }; +} +var init_sorting = __esm({ + "../../aws-cdk-lib/assertions/lib/private/sorting.ts"() { + "use strict"; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/sparse-matrix.ts +var SparseMatrix; +var init_sparse_matrix = __esm({ + "../../aws-cdk-lib/assertions/lib/private/sparse-matrix.ts"() { + "use strict"; + SparseMatrix = class { + constructor() { + this.matrix = /* @__PURE__ */ new Map(); + } + get(row, col) { + var _a; + return (_a = this.matrix.get(row)) == null ? void 0 : _a.get(col); + } + row(row) { + var _a; + return Array.from(((_a = this.matrix.get(row)) == null ? void 0 : _a.entries()) ?? []); + } + set(row, col, value) { + let r = this.matrix.get(row); + if (!r) { + r = /* @__PURE__ */ new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} +var init_type = __esm({ + "../../aws-cdk-lib/assertions/lib/private/type.ts"() { + "use strict"; + } +}); + +// ../../aws-cdk-lib/assertions/lib/match.ts +var match_exports = {}; +__export(match_exports, { + Match: () => Match +}); +var Match, LiteralMatch, ArrayMatch, ObjectMatch, SerializedJson, NotMatch, AnyMatch, StringLikeRegexpMatch; +var init_match = __esm({ + "../../aws-cdk-lib/assertions/lib/match.ts"() { + "use strict"; + init_matcher(); + init_absent(); + init_sorting(); + init_sparse_matrix(); + init_type(); + Match = class { + /** + * Use this matcher in the place of a field's value, if the field must not be present. + */ + static absent() { + return new AbsentMatch("absent"); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must be in the same order as would be found. + * @param pattern the pattern to match + */ + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + /** + * Matches the specified pattern with the array found in the same relative path of the target. + * The set of elements (or matchers) must match exactly and in order. + * @param pattern the pattern to match + */ + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + /** + * Deep exact matching of the specified pattern to the target. + * @param pattern the pattern to match + */ + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must be present in the target but the target can be a superset. + * @param pattern the pattern to match + */ + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + /** + * Matches the specified pattern to an object found in the same relative path of the target. + * The keys and their values (or matchers) must match exactly with the target. + * @param pattern the pattern to match + */ + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + /** + * Matches any target which does NOT follow the specified pattern. + * @param pattern the pattern to NOT match + */ + static not(pattern) { + return new NotMatch("not", pattern); + } + /** + * Matches any string-encoded JSON and applies the specified pattern after parsing it. + * @param pattern the pattern to match after parsing the encoded JSON. + */ + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + /** + * Matches any non-null value at the target. + */ + static anyValue() { + return new AnyMatch("anyValue"); + } + /** + * Matches targets according to a regular expression + */ + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } + }; + LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } + }; + ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + testFullArray(actual) { + const result = new MatchResult(actual); + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + if (i < this.pattern.length) { + result.recordFailure({ + matcher: this, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`] + }); + } + return result; + } + testSubsequence(actual) { + const result = new MatchResult(actual); + let patternIdx = 0; + let actualIdx = 0; + const matches = new SparseMatrix(); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (matcherName == "absent" || matcherName == "anyValue") { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); + patternIdx++; + } + } + if (patternIdx < this.pattern.length) { + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { + continue; + } + const [index] = foundMatch; + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0 + // This is an informational message so it would be unfair to assign it cost + })); + } + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0 + // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`] + }); + } + } + return result; + } + }; + ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [a], + message: `Unexpected key ${a}` + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [patternKey], + message: `Missing key '${patternKey}'` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(patternKey, inner); + } + return result; + } + }; + SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + if (getType(actual) !== "string") { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected JSON as a string but found ${getType(actual)}` + }); + } + let parsed; + try { + parsed = JSON.parse(actual); + } catch (err) { + if (err instanceof SyntaxError) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + } else { + throw err; + } + } + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(parsed); + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: "Encoded JSON value does not match" + }); + } + return innerResult; + } + }; + NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } + }; + AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } + }; + StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } + }; + } +}); + +// ../../aws-cdk-lib/assertions/lib/helpers-internal/index.js +var require_helpers_internal = __commonJS({ + "../../aws-cdk-lib/assertions/lib/helpers-internal/index.js"(exports) { + "use strict"; + var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) { + if (k2 === void 0) + k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m[k]; + } }; + } + Object.defineProperty(o, k2, desc); + } : function(o, m, k, k2) { + if (k2 === void 0) + k2 = k; + o[k2] = m[k]; + }); + var __exportStar = exports && exports.__exportStar || function(m, exports2) { + for (var p in m) + if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) + __createBinding(exports2, m, p); + }; + Object.defineProperty(exports, "__esModule", { value: true }); + __exportStar((init_match(), __toCommonJS(match_exports)), exports); + __exportStar((init_matcher(), __toCommonJS(matcher_exports)), exports); + } +}); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// lib/assertions/providers/lambda-handler/assertion.ts +var import_helpers_internal = __toESM(require_helpers_internal()); + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + /** + * Handles executing the custom resource event. If `stateMachineArn` is present + * in the props then trigger the waiter statemachine + */ + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Handle async requests from the waiter state machine + */ + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + /** + * Start a step function state machine which will wait for the request + * to be successful. + */ + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { + "content-type": "", + "content-length": Buffer.byteLength(responseBody, "utf8") + } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: matchResult.renderMismatch() + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + /** + * Return a Matcher that can be tested against the actual results. + * This will convert the encoded matchers into their corresponding + * assertions matcher. + * + * For example: + * + * ExpectedResult.objectLike({ + * Messages: [{ + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * }], + * }); + * + * Will be encoded as: + * { + * $ObjectLike: { + * Messages: [{ + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * }], + * }, + * } + * + * Which can then be parsed by this function. For each key (recursively) + * the parser will check if the value has one of the encoded matchers as a key + * and if so, it will set the value as the Matcher. So, + * + * { + * Body: { + * $ObjectLike: { + * Elements: { + * $ArrayWith: [{ Asdf: 3 }], + * }, + * Payload: { + * $SerializedJson: { key: 'value' } + * } + * }, + * }, + * } + * + * Will be converted to + * { + * Body: Match.objectLike({ + * Elements: Match.arrayWith([{ Asdf: 3 }]), + * Payload: Match.serializedJson({ key: 'value' }), + * }), + * } + */ + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return import_helpers_internal.Match.arrayWith(v[nested]); + case "$ObjectLike": + return import_helpers_internal.Match.objectLike(v[nested]); + case "$StringLike": + return import_helpers_internal.Match.stringLikeRegexp(v[nested]); + case "$SerializedJson": + return import_helpers_internal.Match.serializedJson(v[nested]); + default: + return v; + } + }); + if (import_helpers_internal.Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return import_helpers_internal.Match.exact(final.matcher); + } catch { + return import_helpers_internal.Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + // return both the result of the API call _and_ the assertion results + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out index d8b441d447f8a..7925065efbcc4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"29.0.0"} \ No newline at end of file +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json index 20686b59dcae4..b72a2ee3c195f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "29.0.0", + "version": "31.0.0", "testCases": { "PipelineLoggingTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json index 356b02defdcda..8f3166a2ca22a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "29.0.0", + "version": "31.0.0", "artifacts": { "LoggingPipelineStack.assets": { "type": "cdk:asset-manifest", @@ -17,7 +17,7 @@ "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}/d99681b07ca842e41d76f0e1de1c36e98184be62476be52ea702af467851166d.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/4a35016ef98a88e56544daa6522d8130aa3d67e5a192b48740c3ad131e63903a.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -134,42 +134,6 @@ "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } - ], - "MyLogsBucket57652DD1": [ - { - "type": "aws:cdk:logicalId", - "data": "MyLogsBucket57652DD1", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } - ], - "PipelineMyWavePostStepRole440B3F64": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepRole440B3F64", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } - ], - "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepRoleDefaultPolicyF4712C0D", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } - ], - "PipelineMyWavePostStepF4CC34B8": [ - { - "type": "aws:cdk:logicalId", - "data": "PipelineMyWavePostStepF4CC34B8", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_DESTROY" - ] - } ] }, "displayName": "LoggingPipelineStack" @@ -190,7 +154,7 @@ "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}/09f29f7ebe8b7593140814d393b86b9778dbd156558bd366262767e00c1a712e.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/6f53cbd31cd9a3668892ac45658c0a89a94af7ab7db1c6b5b74e44d8cfde6b2b.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json index 78b51faf9db72..8341537533ecf 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/pipelines/test/integ.pipeline-with-logging.js.snapshot/tree.json @@ -22,13 +22,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-logs.CfnLogGroup", + "fqn": "aws-cdk-lib.aws_logs.CfnLogGroup", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-logs.LogGroup", + "fqn": "aws-cdk-lib.aws_logs.LogGroup", "version": "0.0.0" } }, @@ -68,7 +68,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucket", + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", "version": "0.0.0" } }, @@ -127,19 +127,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-s3.Bucket", + "fqn": "aws-cdk-lib.aws_s3.Bucket", "version": "0.0.0" } }, @@ -151,7 +151,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/Pipeline/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -176,7 +176,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -251,19 +251,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -332,7 +332,7 @@ "ProjectName": { "Ref": "PipelineBuildSynthCdkBuildProject6BEFA8E6" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"00ebacfb32b1bde8d3638577308e7b7144dfa3b0a58a83bc6ff38a3b1f26951c\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"09deb76d97fe89f2ccd364ad1eedc7ebc7c010be6bf79da68c34f358446cd134\"}]" }, "runOrder": 1, "roleArn": { @@ -364,7 +364,7 @@ "ProjectName": { "Ref": "PipelineUpdatePipelineSelfMutationDAA41400" }, - "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"603e15edc6ebf967876f6d9f657d4874914c3150061f4f9d87f4b92f13082e29\"}]" + "EnvironmentVariables": "[{\"name\":\"_PROJECT_CONFIG_HASH\",\"type\":\"PLAINTEXT\",\"value\":\"ce51e1ab714754e2ab37829a20a38519516c34704aa0e357ce6938dabff698d2\"}]" }, "runOrder": 1, "roleArn": { @@ -387,7 +387,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "fqn": "aws-cdk-lib.aws_codepipeline.CfnPipeline", "version": "0.0.0" } }, @@ -400,13 +400,13 @@ "path": "LoggingPipelineStack/Pipeline/Pipeline/Source/yo-ga_cdk-playground", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "Build": { @@ -429,7 +429,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/Pipeline/Build/Synth/CdkBuildProject/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -454,7 +454,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -623,19 +623,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -650,7 +650,7 @@ }, "environment": { "type": "LINUX_CONTAINER", - "image": "aws/codebuild/standard:5.0", + "image": "aws/codebuild/standard:6.0", "imagePullCredentialsType": "CODEBUILD", "privilegedMode": false, "computeType": "BUILD_GENERAL1_SMALL" @@ -682,26 +682,26 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "UpdatePipeline": { @@ -713,18 +713,18 @@ "path": "LoggingPipelineStack/Pipeline/Pipeline/UpdatePipeline/SelfMutate", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "fqn": "aws-cdk-lib.aws_codepipeline.Pipeline", "version": "0.0.0" } }, @@ -736,7 +736,7 @@ "id": "ImportCodeBuildActionRole", "path": "LoggingPipelineStack/Pipeline/CodeBuildActionRole/ImportCodeBuildActionRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -781,7 +781,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -831,19 +831,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -863,7 +863,7 @@ "id": "ImportRole", "path": "LoggingPipelineStack/Pipeline/UpdatePipeline/SelfMutation/Role/ImportRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -888,7 +888,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -1083,19 +1083,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -1110,7 +1110,7 @@ }, "environment": { "type": "LINUX_CONTAINER", - "image": "aws/codebuild/standard:5.0", + "image": "aws/codebuild/standard:6.0", "imagePullCredentialsType": "CODEBUILD", "privilegedMode": false, "computeType": "BUILD_GENERAL1_SMALL" @@ -1123,7 +1123,7 @@ }, "source": { "type": "CODEPIPELINE", - "buildSpec": "{\n \"version\": \"0.2\",\n \"phases\": {\n \"install\": {\n \"commands\": [\n \"npm install -g aws-cdk@1\"\n ]\n },\n \"build\": {\n \"commands\": [\n \"cdk -a . deploy LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" + "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 LoggingPipelineStack --require-approval=never --verbose\"\n ]\n }\n }\n}" }, "cache": { "type": "NO_CACHE" @@ -1142,25 +1142,25 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "fqn": "aws-cdk-lib.aws_codebuild.CfnProject", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "fqn": "aws-cdk-lib.aws_codebuild.PipelineProject", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/pipelines.CodePipeline", + "fqn": "aws-cdk-lib.pipelines.CodePipeline", "version": "0.0.0" } }, @@ -1172,21 +1172,21 @@ "id": "Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", "path": "LoggingPipelineStack/Exports/Output{\"Ref\":\"PipelineBuildSynthCdkBuildProject6BEFA8E6\"}", "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", + "fqn": "aws-cdk-lib.CfnOutput", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "LoggingPipelineStack/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, @@ -1194,13 +1194,13 @@ "id": "CheckBootstrapVersion", "path": "LoggingPipelineStack/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" } }, @@ -1217,7 +1217,7 @@ "path": "PipelineLoggingTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "DeployAssert": { @@ -1237,12 +1237,12 @@ "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/SdkProvider/AssertionsProvider", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "fqn": "@aws-cdk/integ-tests-alpha.AssertionsProvider", "version": "0.0.0" } }, @@ -1254,13 +1254,13 @@ "id": "Default", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/Default/Default", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.CustomResource", + "fqn": "aws-cdk-lib.CustomResource", "version": "0.0.0" } }, @@ -1268,13 +1268,13 @@ "id": "AssertionResults", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/AwsApiCallCodeBuildbatchGetProjects/AssertionResults", "constructInfo": { - "fqn": "@aws-cdk/core.CfnOutput", + "fqn": "aws-cdk-lib.CfnOutput", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "fqn": "@aws-cdk/integ-tests-alpha.AwsApiCall", "version": "0.0.0" } }, @@ -1286,7 +1286,7 @@ "id": "Staging", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", "constructInfo": { - "fqn": "@aws-cdk/core.AssetStaging", + "fqn": "aws-cdk-lib.AssetStaging", "version": "0.0.0" } }, @@ -1294,7 +1294,7 @@ "id": "Role", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } }, @@ -1302,21 +1302,21 @@ "id": "Handler", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", "constructInfo": { - "fqn": "@aws-cdk/core.CfnResource", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } }, "BootstrapVersion": { "id": "BootstrapVersion", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/BootstrapVersion", "constructInfo": { - "fqn": "@aws-cdk/core.CfnParameter", + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, @@ -1324,25 +1324,25 @@ "id": "CheckBootstrapVersion", "path": "PipelineLoggingTest/DefaultTest/DeployAssert/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" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/integ-tests.IntegTest", + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", "version": "0.0.0" } }, @@ -1351,12 +1351,12 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.216" + "version": "10.1.270" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.App", + "fqn": "aws-cdk-lib.App", "version": "0.0.0" } } From 244159e864f60909ae87f39e480c32a5cd2101b0 Mon Sep 17 00:00:00 2001 From: Yoga Yu Date: Wed, 12 Apr 2023 08:33:25 +0800 Subject: [PATCH 22/22] fix: resource import --- .../aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts index d1802a74bf085..ad97e8ccfc801 100644 --- a/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts +++ b/packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline.ts @@ -426,7 +426,7 @@ export class S3LoggingOptions extends CodeBuildLoggingBase { * @param encrypted S3 object encrypted or not * @returns CodeBuild S3 logging settings */ - static enable(bucket: IBucket, prefix?: string, encrypted?: boolean): S3LoggingOptions { + static enable(bucket: s3.IBucket, prefix?: string, encrypted?: boolean): S3LoggingOptions { return new S3LoggingOptions(true, { bucket, prefix, encrypted }); } @@ -441,7 +441,7 @@ export class S3LoggingOptions extends CodeBuildLoggingBase { /** * The S3 Bucket to send logs to */ - readonly bucket?: IBucket; + readonly bucket?: s3.IBucket; /** * Encrypt the S3 build log output