diff --git a/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts b/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts index e38287c0cdc07..55eac4cadd32f 100644 --- a/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts +++ b/packages/@aws-cdk/aws-events-targets/lib/codebuild.ts @@ -7,6 +7,15 @@ import { singletonEventRole } from './util'; * Customize the CodeBuild Event Target */ export interface CodeBuildProjectProps { + + /** + * The role to assume before invoking the target + * (i.e., the codebuild) when the given rule is triggered. + * + * @default - a new role will be created + */ + readonly eventRole?: iam.IRole; + /** * The event to send to CodeBuild * @@ -33,7 +42,7 @@ export class CodeBuildProject implements events.IRuleTarget { return { id: '', arn: this.project.projectArn, - role: singletonEventRole(this.project, [ + role: this.props.eventRole || singletonEventRole(this.project, [ new iam.PolicyStatement({ actions: ['codebuild:StartBuild'], resources: [this.project.projectArn], diff --git a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts index 7cec0549d4e05..c7bb3d59b68e8 100644 --- a/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts +++ b/packages/@aws-cdk/aws-events-targets/test/codebuild/codebuild.test.ts @@ -1,105 +1,123 @@ import { expect, haveResource } from '@aws-cdk/assert'; import * as codebuild from '@aws-cdk/aws-codebuild'; import * as events from '@aws-cdk/aws-events'; -import { Stack } from '@aws-cdk/core'; +import * as iam from '@aws-cdk/aws-iam'; +import { CfnElement, Stack } from '@aws-cdk/core'; import * as targets from '../../lib'; -test('use codebuild project as an eventrule target', () => { - // GIVEN - const stack = new Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - const rule = new events.Rule(stack, 'Rule', { - schedule: events.Schedule.expression('rate(1 min)'), +describe('CodeBuild event target', () => { + let stack: Stack; + let project: codebuild.PipelineProject; + let projectArn: any; + + beforeEach(() => { + stack = new Stack(); + project = new codebuild.PipelineProject(stack, 'MyProject'); + projectArn = { 'Fn::GetAtt': ['MyProject39F7B0AE', 'Arn'] }; }); - // WHEN - rule.addTarget(new targets.CodeBuildProject(project)); + test('use codebuild project as an eventrule target', () => { + // GIVEN + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { - 'Fn::GetAtt': [ - 'MyProject39F7B0AE', - 'Arn', - ], - }, - Id: 'Target0', - RoleArn: { - 'Fn::GetAtt': [ - 'MyProjectEventsRole5B7D93F5', - 'Arn', - ], - }, - }, - ], - })); + // WHEN + rule.addTarget(new targets.CodeBuildProject(project)); - expect(stack).to(haveResource('AWS::IAM::Role', { - AssumeRolePolicyDocument: { - Statement: [ + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + Targets: [ { - Action: 'sts:AssumeRole', - Effect: 'Allow', - Principal: { Service: 'events.amazonaws.com' }, + Arn: projectArn, + Id: 'Target0', + RoleArn: { 'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'] }, }, ], - Version: '2012-10-17', - }, - })); + })); + + expect(stack).to(haveResource('AWS::IAM::Role', { + AssumeRolePolicyDocument: { + Statement: [ + { + Action: 'sts:AssumeRole', + Effect: 'Allow', + Principal: { Service: 'events.amazonaws.com' }, + }, + ], + Version: '2012-10-17', + }, + })); + + expect(stack).to(haveResource('AWS::IAM::Policy', { + PolicyDocument: { + Statement: [ + { + Action: 'codebuild:StartBuild', + Effect: 'Allow', + Resource: projectArn, + }, + ], + Version: '2012-10-17', + }, + })); + }); - expect(stack).to(haveResource('AWS::IAM::Policy', { - PolicyDocument: { - Statement: [ + test('specifying event for codebuild project target', () => { + // GIVEN + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 hour)'), + }); + + // WHEN + const eventInput = { + buildspecOverride: 'buildspecs/hourly.yml', + }; + + rule.addTarget( + new targets.CodeBuildProject(project, { + event: events.RuleTargetInput.fromObject(eventInput), + }), + ); + + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + Targets: [ { - Action: 'codebuild:StartBuild', - Effect: 'Allow', - Resource: { - 'Fn::GetAtt': [ - 'MyProject39F7B0AE', - 'Arn', - ], + Arn: projectArn, + Id: 'Target0', + Input: JSON.stringify(eventInput), + RoleArn: { + 'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'], }, }, ], - Version: '2012-10-17', - }, - })); -}); - -test('specifying event for codebuild project target', () => { - // GIVEN - const stack = new Stack(); - const project = new codebuild.PipelineProject(stack, 'MyProject'); - const rule = new events.Rule(stack, 'Rule', { - schedule: events.Schedule.expression('rate(1 hour)'), + })); }); - // WHEN - const eventInput = { - buildspecOverride: 'buildspecs/hourly.yml', - }; + test('specifying custom role for codebuild project target', () => { + // GIVEN + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 hour)'), + }); + const role = new iam.Role(stack, 'MyExampleRole', { + assumedBy: new iam.AnyPrincipal(), + }); + const roleResource = role.node.defaultChild as CfnElement; + roleResource.overrideLogicalId('MyRole'); // to make it deterministic in the assertion below - rule.addTarget( - new targets.CodeBuildProject(project, { - event: events.RuleTargetInput.fromObject(eventInput), - }), - ); + // WHEN + rule.addTarget(new targets.CodeBuildProject(project, { eventRole: role })); - // THEN - expect(stack).to(haveResource('AWS::Events::Rule', { - Targets: [ - { - Arn: { - 'Fn::GetAtt': ['MyProject39F7B0AE', 'Arn'], - }, - Id: 'Target0', - Input: JSON.stringify(eventInput), - RoleArn: { - 'Fn::GetAtt': ['MyProjectEventsRole5B7D93F5', 'Arn'], + // THEN + expect(stack).to(haveResource('AWS::Events::Rule', { + Targets: [ + { + Arn: projectArn, + Id: 'Target0', + RoleArn: { 'Fn::GetAtt': ['MyRole', 'Arn'] }, }, - }, - ], - })); + ], + })); + }); });