Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/deploy/events/apiGateway/iamRole.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ module.exports = {
};


const rolePath = _.get(this.serverless.service, 'provider.iam.role.path');
if (rolePath) {
iamRoleApiGatewayToStepFunctions.Properties.Path = rolePath;
}

const getApiToStepFunctionsIamRoleLogicalId = this.getApiToStepFunctionsIamRoleLogicalId();
const newIamRoleStateMachineExecutionObject = {
[getApiToStepFunctionsIamRoleLogicalId]: iamRoleApiGatewayToStepFunctions,
Expand Down
21 changes: 21 additions & 0 deletions lib/deploy/events/apiGateway/iamRole.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,25 @@ describe('#compileHttpIamRole()', () => {
.to.deep.equal(['states:StartExecution']);
});
});

it('should apply provider.iam.role.path to API Gateway IAM role', () => {
serverlessStepFunctions.pluginhttpValidated = {
events: [
{
stateMachineName: 'first',
http: {
path: 'foo/bar1',
method: 'post',
},
},
],
};
serverless.service.provider.iam = { role: { path: '/teamA/' } };

return serverlessStepFunctions.compileHttpIamRole().then(() => {
const properties = serverlessStepFunctions.serverless.service.provider
.compiledCloudFormationTemplate.Resources.ApigatewayToStepFunctionsRole.Properties;
expect(properties.Path).to.equal('/teamA/');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ module.exports = {
}
`;

const iamRoleTemplate = `
let iamRoleTemplate = `
{
"Type": "AWS::IAM::Role",
"Properties": {
Expand Down Expand Up @@ -174,6 +174,13 @@ module.exports = {
const objectsToMerge = [newCloudWatchEventRuleObject];

if (!IamRole) {
const rolePath = _.get(this.serverless.service, 'provider.iam.role.path');
if (rolePath) {
const jsonIamRole = JSON.parse(iamRoleTemplate);
jsonIamRole.Properties.Path = rolePath;
iamRoleTemplate = JSON.stringify(jsonIamRole);
}

const newPermissionObject = {
[cloudWatchIamRoleLogicalId]: JSON.parse(iamRoleTemplate),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,35 @@ describe('awsCompileCloudWatchEventEvents', () => {
.Properties.Targets[0].RoleArn).to.equal('{"Fn::GetAtt": ["StepFunctionsRole", "Arn"]}');
});

it('should apply provider.iam.role.path to CloudWatch event IAM role', () => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
first: {
events: [
{
cloudwatchEvent: {
event: {
source: ['aws.ec2'],
'detail-type': ['EC2 Instance State-change Notification'],
detail: { state: ['pending'] },
},
enabled: false,
},
},
],
},
},
};
serverless.service.provider.iam = { role: { path: '/teamA/' } };

serverlessStepFunctions.compileCloudWatchEventEvents();

expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstEventToStepFunctionsRole
.Properties.Path).to.equal('/teamA/');
});

it('should not create corresponding resources when events are not given', () => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
Expand Down
7 changes: 7 additions & 0 deletions lib/deploy/events/schedule/compileScheduledEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,13 @@ module.exports = {
iamRoleTemplate = JSON.stringify(jsonIamRole);
}

const rolePath = _.get(service, 'provider.iam.role.path');
if (rolePath) {
const jsonIamRole = JSON.parse(iamRoleTemplate);
jsonIamRole.Properties.Path = rolePath;
iamRoleTemplate = JSON.stringify(jsonIamRole);
}

const newScheduleObject = {
[scheduleLogicalId]: JSON.parse(scheduleTemplate),
};
Expand Down
25 changes: 25 additions & 0 deletions lib/deploy/events/schedule/compileScheduledEvents.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,31 @@ describe('#httpValidate()', () => {
.Properties.PermissionsBoundary).to.equal('arn:aws:iam::myAccount:policy/permission_boundary');
});

it('should handle provider.iam.role.path', () => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
first: {
events: [
{
schedule: {
rate: 'rate(10 minutes)',
enabled: false,
inputPath: '$.stageVariables',
},
},
],
},
},
};
serverless.service.provider.iam = { role: { path: '/teamA/' } };
serverlessStepFunctions.compileScheduledEvents();

expect(serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources
.FirstScheduleToStepFunctionsRole
.Properties.Path).to.equal('/teamA/');
});

it('should have type of AWS::Scheduler::Schedule if method is scheduler', () => {
serverlessStepFunctions.serverless.service.stepFunctions = {
stateMachines: {
Expand Down
7 changes: 7 additions & 0 deletions lib/deploy/stepFunctions/compileIamRole.js
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,13 @@ module.exports = {
iamRoleJson = JSON.stringify(jsonIamRole);
}

const rolePath = _.get(service, 'provider.iam.role.path');
if (rolePath) {
const jsonIamRole = JSON.parse(iamRoleJson);
jsonIamRole.Properties.Path = rolePath;
iamRoleJson = JSON.stringify(jsonIamRole);
}

const stateMachineLogicalId = this.getStateMachineLogicalId(
stateMachineId,
stateMachineObj,
Expand Down
27 changes: 27 additions & 0 deletions lib/deploy/stepFunctions/compileIamRole.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4425,6 +4425,33 @@ describe('#compileIamRole', () => {
expect(boundary).to.equal('arn:aws:iam::myAccount:policy/permission_boundary');
});

it('should handle provider.iam.role.path', () => {
serverless.service.stepFunctions = {
stateMachines: {
myStateMachine1: {
id: 'StateMachine1',
definition: {
StartAt: 'A',
States: {
A: {
Type: 'Task',
Resource:
'arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function:hello',
End: true,
},
},
},
},
},
};
serverless.service.provider.iam = { role: { path: '/teamA/' } };
serverlessStepFunctions.compileIamRole();
const rolePath = serverlessStepFunctions.serverless.service.provider
.compiledCloudFormationTemplate.Resources.StateMachine1Role.Properties
.Path;
expect(rolePath).to.equal('/teamA/');
});

it('should handle permissions listObjectsV2', () => {
const myBucket = 'myBucket';
serverless.service.stepFunctions = {
Expand Down
13 changes: 8 additions & 5 deletions lib/deploy/stepFunctions/compileNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ function compilePermissionForTarget(status, targetObj) {
};
}

function bootstrapIamRole() {
function bootstrapIamRole(rolePath) {
const iamRole = {
Type: 'AWS::IAM::Role',
Properties: {
Expand All @@ -215,6 +215,7 @@ function bootstrapIamRole() {
},
},
Policies: [],
...(rolePath && { Path: rolePath }),
},
};
const addPolicy = (name, action, resource) => {
Expand All @@ -234,8 +235,8 @@ function bootstrapIamRole() {
return { iamRole, addPolicy };
}

function* compilePermissionResources(stateMachineLogicalId, iamRoleLogicalId, targets) {
const { iamRole, addPolicy } = bootstrapIamRole();
function* compilePermissionResources(stateMachineLogicalId, iamRoleLogicalId, targets, rolePath) {
const { iamRole, addPolicy } = bootstrapIamRole(rolePath);

for (let index = 0; index < targets.length; index++) {
const { status, target } = targets[index];
Expand Down Expand Up @@ -263,12 +264,12 @@ function* compilePermissionResources(stateMachineLogicalId, iamRoleLogicalId, ta
}
}

function* compileResources(stateMachineLogicalId, stateMachineName, notificationsObj) {
function* compileResources(stateMachineLogicalId, stateMachineName, notificationsObj, rolePath) {
const iamRoleLogicalId = `${stateMachineLogicalId}NotificationsIamRole`;
const allTargets = _.flatMap(executionStatuses, status => _.get(notificationsObj,
status, []).map(target => ({ status, target })));
const permissions = compilePermissionResources(
stateMachineLogicalId, iamRoleLogicalId, allTargets,
stateMachineLogicalId, iamRoleLogicalId, allTargets, rolePath,
);
const permissionResources = Array.from(permissions);
for (const { logicalId, resource } of permissionResources) {
Expand Down Expand Up @@ -354,10 +355,12 @@ module.exports = {
return [];
}

const rolePath = _.get(this.serverless.service, 'provider.iam.role.path');
const resourcesIterator = compileResources(
stateMachineLogicalId,
stateMachineName,
notificationsObj,
rolePath,
);

return Array.from(resourcesIterator);
Expand Down
15 changes: 15 additions & 0 deletions lib/deploy/stepFunctions/compileNotifications.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,19 @@ describe('#compileNotifications', () => {
expect(logMessage.startsWith('State machine [Beta1] : notifications are not supported on Express Workflows.'))
.to.equal(true);
});

it('should apply provider.iam.role.path to notifications IAM role', () => {
serverless.service.stepFunctions = {
stateMachines: {
beta1: genStateMachineWithTargets('Beta1', [{ stepFunctions: 'STATE_MACHINE_ARN' }]),
},
};
serverless.service.provider.iam = { role: { path: '/teamA/' } };

serverlessStepFunctions.compileNotifications();
const resources = serverlessStepFunctions.serverless.service
.provider.compiledCloudFormationTemplate.Resources;

expect(resources.Beta1NotificationsIamRole.Properties.Path).to.equal('/teamA/');
});
});
Loading