Skip to content

Commit b7968a5

Browse files
feat: intrinsic function in compile role
1 parent cddad0d commit b7968a5

File tree

5 files changed

+99
-8
lines changed

5 files changed

+99
-8
lines changed

lib/deploy/stepFunctions/compileIamRole.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const _ = require('lodash');
33
const BbPromise = require('bluebird');
44
const path = require('path');
5+
const { isIntrinsic } = require('../../utils/aws');
56

67
function getTaskStates(states) {
78
return _.flatMap(states, state => {
@@ -28,6 +29,12 @@ function sqsQueueUrlToArn(serverless, queueUrl) {
2829
const accountId = match[2];
2930
const queueName = match[3];
3031
return `arn:aws:sqs:${region}:${accountId}:${queueName}`;
32+
} else if (isIntrinsic(queueUrl) && queueUrl.Ref) {
33+
// most likely we'll see a { Ref: LogicalId }, which we need to map to
34+
// { Fn::GetAtt: [ LogicalId, Arn ] } to get the ARN
35+
return {
36+
'Fn::GetAtt': [queueUrl.Ref, 'Arn'],
37+
};
3138
}
3239
serverless.cli.consoleLog(`Unable to parse SQS queue url [${queueUrl}]`);
3340
return [];
@@ -197,7 +204,7 @@ function getIamPermissions(serverless, taskStates) {
197204
return getEcsPermissions();
198205

199206
default:
200-
if (state.Resource.startsWith('arn:aws:lambda')) {
207+
if (isIntrinsic(state.Resource) || state.Resource.startsWith('arn:aws:lambda')) {
201208
return [{
202209
action: 'lambda:InvokeFunction',
203210
resource: state.Resource,

lib/deploy/stepFunctions/compileIamRole.test.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,4 +900,85 @@ describe('#compileIamRole', () => {
900900
.Properties.Policies[0];
901901
expectDenyAllPolicy(policy);
902902
});
903+
904+
it('should respect CloudFormation intrinsic functions for Resource', () => {
905+
serverless.service.stepFunctions = {
906+
stateMachines: {
907+
myStateMachine: {
908+
name: 'stateMachine',
909+
definition: {
910+
StartAt: 'Lambda',
911+
States: {
912+
Lambda: {
913+
Type: 'Task',
914+
Resource: {
915+
Ref: 'MyFunction',
916+
},
917+
Next: 'Sns',
918+
},
919+
Sns: {
920+
Type: 'Task',
921+
Resource: 'arn:aws:states:::sns:publish',
922+
Parameters: {
923+
Message: {
924+
'Fn::GetAtt': ['MyTopic', 'TopicName'],
925+
},
926+
TopicArn: {
927+
Ref: 'MyTopic',
928+
},
929+
},
930+
Next: 'Sqs',
931+
},
932+
Sqs: {
933+
Type: 'Task',
934+
Resource: 'arn:aws:states:::sqs:sendMessage',
935+
Parameters: {
936+
QueueUrl: {
937+
Ref: 'MyQueue',
938+
},
939+
MessageBody: 'This is a static message',
940+
},
941+
Next: 'Parallel',
942+
},
943+
Parallel: {
944+
Type: 'Parallel',
945+
End: true,
946+
Branches: [
947+
{
948+
StartAt: 'Lambda2',
949+
States: {
950+
Lambda2: {
951+
Type: 'Task',
952+
Resource: {
953+
Ref: 'MyFunction2',
954+
},
955+
End: true,
956+
},
957+
},
958+
},
959+
],
960+
},
961+
},
962+
},
963+
},
964+
},
965+
};
966+
967+
serverlessStepFunctions.compileIamRole();
968+
serverlessStepFunctions.compileStateMachines();
969+
const policy = serverlessStepFunctions.serverless.service
970+
.provider.compiledCloudFormationTemplate.Resources.IamRoleStateMachineExecution
971+
.Properties.Policies[0];
972+
973+
const statements = policy.PolicyDocument.Statement;
974+
const lambdaPermissions = statements.find(x => x.Action[0] === 'lambda:InvokeFunction');
975+
expect(lambdaPermissions.Resource).to.be.deep.equal([
976+
{ Ref: 'MyFunction' }, { Ref: 'MyFunction2' }]);
977+
const snsPermissions = statements.find(x => x.Action[0] === 'sns:Publish');
978+
expect(snsPermissions.Resource).to.be.deep.equal([{ Ref: 'MyTopic' }]);
979+
const sqsPermissions = statements.find(x => x.Action[0] === 'sqs:SendMessage');
980+
expect(sqsPermissions.Resource).to.be.deep.equal([{
981+
'Fn::GetAtt': ['MyQueue', 'Arn'],
982+
}]);
983+
});
903984
});

lib/deploy/stepFunctions/compileStateMachines.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
'use strict';
22
const _ = require('lodash');
33
const BbPromise = require('bluebird');
4+
const { isIntrinsic } = require('../../utils/aws');
45

56
function randomName() {
67
const chars = 'abcdefghijklmnopqrstufwxyzABCDEFGHIJKLMNOPQRSTUFWXYZ1234567890';
78
const pwd = _.sampleSize(chars, 10);
89
return pwd.join('');
910
}
1011

11-
function isIntrinsic(obj) {
12-
return typeof obj === 'object' &&
13-
Object.keys(obj).some((k) => k.startsWith('Fn::') || k.startsWith('Ref'));
14-
}
15-
1612
function toTags(obj, serverless) {
1713
const tags = [];
1814

@@ -66,7 +62,6 @@ function* getIntrinsicFunctions(obj) {
6662
}
6763

6864
module.exports = {
69-
isIntrinsic,
7065
compileStateMachines() {
7166
if (this.isStateMachines()) {
7267
this.getAllStateMachines().forEach((stateMachineName) => {

lib/deploy/stepFunctions/compileStateMachines.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ describe('#compileStateMachines', () => {
608608
expect(() => serverlessStepFunctions.compileStateMachines()).to.throw(Error);
609609
});
610610

611-
it('should respect CloudFormation intrinsic functions for Resource', () => {
611+
it('should respect CloudFormation intrinsic functions', () => {
612612
serverless.service.stepFunctions = {
613613
stateMachines: {
614614
myStateMachine: {

lib/utils/aws.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function isIntrinsic(obj) {
2+
return typeof obj === 'object' &&
3+
Object.keys(obj).some((k) => k.startsWith('Fn::') || k.startsWith('Ref'));
4+
}
5+
6+
module.exports = {
7+
isIntrinsic,
8+
};

0 commit comments

Comments
 (0)