diff --git a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts index dc40545e04e49..54e0d13856bda 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/lib/codebuild/build-action.ts @@ -83,8 +83,19 @@ export class CodeBuildAction extends Action { this.props = props; } - protected bound(_scope: cdk.Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): + protected bound(scope: cdk.Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig { + // check for a cross-account action if there are any outputs + if ((this.actionProperties.outputs || []).length > 0) { + const pipelineStack = cdk.Stack.of(scope); + const projectStack = cdk.Stack.of(this.props.project); + if (pipelineStack.account !== projectStack.account) { + throw new Error('A cross-account CodeBuild action cannot have outputs. ' + + 'This is a known CodeBuild limitation. ' + + 'See https://github.com/aws/aws-cdk/issues/4169 for details'); + } + } + // grant the Pipeline role the required permissions to this Project options.role.addToPolicy(new iam.PolicyStatement({ resources: [this.props.project.projectArn], diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts new file mode 100644 index 0000000000000..96370fb923c8d --- /dev/null +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/codebuild/test.codebuild-action.ts @@ -0,0 +1,67 @@ +import codebuild = require('@aws-cdk/aws-codebuild'); +import codecommit = require('@aws-cdk/aws-codecommit'); +import codepipeline = require('@aws-cdk/aws-codepipeline'); +import { App, Stack } from '@aws-cdk/core'; +import { Test } from 'nodeunit'; +import cpactions = require('../../lib'); + +// tslint:disable:object-literal-key-quotes + +export = { + 'a cross-account CodeBuild action with outputs': { + 'causes an error'(test: Test) { + const app = new App(); + + const projectStack = new Stack(app, 'ProjectStack', { + env: { + region: 'us-west-2', + account: '012345678901', + }, + }); + const project = new codebuild.PipelineProject(projectStack, 'Project'); + + const pipelineStack = new Stack(app, 'PipelineStack', { + env: { + region: 'us-west-2', + account: '123456789012', + }, + }); + const sourceOutput = new codepipeline.Artifact(); + const pipeline = new codepipeline.Pipeline(pipelineStack, 'Pipeline', { + stages: [ + { + stageName: 'Source', + actions: [new cpactions.CodeCommitSourceAction({ + actionName: 'CodeCommit', + repository: codecommit.Repository.fromRepositoryName(pipelineStack, 'Repo', 'repo-name'), + output: sourceOutput, + })], + }, + ], + }); + const buildStage = pipeline.addStage({ + stageName: 'Build', + }); + + // this works fine - no outputs! + buildStage.addAction(new cpactions.CodeBuildAction({ + actionName: 'Build1', + input: sourceOutput, + project, + })); + + const buildAction2 = new cpactions.CodeBuildAction({ + actionName: 'Build2', + input: sourceOutput, + project, + outputs: [new codepipeline.Artifact()], + }); + + test.throws(() => { + buildStage.addAction(buildAction2); + }, /https:\/\/github\.com\/aws\/aws-cdk\/issues\/4169/); + + test.done(); + }, + }, +}; diff --git a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts index 9591470c004e7..b006aea4800e2 100644 --- a/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts +++ b/packages/@aws-cdk/aws-codepipeline-actions/test/test.pipeline.ts @@ -873,7 +873,6 @@ export = { actionName: 'CodeBuild', project, input: sourceOutput, - outputs: [new codepipeline.Artifact()], }), ], }, @@ -922,9 +921,6 @@ export = { "s3:GetObject*", "s3:GetBucket*", "s3:List*", - "s3:DeleteObject*", - "s3:PutObject*", - "s3:Abort*", ], "Effect": "Allow", "Resource": [ @@ -958,9 +954,6 @@ export = { "Action": [ "kms:Decrypt", "kms:DescribeKey", - "kms:Encrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*", ], "Effect": "Allow", "Resource": "*",