From 00bc4cf8a40e6022abf84d89b7efef354f3bb8f8 Mon Sep 17 00:00:00 2001 From: zirkelc Date: Thu, 5 Dec 2024 13:41:25 +0100 Subject: [PATCH 1/6] test: add test for jsonata --- .../compileStateMachines.test.js | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/deploy/stepFunctions/compileStateMachines.test.js b/lib/deploy/stepFunctions/compileStateMachines.test.js index 1b17a39c..e3a4de80 100644 --- a/lib/deploy/stepFunctions/compileStateMachines.test.js +++ b/lib/deploy/stepFunctions/compileStateMachines.test.js @@ -16,7 +16,7 @@ describe('#compileStateMachines', () => { serverless.cli = new CLI(serverless); serverless.configSchemaHandler = { // eslint-disable-next-line no-unused-vars - defineTopLevelProperty: (propertyName, propertySchema) => {}, + defineTopLevelProperty: (propertyName, propertySchema) => { }, }; serverless.servicePath = true; serverless.service.service = 'step-functions'; @@ -1728,4 +1728,59 @@ describe('#compileStateMachines', () => { const stateMachineObj = JSON.parse(stateMachine.Properties.DefinitionString); expect(stateMachineObj.States).to.haveOwnProperty('One'); }); + + it('should compile with the new JSONata fields', () => { + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: { + id: 'Test', + name: 'Test', + definition: { + Comment: 'Test JSONata features', + QueryLanguage: 'JSONata', + StartAt: 'Store inputs', + States: { + 'Store inputs': { + Type: 'Pass', + Next: 'Output transformation', + Assign: { + desiredPrice: '{% $states.input.desired_price %}', + maximumWait: '{% $states.input.max_days %}', + }, + }, + 'Output transformation': { + Type: 'Succeed', + Output: { + lastName: + "{% 'Last=>' & $states.input.customer.lastName %}", + orderValue: '{% $states.input.order.total %}', + }, + }, + }, + }, + }, + }, + }; + + serverlessStepFunctions.compileStateMachines(); + + const stateMachine = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources + .Test; + + expect(stateMachine.Properties.DefinitionString).not.to.haveOwnProperty('Fn::Sub'); + const stateMachineObj = JSON.parse(stateMachine.Properties.DefinitionString); + expect(stateMachineObj.States).to.haveOwnProperty('Store inputs'); + expect(stateMachineObj.States).to.haveOwnProperty('Output transformation'); + + expect(stateMachineObj.QueryLanguage).to.equal('JSONata'); + expect(stateMachineObj.States['Store inputs'].Assign).to.deep.equal({ + desiredPrice: '{% $states.input.desired_price %}', + maximumWait: '{% $states.input.max_days %}', + }); + expect(stateMachineObj.States['Output transformation'].Output).to.deep.equal({ + lastName: "{% 'Last=>' & $states.input.customer.lastName %}", + orderValue: '{% $states.input.order.total %}', + }); + }); }); From f8a350571cc38f1db6bf6cf427e45f86812cebad Mon Sep 17 00:00:00 2001 From: zirkelc Date: Mon, 16 Dec 2024 14:59:55 +0100 Subject: [PATCH 2/6] test: add test --- .../compileStateMachines.test.js | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/deploy/stepFunctions/compileStateMachines.test.js b/lib/deploy/stepFunctions/compileStateMachines.test.js index e3a4de80..cfe5a5e9 100644 --- a/lib/deploy/stepFunctions/compileStateMachines.test.js +++ b/lib/deploy/stepFunctions/compileStateMachines.test.js @@ -1742,12 +1742,27 @@ describe('#compileStateMachines', () => { States: { 'Store inputs': { Type: 'Pass', - Next: 'Output transformation', + Next: 'Get Current Price', Assign: { desiredPrice: '{% $states.input.desired_price %}', maximumWait: '{% $states.input.max_days %}', }, }, + 'Get Current Price': { + Type: 'Task', + QueryLanguage: 'JSONata', + Resource: 'arn:aws:states:::lambda:invoke', + Next: 'Output transformation', + Arguments: { + Payload: { + product: '{% $states.context.Execution.Input.product %}', + }, + FunctionName: 'arn:aws:lambda::123456789012:function:priceWatcher:$LATEST', + }, + Assign: { + currentPrice: '{% $states.result.Payload.current_price %}', + }, + }, 'Output transformation': { Type: 'Succeed', Output: { @@ -1771,6 +1786,7 @@ describe('#compileStateMachines', () => { expect(stateMachine.Properties.DefinitionString).not.to.haveOwnProperty('Fn::Sub'); const stateMachineObj = JSON.parse(stateMachine.Properties.DefinitionString); expect(stateMachineObj.States).to.haveOwnProperty('Store inputs'); + expect(stateMachineObj.States).to.haveOwnProperty('Get Current Price'); expect(stateMachineObj.States).to.haveOwnProperty('Output transformation'); expect(stateMachineObj.QueryLanguage).to.equal('JSONata'); @@ -1778,6 +1794,15 @@ describe('#compileStateMachines', () => { desiredPrice: '{% $states.input.desired_price %}', maximumWait: '{% $states.input.max_days %}', }); + expect(stateMachineObj.States['Get Current Price'].Arguments).to.deep.equal({ + Payload: { + product: '{% $states.context.Execution.Input.product %}', + }, + FunctionName: 'arn:aws:lambda::123456789012:function:priceWatcher:$LATEST', + }); + expect(stateMachineObj.States['Get Current Price'].Assign).to.deep.equal({ + currentPrice: '{% $states.result.Payload.current_price %}', + }); expect(stateMachineObj.States['Output transformation'].Output).to.deep.equal({ lastName: "{% 'Last=>' & $states.input.customer.lastName %}", orderValue: '{% $states.input.order.total %}', From 39272e240b0d4f1cbedd94abef8962a06c3c7971 Mon Sep 17 00:00:00 2001 From: zirkelc Date: Wed, 18 Dec 2024 17:50:05 +0100 Subject: [PATCH 3/6] fix: compiel iam roles for arguments --- lib/deploy/stepFunctions/compileIamRole.js | 22 +- .../stepFunctions/compileIamRole.test.js | 566 ++++++++++++------ 2 files changed, 415 insertions(+), 173 deletions(-) diff --git a/lib/deploy/stepFunctions/compileIamRole.js b/lib/deploy/stepFunctions/compileIamRole.js index c5f56760..864491be 100644 --- a/lib/deploy/stepFunctions/compileIamRole.js +++ b/lib/deploy/stepFunctions/compileIamRole.js @@ -407,6 +407,22 @@ function getLambdaPermissions(state) { }]; } +function getStateMachineArn(state) { + let stateMachineArn; + + if (state.Arguments) { + stateMachineArn = state.Arguments.StateMachineArn.trim().startsWith('{%') + ? '*' + : state.Arguments.StateMachineArn; + } else { + stateMachineArn = state.Parameters['StateMachineArn.$'] + ? '*' + : state.Parameters.StateMachineArn; + } + + return stateMachineArn; +} + function getStepFunctionsPermissions(state) { let stateMachineArn = state.Mode === 'DISTRIBUTED' ? { 'Fn::Sub': [ @@ -416,8 +432,7 @@ function getStepFunctionsPermissions(state) { } : null; if (!stateMachineArn) { - stateMachineArn = state.Parameters['StateMachineArn.$'] ? '*' - : state.Parameters.StateMachineArn; + stateMachineArn = getStateMachineArn(state); } return [{ @@ -449,8 +464,7 @@ function getStepFunctionsSDKPermissions(state) { } : null; if (!stateMachineArn) { - stateMachineArn = state.Parameters['StateMachineArn.$'] ? '*' - : state.Parameters.StateMachineArn; + stateMachineArn = getStateMachineArn(state); } return [{ diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index ab17a4a7..91588998 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -2874,219 +2874,447 @@ describe('#compileIamRole', () => { }]); }); - 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 => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + describe('should give step functions permissions (too permissive, but mirrors console behaviour)', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'B', }, - Next: 'B', - }, - B: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', }, - Next: 'C', - }, - C: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync:2', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync:2', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'D', }, - Next: 'D', - }, - D: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + D: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - 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 stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'B', + }, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', + }, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync:2', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'D', + }, + D: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; - const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); - expect(executionPermissions).to.have.lengthOf(1); - expect(executionPermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); - 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', - {}, - ], - }]); + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); + }); }); - it('should give step functions using sdk permissions (too permissive, but mirrors console behavior)', () => { - const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + describe('should give step functions using sdk permissions (too permissive, but mirrors console behavior)', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - 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 stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; - const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); - expect(executionPermissions).to.have.lengthOf(1); - expect(executionPermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.isEqual(s.Action, ['states:StartSyncExecution'])); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.deep.eq([stateMachineArn]); - 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', - {}, - ], - }]); + const executionPermissions = statements.filter(s => _.isEqual(s.Action, ['states:DescribeExecution', 'states:StopExecution'])); + expect(executionPermissions).to.have.lengthOf(1); + expect(executionPermissions[0].Resource).to.equal('*'); + + 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::Partition}:events:${AWS::Region}:${AWS::AccountId}:rule/StepFunctionsGetEventsForStepFunctionsExecutionRule', + {}, + ], + }]); + }); }); - it('should give step functions permission to * whenever StateMachineArn.$ is seen', () => { - const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution', - Parameters: { - 'StateMachineArn.$': '$.arn', - Input: {}, + describe('should give step functions permission to * whenever StateMachineArn.$ (JSONPath) or {% $arn %} (JSONata) is seen', () => { + it('jsonpath', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Parameters: { + 'StateMachineArn.$': '$.arn', + Input: {}, + }, + Next: 'B', }, - Next: 'B', - }, - B: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.sync', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', }, - Next: 'C', - }, - C: { - Type: 'Task', - Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', - Parameters: { - StateMachineArn: stateMachineArn, - Input: {}, + C: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.waitForTaskToken', + Parameters: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, }, - 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 stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const stateMachineArn = 'arn:aws:states:us-east-1:123456789:stateMachine:HelloStateMachine'; + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution', + Arguments: { + StateMachineArn: '{% $arn %}', + Input: {}, + }, + Next: 'B', + }, + B: { + Type: 'Task', + Resource: 'arn:aws:states:::states:startExecution.sync', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + Next: 'C', + }, + C: { + Type: 'Task', + Resource: + 'arn:aws:states:::states:startExecution.waitForTaskToken', + Arguments: { + StateMachineArn: stateMachineArn, + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service.provider + .compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.equal('*'); + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartExecution')); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); + }); }); - it('should give step functions using sdk permission to * whenever StateMachineArn.$ is seen', () => { - const genStateMachine = id => ({ - id, - definition: { - StartAt: 'A', - States: { - A: { - Type: 'Task', - Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', - Parameters: { - 'StateMachineArn.$': '$.arn', - Input: {}, + describe('should give step functions using sdk permission to * whenever StateMachineArn.$ (JSONPath) or {% $arn %} (JSONata) is seen', () => { + it('jsonpath', () => { + const genStateMachine = id => ({ + id, + definition: { + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Parameters: { + 'StateMachineArn.$': '$.arn', + Input: {}, + }, + End: true, }, - 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 stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); + + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); }); - serverless.service.stepFunctions = { - stateMachines: { - myStateMachine1: genStateMachine('StateMachine1'), - }, - }; + it('jsonata', () => { + const genStateMachine = id => ({ + id, + definition: { + QueryLanguage: 'JSONata', + StartAt: 'A', + States: { + A: { + Type: 'Task', + Resource: 'arn:aws:states:::aws-sdk:sfn:startSyncExecution', + Arguments: { + StateMachineArn: '{% $arn %}', + Input: {}, + }, + End: true, + }, + }, + }, + }); - serverlessStepFunctions.compileIamRole(); - const statements = serverlessStepFunctions.serverless.service - .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role - .Properties.Policies[0].PolicyDocument.Statement; + serverless.service.stepFunctions = { + stateMachines: { + myStateMachine1: genStateMachine('StateMachine1'), + }, + }; + + serverlessStepFunctions.compileIamRole(); + const statements = serverlessStepFunctions.serverless.service + .provider.compiledCloudFormationTemplate.Resources.StateMachine1Role + .Properties.Policies[0].PolicyDocument.Statement; - const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); + const stateMachinePermissions = statements.filter(s => _.includes(s.Action, 'states:StartSyncExecution')); - expect(stateMachinePermissions).to.have.lengthOf(1); - expect(stateMachinePermissions[0].Resource).to.equal('*'); + expect(stateMachinePermissions).to.have.lengthOf(1); + expect(stateMachinePermissions[0].Resource).to.equal('*'); + }); }); it('should support Map state type', () => { From 023ab31f9659778a97193fe0c2a160ff6bc7cdc4 Mon Sep 17 00:00:00 2001 From: zirkelc Date: Wed, 18 Dec 2024 17:54:59 +0100 Subject: [PATCH 4/6] chore: noop --- lib/deploy/stepFunctions/compileIamRole.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index 91588998..c048b3b1 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -3190,7 +3190,7 @@ describe('#compileIamRole', () => { const genStateMachine = id => ({ id, definition: { - QueryLanguage: 'JSONata', + QueryLanguage: 'JSONata', // JSONPath is default StartAt: 'A', States: { A: { From 0f990572c57825a828813cc589817408a69bc4d1 Mon Sep 17 00:00:00 2001 From: zirkelc Date: Thu, 19 Dec 2024 08:33:14 +0100 Subject: [PATCH 5/6] chore: noop --- lib/deploy/stepFunctions/compileIamRole.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index c048b3b1..41556324 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -3084,7 +3084,7 @@ describe('#compileIamRole', () => { const genStateMachine = id => ({ id, definition: { - QueryLanguage: 'JSONata', + QueryLanguage: 'JSONata', // JSONPath is default StartAt: 'A', States: { A: { From d2555b719ab92f7153b729a4156e6350cbbb91de Mon Sep 17 00:00:00 2001 From: zirkelc Date: Thu, 19 Dec 2024 08:36:31 +0100 Subject: [PATCH 6/6] chore: noop --- lib/deploy/stepFunctions/compileIamRole.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/deploy/stepFunctions/compileIamRole.test.js b/lib/deploy/stepFunctions/compileIamRole.test.js index 41556324..d9f76a2b 100644 --- a/lib/deploy/stepFunctions/compileIamRole.test.js +++ b/lib/deploy/stepFunctions/compileIamRole.test.js @@ -2956,7 +2956,7 @@ describe('#compileIamRole', () => { const genStateMachine = id => ({ id, definition: { - QueryLanguage: 'JSONata', + QueryLanguage: 'JSONata', // JSONPath is default StartAt: 'A', States: { A: {