diff --git a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts index 43519fdda97bf..12bb058fceddb 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/codebuild-step.ts @@ -66,6 +66,13 @@ export interface CodeBuildStepProps extends ShellStepProps { */ readonly role?: iam.IRole; + /** + * Custom execution role to be used for the Code Build Action + * + * @default - A role is automatically created + */ + readonly actionRole?: iam.IRole; + /** * Changes to environment * @@ -146,6 +153,13 @@ export class CodeBuildStep extends ShellStep { */ public readonly role?: iam.IRole; + /** + * Custom execution role to be used for the Code Build Action + * + * @default - A role is automatically created + */ + readonly actionRole?: iam.IRole; + /** * Build environment * @@ -183,6 +197,7 @@ export class CodeBuildStep extends ShellStep { this.vpc = props.vpc; this.subnetSelection = props.subnetSelection; this.role = props.role; + this.actionRole = props.actionRole; this.rolePolicyStatements = props.rolePolicyStatements; this.securityGroups = props.securityGroups; this.timeout = props.timeout; 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 3103586f71546..85697104e2cc4 100644 --- a/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts +++ b/packages/@aws-cdk/pipelines/lib/codepipeline/private/codebuild-factory.ts @@ -44,6 +44,13 @@ export interface CodeBuildFactoryProps { */ readonly role?: iam.IRole; + /** + * Custom execution role to be used for the Code Build Action + * + * @default - A role is automatically created + */ + readonly actionRole?: iam.IRole; + /** * If true, the build spec will be passed via the Cloud Assembly instead of rendered onto the Project * @@ -145,6 +152,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { const factory = CodeBuildFactory.fromShellStep(constructId, step, { projectName: step.projectName, role: step.role, + actionRole: step.actionRole, ...additional, projectOptions: mergeCodeBuildOptions(additional?.projectOptions, { buildEnvironment: step.buildEnvironment, @@ -322,6 +330,7 @@ export class CodeBuildFactory implements ICodePipelineActionFactory { outputs: outputArtifacts, project, runOrder: options.runOrder, + role: this.props.actionRole, variablesNamespace: options.variablesNamespace, // Inclusion of the hash here will lead to the pipeline structure for any changes diff --git a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts index a48b41ce1d6c6..ad3a5b3be9923 100644 --- a/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts +++ b/packages/@aws-cdk/pipelines/test/codepipeline/codebuild-step.test.ts @@ -1,4 +1,5 @@ import { Template, Match } from '@aws-cdk/assertions'; +import * as iam from '@aws-cdk/aws-iam'; import { Duration, Stack } from '@aws-cdk/core'; import * as cdkp from '../../lib'; import { PIPELINE_ENV, TestApp, ModernTestGitHubNpmPipeline, AppWithOutput } from '../testhelpers'; @@ -143,6 +144,68 @@ test('envFromOutputs works even with very long stage and stack names', () => { // THEN - did not throw an error about identifier lengths }); +test('role passed it used for project and code build action', () => { + const projectRole = new iam.Role( + pipelineStack, + 'ProjectRole', + { + roleName: 'ProjectRole', + assumedBy: new iam.ServicePrincipal('codebuild.amazon.com'), + }, + ); + const buildRole = new iam.Role( + pipelineStack, + 'BuildRole', + { + roleName: 'BuildRole', + assumedBy: new iam.ServicePrincipal('codebuild.amazon.com'), + }, + ); + // WHEN + new cdkp.CodePipeline(pipelineStack, 'Pipeline', { + synth: new cdkp.CodeBuildStep('Synth', { + commands: ['/bin/true'], + input: cdkp.CodePipelineSource.gitHub('test/test', 'main'), + role: projectRole, + actionRole: buildRole, + }), + }); + + // THEN + Template.fromStack(pipelineStack).hasResourceProperties('AWS::CodeBuild::Project', { + ServiceRole: { + 'Fn::GetAtt': [ + 'ProjectRole5B707505', + 'Arn', + ], + }, + }); + + expect(pipelineStack).toHaveResourceLike('AWS::CodePipeline::Pipeline', { + Stages: [ + // source stage + {}, + // build stage, + { + Actions: [ + { + ActionTypeId: { + Category: 'Build', + Owner: 'AWS', + Provider: 'CodeBuild', + }, + RoleArn: { + 'Fn::GetAtt': [ + 'BuildRole41B77417', + 'Arn', + ], + }, + }, + ], + }, + ], + }); +}); test('exportedVariables', () => { const pipeline = new ModernTestGitHubNpmPipeline(pipelineStack, 'Cdk'); @@ -207,4 +270,4 @@ test('exportedVariables', () => { })), }, }); -}); \ No newline at end of file +});