diff --git a/lib/deploy/stepFunctions/compileIamRole.js b/lib/deploy/stepFunctions/compileIamRole.js index 5656d652..13c649e3 100644 --- a/lib/deploy/stepFunctions/compileIamRole.js +++ b/lib/deploy/stepFunctions/compileIamRole.js @@ -264,6 +264,28 @@ function getStepFunctionsPermissions(state) { }]; } +function getCodeBuildPermissions(state) { + const projectName = state.Parameters.ProjectName; + + return [{ + action: 'codebuild:StartBuild,codebuild:StopBuild,codebuild:BatchGetBuilds', + resource: { + 'Fn::Sub': [ + `arn:aws:codebuild:$\{AWS::Region}:$\{AWS::AccountId}:project/${projectName}`, + {}, + ], + }, + }, { + action: 'events:PutTargets,events:PutRule,events:DescribeRule', + resource: { + 'Fn::Sub': [ + 'arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventForCodeBuildStartBuildRule', + {}, + ], + }, + }]; +} + // if there are multiple permissions with the same action, then collapsed them into one // permission instead, and collect the resources into an array function consolidatePermissionsByAction(permissions) { @@ -344,6 +366,10 @@ function getIamPermissions(taskStates) { case 'arn:aws:states:::states:startExecution.waitForTaskToken': return getStepFunctionsPermissions(state); + case 'arn:aws:states:::codebuild:startBuild': + case 'arn:aws:states:::codebuild:startBuild.sync': + return getCodeBuildPermissions(state); + default: if (isIntrinsic(state.Resource) || state.Resource.startsWith('arn:aws:lambda')) { const trimmedArn = trimAliasFromLambdaArn(state.Resource); diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index e0d12908..1a8a315f 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -1560,6 +1560,63 @@ describe('#compileIamRole', () => { expectation(policy2, lambdaArns[2], lambdaArns[3]); }); + it('should give CodeBuild permissions', () => { + const projectName = 'HelloProject'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::codebuild:startBuild', + Parameters: { + ProjectName: projectName, + }, + Next: 'B', + }, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::codebuild:startBuild.sync', + Parameters: { + ProjectName: projectName, + }, + End: true, + }, + }, + }, + }); + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + + const codeBuildPermissions = statements.filter(s => _.isEqual(s.Action, ['codebuild:StartBuild', 'codebuild:StopBuild', 'codebuild:BatchGetBuilds'])); + expect(codeBuildPermissions).to.have.lengthOf(1); + expect(codeBuildPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + `arn:aws:codebuild:$\{AWS::Region}:$\{AWS::AccountId}:project/${projectName}`, + {}, + ], + }]); + + + const eventPermissions = statements.filter(s => _.isEqual(s.Action, ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'])); + expect(eventPermissions).to.have.lengthOf(1); + expect(eventPermissions[0].Resource).to.deep.eq([{ + 'Fn::Sub': [ + 'arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventForCodeBuildStartBuildRule', + {}, + ], + }]); + }); + it('should give step functions permissions (too permissive, but mirrors console behaviour)', () => { const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; const genStateMachine = id => ({ @@ -1935,7 +1992,6 @@ describe('#compileIamRole', () => { .Properties.Policies[0].PolicyDocument.Statement; const lambdaPermissions2 = statements2.filter(s => _.isEqual(s.Action, ['lambda:InvokeFunction'])); expect(lambdaPermissions2).to.have.lengthOf(1); - console.log(lambdaPermissions2); expect(lambdaPermissions2[0].Resource).to.deep.equal([ 'arn:aws:lambda:us-west-2:1234567890:function:foo', '*limited*',