diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts index 884ada9221ddc..85feb51c001e5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codecommit/source-action.ts @@ -171,6 +171,7 @@ export class CodeCommitSourceAction extends Action { eventRole: this.props.eventRole, }), branches: [this.branch], + crossStackScope: stage.pipeline as unknown as Construct, }); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts index dea699e3bea37..092759e6b1c29 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/s3/source-action.ts @@ -118,6 +118,7 @@ export class S3SourceAction extends Action { this.props.bucket.onCloudTrailWriteObject(id, { target: new targets.CodePipeline(stage.pipeline), paths: [this.props.bucketKey], + crossStackScope: stage.pipeline as unknown as Construct, }); } diff --git a/packages/@aws-cdk/aws-codepipeline-actions/package.json b/packages/@aws-cdk/aws-codepipeline-actions/package.json index c30b840c1c0fe..fefc33b7691ef 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/package.json +++ b/packages/@aws-cdk/aws-codepipeline-actions/package.json @@ -82,6 +82,7 @@ "@aws-cdk/aws-s3-assets": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/integ-runner": "0.0.0", + "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.5.2", diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts index 2ca60b9d5c49e..b317e522fb1e5 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codecommit/codecommit-source-action.test.ts @@ -33,8 +33,6 @@ describe('CodeCommit Source Action', () => { }); Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 1); - - }); test('cross-account CodeCommit Repository Source does not use target role in source stack', () => { @@ -118,8 +116,6 @@ describe('CodeCommit Source Action', () => { }, ], }); - - }); test('does not poll for source changes and uses Events for CodeCommitTrigger.EVENTS', () => { @@ -143,8 +139,6 @@ describe('CodeCommit Source Action', () => { }); Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 1); - - }); test('polls for source changes and does not use Events for CodeCommitTrigger.POLL', () => { @@ -168,8 +162,6 @@ describe('CodeCommit Source Action', () => { }); Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); - - }); test('does not poll for source changes and does not use Events for CodeCommitTrigger.NONE', () => { @@ -193,8 +185,6 @@ describe('CodeCommit Source Action', () => { }); Template.fromStack(stack).resourceCountIs('AWS::Events::Rule', 0); - - }); test('cannot be created with an empty branch', () => { @@ -211,8 +201,6 @@ describe('CodeCommit Source Action', () => { branch: '', }); }).toThrow(/'branch' parameter cannot be an empty string/); - - }); test('allows using the same repository multiple times with different branches when trigger=EVENTS', () => { @@ -253,8 +241,6 @@ describe('CodeCommit Source Action', () => { }, ], }); - - }); test('exposes variables for other actions to consume', () => { @@ -308,8 +294,6 @@ describe('CodeCommit Source Action', () => { }, ], }); - - }); test('allows using a Token for the branch name', () => { @@ -351,8 +335,6 @@ describe('CodeCommit Source Action', () => { }, }, }); - - }); test('allows to enable full clone', () => { @@ -456,8 +438,6 @@ describe('CodeCommit Source Action', () => { ]), }, }); - - }); test('uses the role when passed', () => { @@ -512,8 +492,6 @@ describe('CodeCommit Source Action', () => { }, ], }); - - }); test('grants explicit s3:PutObjectAcl permissions when the Actions is cross-account', () => { @@ -569,8 +547,49 @@ describe('CodeCommit Source Action', () => { }]), }, }); + }); + test('allows using a new Repository from another Stack as a source of the Pipeline, with Events', () => { + const app = new App(); + + const repoStack = new Stack(app, 'RepositoryStack'); + const repo = new codecommit.Repository(repoStack, 'Repository', { + repositoryName: 'my-repo', + }); + + const pipelineStack = new Stack(app, 'PipelineStack'); + const sourceOutput = new codepipeline.Artifact(); + new codepipeline.Pipeline(pipelineStack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ + new cpactions.CodeCommitSourceAction({ + actionName: 'Source', + repository: repo, + output: sourceOutput, + }), + ], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'Build', + project: codebuild.Project.fromProjectName(pipelineStack, 'Project', 'my-project'), + input: sourceOutput, + }), + ], + }, + ], + }); + // If the Event Rule was created in the repo's Stack, + // we would have a cycle + // (the repo's Stack would need the name of the CodePipeline to trigger through the Rule, + // while the pipeline's Stack would need the name of the Repository to use as a Source). + // By moving the Rule to pipeline's Stack, we get rid of the cycle. + Template.fromStack(pipelineStack).resourceCountIs('AWS::Events::Rule', 1); }); }); }); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/integ.source-bucket-events-cross-stack-same-env.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/integ.source-bucket-events-cross-stack-same-env.ts new file mode 100644 index 0000000000000..8d7ac75267597 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/integ.source-bucket-events-cross-stack-same-env.ts @@ -0,0 +1,47 @@ +/// !cdk-integ PipelineStack + +import * as codebuild from '@aws-cdk/aws-codebuild'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as s3 from '@aws-cdk/aws-s3'; +import { App, RemovalPolicy, Stack } from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import * as cpactions from '../../lib'; + +const app = new App(); +const bucketStack = new Stack(app, 'BucketStack'); +const bucket = new s3.Bucket(bucketStack, 'Bucket', { + removalPolicy: RemovalPolicy.DESTROY, +}); + +const pipelineStack = new Stack(app, 'PipelineStack'); +const sourceOutput = new codepipeline.Artifact(); +new codepipeline.Pipeline(pipelineStack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [ + new cpactions.S3SourceAction({ + actionName: 'Source', + bucket, + trigger: cpactions.S3Trigger.EVENTS, + bucketKey: 'file.zip', + output: sourceOutput, + }), + ], + }, + { + stageName: 'Build', + actions: [ + new cpactions.CodeBuildAction({ + actionName: 'Build', + project: new codebuild.PipelineProject(pipelineStack, 'Project'), + input: sourceOutput, + }), + ], + }, + ], +}); + +new integ.IntegTest(app, 'CodePipelineS3SourceTest', { + testCases: [pipelineStack], +}); diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/BucketStack.template.json b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/BucketStack.template.json new file mode 100644 index 0000000000000..eca13e273e16e --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/BucketStack.template.json @@ -0,0 +1,30 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "ExportsOutputRefBucket83908E7781C90AC0": { + "Value": { + "Ref": "Bucket83908E77" + }, + "Export": { + "Name": "BucketStack:ExportsOutputRefBucket83908E7781C90AC0" + } + }, + "ExportsOutputFnGetAttBucket83908E77Arn063C8555": { + "Value": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "Export": { + "Name": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/PipelineStack.template.json b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/PipelineStack.template.json new file mode 100644 index 0000000000000..bf00c5c4bf2ef --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/PipelineStack.template.json @@ -0,0 +1,854 @@ +{ + "Resources": { + "ProjectRole4CCB274E": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codebuild.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "ProjectRoleDefaultPolicy7F29461B": { + "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": "ProjectC78D97AD" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "ProjectC78D97AD" + } + ] + ] + } + ] + }, + { + "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": "ProjectC78D97AD" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ProjectRoleDefaultPolicy7F29461B", + "Roles": [ + { + "Ref": "ProjectRole4CCB274E" + } + ] + } + }, + "ProjectC78D97AD": { + "Type": "AWS::CodeBuild::Project", + "Properties": { + "Artifacts": { + "Type": "CODEPIPELINE" + }, + "Environment": { + "ComputeType": "BUILD_GENERAL1_SMALL", + "Image": "aws/codebuild/standard:1.0", + "ImagePullCredentialsType": "CODEBUILD", + "PrivilegedMode": false, + "Type": "LINUX_CONTAINER" + }, + "ServiceRole": { + "Fn::GetAtt": [ + "ProjectRole4CCB274E", + "Arn" + ] + }, + "Source": { + "Type": "CODEPIPELINE" + }, + "Cache": { + "Type": "NO_CACHE" + }, + "EncryptionKey": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + }, + "PipelineArtifactsBucketEncryptionKey01D58D69": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucketEncryptionKeyAlias5C510EEE": { + "Type": "AWS::KMS::Alias", + "Properties": { + "AliasName": "alias/codepipeline-pipelinestack-pipeline-9db740af", + "TargetKeyId": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "PipelineArtifactsBucket22248F97": { + "Type": "AWS::S3::Bucket", + "Properties": { + "BucketEncryption": { + "ServerSideEncryptionConfiguration": [ + { + "ServerSideEncryptionByDefault": { + "KMSMasterKeyID": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + }, + "SSEAlgorithm": "aws:kms" + } + } + ] + }, + "PublicAccessBlockConfiguration": { + "BlockPublicAcls": true, + "BlockPublicPolicy": true, + "IgnorePublicAcls": true, + "RestrictPublicBuckets": true + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "PipelineArtifactsBucketPolicyD4F9712A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "PipelineArtifactsBucket22248F97" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleD68726F7": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "codepipeline.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineRoleDefaultPolicyC7A05455": { + "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": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildCodePipelineActionRoleD77A08E6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineRoleDefaultPolicyC7A05455", + "Roles": [ + { + "Ref": "PipelineRoleD68726F7" + } + ] + } + }, + "PipelineC660917D": { + "Type": "AWS::CodePipeline::Pipeline", + "Properties": { + "RoleArn": { + "Fn::GetAtt": [ + "PipelineRoleD68726F7", + "Arn" + ] + }, + "Stages": [ + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Source", + "Owner": "AWS", + "Provider": "S3", + "Version": "1" + }, + "Configuration": { + "S3Bucket": { + "Fn::ImportValue": "BucketStack:ExportsOutputRefBucket83908E7781C90AC0" + }, + "S3ObjectKey": "file.zip", + "PollForSourceChanges": false + }, + "Name": "Source", + "OutputArtifacts": [ + { + "Name": "Artifact_Source_Source" + } + ], + "RoleArn": { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "Source" + }, + { + "Actions": [ + { + "ActionTypeId": { + "Category": "Build", + "Owner": "AWS", + "Provider": "CodeBuild", + "Version": "1" + }, + "Configuration": { + "ProjectName": { + "Ref": "ProjectC78D97AD" + } + }, + "InputArtifacts": [ + { + "Name": "Artifact_Source_Source" + } + ], + "Name": "Build", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineBuildCodePipelineActionRoleD77A08E6", + "Arn" + ] + }, + "RunOrder": 1 + } + ], + "Name": "Build" + } + ], + "ArtifactStore": { + "EncryptionKey": { + "Id": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + }, + "Type": "KMS" + }, + "Location": { + "Ref": "PipelineArtifactsBucket22248F97" + }, + "Type": "S3" + } + }, + "DependsOn": [ + "PipelineRoleDefaultPolicyC7A05455", + "PipelineRoleD68726F7" + ] + }, + "PipelineSourceCodePipelineActionRoleC6F9E7F5": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + "/file.zip" + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925", + "Roles": [ + { + "Ref": "PipelineSourceCodePipelineActionRoleC6F9E7F5" + } + ] + } + }, + "PipelinePipelineStackPipeline9DB740AFSourceEventRulefilezipE8D1F0EF": { + "Type": "AWS::Events::Rule", + "Properties": { + "EventPattern": { + "source": [ + "aws.s3" + ], + "detail-type": [ + "AWS API Call via CloudTrail" + ], + "detail": { + "resources": { + "ARN": [ + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + "/file.zip" + ] + ] + } + ] + }, + "eventName": [ + "CompleteMultipartUpload", + "CopyObject", + "PutObject" + ], + "requestParameters": { + "bucketName": [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputRefBucket83908E7781C90AC0" + } + ], + "key": [ + "file.zip" + ] + } + } + }, + "State": "ENABLED", + "Targets": [ + { + "Arn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codepipeline:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "PipelineC660917D" + } + ] + ] + }, + "Id": "Target0", + "RoleArn": { + "Fn::GetAtt": [ + "PipelineEventsRole46BEEA7C", + "Arn" + ] + } + } + ] + } + }, + "PipelineEventsRole46BEEA7C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineEventsRoleDefaultPolicyFF4FCCE0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "codepipeline:StartPipelineExecution", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codepipeline:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "PipelineC660917D" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineEventsRoleDefaultPolicyFF4FCCE0", + "Roles": [ + { + "Ref": "PipelineEventsRole46BEEA7C" + } + ] + } + }, + "PipelineBuildCodePipelineActionRoleD77A08E6": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "codebuild:BatchGetBuilds", + "codebuild:StartBuild", + "codebuild:StopBuild" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "ProjectC78D97AD", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8", + "Roles": [ + { + "Ref": "PipelineBuildCodePipelineActionRoleD77A08E6" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..588d7b269d34f --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"20.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..17c3ab579029e --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/manifest.json @@ -0,0 +1,156 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "BucketStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "BucketStack.template.json", + "validateOnSynth": false + }, + "metadata": { + "/BucketStack/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/BucketStack/Exports/Output{\"Ref\":\"Bucket83908E77\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefBucket83908E7781C90AC0" + } + ], + "/BucketStack/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputFnGetAttBucket83908E77Arn063C8555" + } + ] + }, + "displayName": "BucketStack" + }, + "PipelineStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PipelineStack.template.json", + "validateOnSynth": false + }, + "dependencies": [ + "BucketStack" + ], + "metadata": { + "/PipelineStack/Project/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ProjectRole4CCB274E" + } + ], + "/PipelineStack/Project/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ProjectRoleDefaultPolicy7F29461B" + } + ], + "/PipelineStack/Project/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ProjectC78D97AD" + } + ], + "/PipelineStack/Pipeline/ArtifactsBucketEncryptionKey/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketEncryptionKey01D58D69" + } + ], + "/PipelineStack/Pipeline/ArtifactsBucketEncryptionKeyAlias/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketEncryptionKeyAlias5C510EEE" + } + ], + "/PipelineStack/Pipeline/ArtifactsBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucket22248F97" + } + ], + "/PipelineStack/Pipeline/ArtifactsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineArtifactsBucketPolicyD4F9712A" + } + ], + "/PipelineStack/Pipeline/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleD68726F7" + } + ], + "/PipelineStack/Pipeline/Role/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineRoleDefaultPolicyC7A05455" + } + ], + "/PipelineStack/Pipeline/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineC660917D" + } + ], + "/PipelineStack/Pipeline/Source/Source/CodePipelineActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineSourceCodePipelineActionRoleC6F9E7F5" + } + ], + "/PipelineStack/Pipeline/Source/Source/CodePipelineActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925" + } + ], + "/PipelineStack/Pipeline/PipelineStackPipeline9DB740AFSourceEventRulefile.zip/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelinePipelineStackPipeline9DB740AFSourceEventRulefilezipE8D1F0EF" + } + ], + "/PipelineStack/Pipeline/EventsRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineEventsRole46BEEA7C" + } + ], + "/PipelineStack/Pipeline/EventsRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineEventsRoleDefaultPolicyFF4FCCE0" + } + ], + "/PipelineStack/Pipeline/Build/Build/CodePipelineActionRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildCodePipelineActionRoleD77A08E6" + } + ], + "/PipelineStack/Pipeline/Build/Build/CodePipelineActionRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8" + } + ] + }, + "displayName": "PipelineStack" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/tree.json b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/tree.json new file mode 100644 index 0000000000000..257932a27ad95 --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/s3/source-bucket-events-cross-stack-same-env.integ.snapshot/tree.json @@ -0,0 +1,1275 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + }, + "BucketStack": { + "id": "BucketStack", + "path": "BucketStack", + "children": { + "Bucket": { + "id": "Bucket", + "path": "BucketStack/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "BucketStack/Bucket/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" + } + }, + "Exports": { + "id": "Exports", + "path": "BucketStack/Exports", + "children": { + "Output{\"Ref\":\"Bucket83908E77\"}": { + "id": "Output{\"Ref\":\"Bucket83908E77\"}", + "path": "BucketStack/Exports/Output{\"Ref\":\"Bucket83908E77\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}": { + "id": "Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}", + "path": "BucketStack/Exports/Output{\"Fn::GetAtt\":[\"Bucket83908E77\",\"Arn\"]}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PipelineStack": { + "id": "PipelineStack", + "path": "PipelineStack", + "children": { + "Project": { + "id": "Project", + "path": "PipelineStack/Project", + "children": { + "Role": { + "id": "Role", + "path": "PipelineStack/Project/Role", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Project/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": "PipelineStack/Project/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Project/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": "ProjectC78D97AD" + }, + ":*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/codebuild/", + { + "Ref": "ProjectC78D97AD" + } + ] + ] + } + ] + }, + { + "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": "ProjectC78D97AD" + }, + "-*" + ] + ] + } + }, + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "ProjectRoleDefaultPolicy7F29461B", + "roles": [ + { + "Ref": "ProjectRole4CCB274E" + } + ] + } + }, + "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": "PipelineStack/Project/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodeBuild::Project", + "aws:cdk:cloudformation:props": { + "artifacts": { + "type": "CODEPIPELINE" + }, + "environment": { + "type": "LINUX_CONTAINER", + "image": "aws/codebuild/standard:1.0", + "imagePullCredentialsType": "CODEBUILD", + "privilegedMode": false, + "computeType": "BUILD_GENERAL1_SMALL" + }, + "serviceRole": { + "Fn::GetAtt": [ + "ProjectRole4CCB274E", + "Arn" + ] + }, + "source": { + "type": "CODEPIPELINE" + }, + "cache": { + "type": "NO_CACHE" + }, + "encryptionKey": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.CfnProject", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codebuild.PipelineProject", + "version": "0.0.0" + } + }, + "Pipeline": { + "id": "Pipeline", + "path": "PipelineStack/Pipeline", + "children": { + "ArtifactsBucketEncryptionKey": { + "id": "ArtifactsBucketEncryptionKey", + "path": "PipelineStack/Pipeline/ArtifactsBucketEncryptionKey", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/ArtifactsBucketEncryptionKey/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.Key", + "version": "0.0.0" + } + }, + "ArtifactsBucketEncryptionKeyAlias": { + "id": "ArtifactsBucketEncryptionKeyAlias", + "path": "PipelineStack/Pipeline/ArtifactsBucketEncryptionKeyAlias", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/ArtifactsBucketEncryptionKeyAlias/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Alias", + "aws:cdk:cloudformation:props": { + "aliasName": "alias/codepipeline-pipelinestack-pipeline-9db740af", + "targetKeyId": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.CfnAlias", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.Alias", + "version": "0.0.0" + } + }, + "ArtifactsBucket": { + "id": "ArtifactsBucket", + "path": "PipelineStack/Pipeline/ArtifactsBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/ArtifactsBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "bucketEncryption": { + "serverSideEncryptionConfiguration": [ + { + "serverSideEncryptionByDefault": { + "sseAlgorithm": "aws:kms", + "kmsMasterKeyId": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + } + ] + }, + "publicAccessBlockConfiguration": { + "blockPublicAcls": true, + "blockPublicPolicy": true, + "ignorePublicAcls": true, + "restrictPublicBuckets": true + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "PipelineStack/Pipeline/ArtifactsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/ArtifactsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "PipelineArtifactsBucket22248F97" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:*", + "Condition": { + "Bool": { + "aws:SecureTransport": "false" + } + }, + "Effect": "Deny", + "Principal": { + "AWS": "*" + }, + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "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": "PipelineStack/Pipeline/Role", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/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": "PipelineStack/Pipeline/Role/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/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": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:DescribeKey", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + }, + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineBuildCodePipelineActionRoleD77A08E6", + "Arn" + ] + }, + { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineRoleDefaultPolicyC7A05455", + "roles": [ + { + "Ref": "PipelineRoleD68726F7" + } + ] + } + }, + "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": "PipelineStack/Pipeline/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CodePipeline::Pipeline", + "aws:cdk:cloudformation:props": { + "roleArn": { + "Fn::GetAtt": [ + "PipelineRoleD68726F7", + "Arn" + ] + }, + "stages": [ + { + "name": "Source", + "actions": [ + { + "name": "Source", + "outputArtifacts": [ + { + "name": "Artifact_Source_Source" + } + ], + "actionTypeId": { + "category": "Source", + "version": "1", + "owner": "AWS", + "provider": "S3" + }, + "configuration": { + "S3Bucket": { + "Fn::ImportValue": "BucketStack:ExportsOutputRefBucket83908E7781C90AC0" + }, + "S3ObjectKey": "file.zip", + "PollForSourceChanges": false + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineSourceCodePipelineActionRoleC6F9E7F5", + "Arn" + ] + } + } + ] + }, + { + "name": "Build", + "actions": [ + { + "name": "Build", + "inputArtifacts": [ + { + "name": "Artifact_Source_Source" + } + ], + "actionTypeId": { + "category": "Build", + "version": "1", + "owner": "AWS", + "provider": "CodeBuild" + }, + "configuration": { + "ProjectName": { + "Ref": "ProjectC78D97AD" + } + }, + "runOrder": 1, + "roleArn": { + "Fn::GetAtt": [ + "PipelineBuildCodePipelineActionRoleD77A08E6", + "Arn" + ] + } + } + ] + } + ], + "artifactStore": { + "type": "S3", + "location": { + "Ref": "PipelineArtifactsBucket22248F97" + }, + "encryptionKey": { + "type": "KMS", + "id": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.CfnPipeline", + "version": "0.0.0" + } + }, + "Source": { + "id": "Source", + "path": "PipelineStack/Pipeline/Source", + "children": { + "Source": { + "id": "Source", + "path": "PipelineStack/Pipeline/Source/Source", + "children": { + "CodePipelineActionRole": { + "id": "CodePipelineActionRole", + "path": "PipelineStack/Pipeline/Source/Source/CodePipelineActionRole", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Source/Source/CodePipelineActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "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": "PipelineStack/Pipeline/Source/Source/CodePipelineActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Source/Source/CodePipelineActionRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:GetBucket*", + "s3:GetObject*", + "s3:List*" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + "/file.zip" + ] + ] + } + ] + }, + { + "Action": [ + "s3:Abort*", + "s3:DeleteObject*", + "s3:PutObject", + "s3:PutObjectLegalHold", + "s3:PutObjectRetention", + "s3:PutObjectTagging", + "s3:PutObjectVersionTagging" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "PipelineArtifactsBucket22248F97", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + }, + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "PipelineArtifactsBucketEncryptionKey01D58D69", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineSourceCodePipelineActionRoleDefaultPolicy2D565925", + "roles": [ + { + "Ref": "PipelineSourceCodePipelineActionRoleC6F9E7F5" + } + ] + } + }, + "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" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + }, + "PipelineStackPipeline9DB740AFSourceEventRulefile.zip": { + "id": "PipelineStackPipeline9DB740AFSourceEventRulefile.zip", + "path": "PipelineStack/Pipeline/PipelineStackPipeline9DB740AFSourceEventRulefile.zip", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/PipelineStackPipeline9DB740AFSourceEventRulefile.zip/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Events::Rule", + "aws:cdk:cloudformation:props": { + "eventPattern": { + "source": [ + "aws.s3" + ], + "detail-type": [ + "AWS API Call via CloudTrail" + ], + "detail": { + "resources": { + "ARN": [ + { + "Fn::Join": [ + "", + [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputFnGetAttBucket83908E77Arn063C8555" + }, + "/file.zip" + ] + ] + } + ] + }, + "eventName": [ + "CompleteMultipartUpload", + "CopyObject", + "PutObject" + ], + "requestParameters": { + "bucketName": [ + { + "Fn::ImportValue": "BucketStack:ExportsOutputRefBucket83908E7781C90AC0" + } + ], + "key": [ + "file.zip" + ] + } + } + }, + "state": "ENABLED", + "targets": [ + { + "id": "Target0", + "arn": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codepipeline:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "PipelineC660917D" + } + ] + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "PipelineEventsRole46BEEA7C", + "Arn" + ] + } + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-events.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-events.Rule", + "version": "0.0.0" + } + }, + "EventsRole": { + "id": "EventsRole", + "path": "PipelineStack/Pipeline/EventsRole", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/EventsRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "events.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "PipelineStack/Pipeline/EventsRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/EventsRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "codepipeline:StartPipelineExecution", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":codepipeline:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "PipelineC660917D" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineEventsRoleDefaultPolicyFF4FCCE0", + "roles": [ + { + "Ref": "PipelineEventsRole46BEEA7C" + } + ] + } + }, + "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" + } + }, + "Build": { + "id": "Build", + "path": "PipelineStack/Pipeline/Build", + "children": { + "Build": { + "id": "Build", + "path": "PipelineStack/Pipeline/Build/Build", + "children": { + "CodePipelineActionRole": { + "id": "CodePipelineActionRole", + "path": "PipelineStack/Pipeline/Build/Build/CodePipelineActionRole", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Build/Build/CodePipelineActionRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "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": "PipelineStack/Pipeline/Build/Build/CodePipelineActionRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "PipelineStack/Pipeline/Build/Build/CodePipelineActionRole/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": [ + "ProjectC78D97AD", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "PipelineBuildCodePipelineActionRoleDefaultPolicyC9CB73F8", + "roles": [ + { + "Ref": "PipelineBuildCodePipelineActionRoleD77A08E6" + } + ] + } + }, + "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" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.63" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-codepipeline.Pipeline", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-events/lib/on-event-options.ts b/packages/@aws-cdk/aws-events/lib/on-event-options.ts index 57fad3514c2f8..ff3d57652b46e 100644 --- a/packages/@aws-cdk/aws-events/lib/on-event-options.ts +++ b/packages/@aws-cdk/aws-events/lib/on-event-options.ts @@ -1,17 +1,11 @@ +import { Construct } from 'constructs'; import { EventPattern } from './event-pattern'; import { IRuleTarget } from './target'; /** - * Standard set of options for `onXxx` event handlers on construct + * Common options for Events. */ -export interface OnEventOptions { - /** - * The target to register for the event - * - * @default - No target is added to the rule. Use `addTarget()` to add a target. - */ - readonly target?: IRuleTarget; - +export interface EventCommonOptions { /** * A description of the rule's purpose. * @@ -39,4 +33,25 @@ export interface OnEventOptions { * https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-and-event-patterns.html */ readonly eventPattern?: EventPattern; + + /** + * The scope to use if the source of the rule and its target are in different Stacks + * (but in the same account & region). + * This helps dealing with cycles that often arise in these situations. + * + * @default - none (the main scope will be used, even for cross-stack Events) + */ + readonly crossStackScope?: Construct; +} + +/** + * Standard set of options for `onXxx` event handlers on construct + */ +export interface OnEventOptions extends EventCommonOptions { + /** + * The target to register for the event + * + * @default - No target is added to the rule. Use `addTarget()` to add a target. + */ + readonly target?: IRuleTarget; } diff --git a/packages/@aws-cdk/aws-events/lib/rule.ts b/packages/@aws-cdk/aws-events/lib/rule.ts index 5ef09a21dc69d..3d912ec561254 100644 --- a/packages/@aws-cdk/aws-events/lib/rule.ts +++ b/packages/@aws-cdk/aws-events/lib/rule.ts @@ -1,9 +1,10 @@ import { IRole, PolicyStatement, Role, ServicePrincipal } from '@aws-cdk/aws-iam'; -import { App, IResource, Lazy, Names, Resource, Stack, Token, PhysicalName, ArnFormat } from '@aws-cdk/core'; +import { App, IResource, Lazy, Names, Resource, Stack, Token, TokenComparison, PhysicalName, ArnFormat } from '@aws-cdk/core'; import { Node, Construct } from 'constructs'; import { IEventBus } from './event-bus'; import { EventPattern } from './event-pattern'; import { CfnEventBusPolicy, CfnRule } from './events.generated'; +import { EventCommonOptions } from './on-event-options'; import { IRule } from './rule-ref'; import { Schedule } from './schedule'; import { IRuleTarget } from './target'; @@ -12,22 +13,7 @@ import { mergeEventPattern, renderEventPattern, sameEnvDimension } from './util' /** * Properties for defining an EventBridge Rule */ -export interface RuleProps { - /** - * A description of the rule's purpose. - * - * @default - No description. - */ - readonly description?: string; - - /** - * A name for the rule. - * - * @default - AWS CloudFormation generates a unique physical ID and uses that ID - * for the rule name. For more information, see Name Type. - */ - readonly ruleName?: string; - +export interface RuleProps extends EventCommonOptions { /** * Indicates whether the rule is enabled. * @@ -50,23 +36,6 @@ export interface RuleProps { */ readonly schedule?: Schedule; - /** - * Describes which events EventBridge routes to the specified target. - * These routed events are matched events. - * - * You must specify this property (either via props or via - * `addEventPattern`), the `scheduleExpression` property, or both. The - * method `addEventPattern` can be used to add filter values to the event - * pattern. - * - * For more information, see Events and Event Patterns in the Amazon EventBridge User Guide. - * - * @see https://docs.aws.amazon.com/eventbridge/latest/userguide/eventbridge-and-event-patterns.html - * - * @default - None. - */ - readonly eventPattern?: EventPattern; - /** * Targets to invoke when this rule matches an event. * @@ -121,7 +90,7 @@ export class Rule extends Resource implements IRule { private readonly _xEnvTargetsAdded = new Set(); constructor(scope: Construct, id: string, props: RuleProps = { }) { - super(scope, id, { + super(determineRuleScope(scope, props), id, { physicalName: props.ruleName, }); @@ -456,6 +425,24 @@ export class Rule extends Resource implements IRule { } } +function determineRuleScope(scope: Construct, props: RuleProps): Construct { + if (!props.crossStackScope) { + return scope; + } + const scopeStack = Stack.of(scope); + const targetStack = Stack.of(props.crossStackScope); + if (scopeStack === targetStack) { + return scope; + } + // cross-region/account Events require their own setup, + // so we use the base scope in that case + const regionComparison = Token.compareStrings(scopeStack.region, targetStack.region); + const accountComparison = Token.compareStrings(scopeStack.account, targetStack.account); + const stacksInSameAccountAndRegion = (regionComparison === TokenComparison.SAME || regionComparison === TokenComparison.BOTH_UNRESOLVED) && + (accountComparison === TokenComparison.SAME || accountComparison === TokenComparison.BOTH_UNRESOLVED); + return stacksInSameAccountAndRegion ? props.crossStackScope : scope; +} + /** * A rule that mirrors another rule */