diff --git a/lib/deploy/stepFunctions/compileIamRole.js b/lib/deploy/stepFunctions/compileIamRole.js index 8772a20..90ec17e 100644 --- a/lib/deploy/stepFunctions/compileIamRole.js +++ b/lib/deploy/stepFunctions/compileIamRole.js @@ -360,9 +360,18 @@ function getRedshiftDataPermissions(action, state) { } function getLambdaPermissions(state) { + if (isJsonPathParameter(state, 'FunctionName') || isJsonataArgument(state, 'FunctionName')) { + const allowedFunctions = getParameterOrArgument(state, 'AllowedFunctions'); + return [{ + action: 'lambda:InvokeFunction', + resource: allowedFunctions || '*', + }]; + } + // function name can be name-only, name-only with alias, full arn or partial arn // https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestParameters - const functionName = state.Parameters.FunctionName; + const functionName = getParameterOrArgument(state, 'FunctionName'); + if (_.isString(functionName)) { const segments = functionName.split(':'); @@ -429,13 +438,6 @@ function getLambdaPermissions(state) { }]; } - if (state.Parameters['FunctionName.$']) { - return [{ - action: 'lambda:InvokeFunction', - resource: state.Parameters.AllowedFunctions ? state.Parameters.AllowedFunctions : '*', - }]; - } - // hope for the best... return [{ action: 'lambda:InvokeFunction', diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index e6603ef..0772986 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -3587,7 +3587,49 @@ describe('#compileIamRole', () => { ]); }); - it('should support variable FunctionName', () => { + itParam('should resolve FunctionName: ${value}', ['JSONPath', 'JSONata'], (queryLanguage) => { + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: { + id: 'StateMachine1', + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::lambda:invoke', + ...getParamsOrArgs( + queryLanguage, + { + FunctionName: 'arn:aws:lambda:us-west-2:1234567890:function:foo', + 'Payload.$': '$.Payload', + }, + { + FunctionName: 'arn:aws:lambda:us-west-2:1234567890:function:foo', + Payload: '{% $states.input.Payload %}', + }, + ), + End: true, + }, + }, + }, + }, + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; + const lambdaPermissions = statements.filter(s => _.isEqual(s.Action, ['lambda:InvokeFunction'])); + expect(lambdaPermissions).to.have.lengthOf(1); + expect(lambdaPermissions[0].Resource).to.deep.equal([ + 'arn:aws:lambda:us-west-2:1234567890:function:foo', + 'arn:aws:lambda:us-west-2:1234567890:function:foo:*', + ]); + }); + + itParam('should support variable FunctionName: ${value}', ['JSONPath', 'JSONata'], (queryLanguage) => { serverless.service.stepFunctions = { stateMachines: { myStateMachine1: { @@ -3598,26 +3640,47 @@ describe('#compileIamRole', () => { A: { Type: 'Task', Resource: 'arn:aws:states:::lambda:invoke.waitForTaskToken', - Parameters: { - 'FunctionName.$': '$.functionName', - Payload: { - 'model.$': '$.new_model', - 'token.$': '$$.Task.Token', + ...getParamsOrArgs( + queryLanguage, + { + 'FunctionName.$': '$.functionName', + Payload: { + 'model.$': '$.new_model', + 'token.$': '$$.Task.Token', + }, }, - }, + { + FunctionName: '{% $states.input.functionName %}', + Payload: { + model: '{% $states.input.new_model %}', + token: '{% $states.context.Task.Token %}', + }, + }, + ), Next: 'B', }, B: { Type: 'Task', Resource: 'arn:aws:states:::lambda:invoke.waitForTaskToken', - Parameters: { - 'FunctionName.$': '$.functionName', - AllowedFunctions: '*limited*', - Payload: { - 'model.$': '$.new_model', - 'token.$': '$$.Task.Token', + ...getParamsOrArgs( + queryLanguage, + { + 'FunctionName.$': '$.functionName', + AllowedFunctions: '*limited*', + Payload: { + 'model.$': '$.new_model', + 'token.$': '$$.Task.Token', + }, }, - }, + { + FunctionName: '{% $states.input.functionName %}', + AllowedFunctions: '*limited*', + Payload: { + model: '{% $states.input.new_model %}', + token: '{% $states.context.Task.Token %}', + }, + }, + ), End: true, }, }, @@ -3643,27 +3706,49 @@ describe('#compileIamRole', () => { A: { Type: 'Task', Resource: 'arn:aws:states:::lambda:invoke.waitForTaskToken', - Parameters: { - 'FunctionName.$': '$.functionName', - AllowedFunctions: 'arn:aws:lambda:us-west-2:1234567890:function:foo', - Payload: { - 'model.$': '$.new_model', - 'token.$': '$$.Task.Token', + ...getParamsOrArgs( + queryLanguage, + { + 'FunctionName.$': '$.functionName', + AllowedFunctions: 'arn:aws:lambda:us-west-2:1234567890:function:foo', + Payload: { + 'model.$': '$.new_model', + 'token.$': '$$.Task.Token', + }, }, - }, + { + FunctionName: '{% $states.input.functionName %}', + AllowedFunctions: 'arn:aws:lambda:us-west-2:1234567890:function:foo', + Payload: { + model: '{% $states.input.new_model %}', + token: '{% $states.context.Task.Token %}', + }, + }, + ), Next: 'B', }, B: { Type: 'Task', Resource: 'arn:aws:states:::lambda:invoke.waitForTaskToken', - Parameters: { - 'FunctionName.$': '$.functionName', - AllowedFunctions: '*limited*', - Payload: { - 'model.$': '$.new_model', - 'token.$': '$$.Task.Token', + ...getParamsOrArgs( + queryLanguage, + { + 'FunctionName.$': '$.functionName', + AllowedFunctions: '*limited*', + Payload: { + 'model.$': '$.new_model', + 'token.$': '$$.Task.Token', + }, }, - }, + { + FunctionName: '{% $states.input.functionName %}', + AllowedFunctions: '*limited*', + Payload: { + model: '{% $states.input.new_model %}', + token: '{% $states.context.Task.Token %}', + }, + }, + ), End: true, }, },