Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
{
Effect: 'Allow',
Principal: { Service: 'lambda.amazonaws.com' },
Action: 'sts:AssumeRole'
}
]
},
Policies: [
{
PolicyName: 'codebuild-status',
PolicyDocument: {
Statement: [
{
Effect: 'Allow',
Action: 'logs:*',
Resource: cf.getAtt('StatusLambdaLogs', 'Arn')
},
{
Effect: 'Allow',
Action: 'codebuild:BatchGetBuilds',
Resource: '*'
},
{
Effect: 'Allow',
Action: 'kms:Decrypt',
Resource: cf.importValue('cloudformation-kms-production')
}
]
}
}
]
}
},
{
Effect: 'Allow',
Action: [
'codebuild:BatchGetProjects',
'codebuild:CreateProject',
'codebuild:StartBuild',
'events:PutRule',
'events:PutTargets'
],
Resource: '*'
},
{
Effect: 'Allow',
Action: 'iam:PassRole',
Resource: cf.getAtt('ProjectRole', 'Arn')
},
{
Effect: 'Allow',
Action: 'kms:Decrypt',
Resource: cf.importValue('cloudformation-kms-production')
},
{
Effect: 'Allow',
Action: [
'logs:CreateLogGroup',
'logs:PutRetentionPolicy'
],
Resource: cf.sub('arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/*')
}
]
}
}
}
]
}
};
Resources[prefixed('ScalingTarget')] = {
Type: 'AWS::ApplicationAutoScaling::ScalableTarget',
Properties: {
ServiceNamespace: 'ecs',
ScalableDimension: 'ecs:service:DesiredCount',
ResourceId: cf.join([
'service/',
options.cluster,
'/',
cf.getAtt(prefixed('Service'), 'Name')
]),
MinCapacity: options.minSize,
MaxCapacity: options.maxSize,
RoleARN: cf.getAtt(prefixed('ScalingRole'), 'Arn')
}
};
Resources[prefixed('ScaleUp')] = {
Type: 'AWS::ApplicationAutoScaling::ScalingPolicy',
Properties: {
ScalingTargetId: cf.ref(prefixed('ScalingTarget')),
PolicyName: cf.sub('${AWS::StackName}-scale-up'),
PolicyType: 'StepScaling',
StepScalingPolicyConfiguration: {
AdjustmentType: 'ChangeInCapacity',
Cooldown: 300,
};
Resources[prefixed('ScalingTarget')] = {
Type: 'AWS::ApplicationAutoScaling::ScalableTarget',
Properties: {
ServiceNamespace: 'ecs',
ScalableDimension: 'ecs:service:DesiredCount',
ResourceId: cf.join([
'service/',
options.cluster,
'/',
cf.getAtt(prefixed('Service'), 'Name')
]),
MinCapacity: options.minSize,
MaxCapacity: options.maxSize,
RoleARN: cf.getAtt(prefixed('ScalingRole'), 'Arn')
}
};
Resources[prefixed('ScaleUp')] = {
Type: 'AWS::ApplicationAutoScaling::ScalingPolicy',
Properties: {
ScalingTargetId: cf.ref(prefixed('ScalingTarget')),
PolicyName: cf.sub('${AWS::StackName}-scale-up'),
PolicyType: 'StepScaling',
StepScalingPolicyConfiguration: {
AdjustmentType: 'ChangeInCapacity',
Cooldown: 300,
MetricAggregationType: 'Average',
StepAdjustments: [
{
ScalingAdjustment: cf.getAtt(prefixed('CustomScalingResource'), 'ScalingAdjustment'),
},
Handler: 'lambda.trigger',
Runtime: 'nodejs6.10',
Timeout: 300,
MemorySize: 512,
Environment: {
Variables: {
GITHUB_APP_ID: cf.ref('GithubAppId'),
GITHUB_APP_INSTALLATION_ID: cf.ref('GithubAppInstallationId'),
GITHUB_APP_PRIVATE_KEY: cf.ref('GithubAppPrivateKey'),
NPM_ACCESS_TOKEN: cf.ref('NpmAccessToken'),
AWS_ACCOUNT_ID: cf.accountId,
S3_BUCKET: cf.sub('${OutputBucketPrefix}-${AWS::Region}'),
S3_PREFIX: cf.ref('OutputKeyPrefix'),
PROJECT_ROLE: cf.getAtt('ProjectRole', 'Arn'),
STATUS_FUNCTION: cf.getAtt('StatusLambda', 'Arn')
}
}
}
},
TriggerLambdaErrorAlarm: {
Type: 'AWS::CloudWatch::Alarm',
Properties: {
AlarmName: cf.sub('${AWS::StackName}-trigger-function-errors'),
Period: 60,
EvaluationPeriods: 1,
Statistic: 'Sum',
Threshold: 0,
ComparisonOperator: 'GreaterThanThreshold',
TreatMissingData: 'notBreaching',
Namespace: 'AWS/Lambda',
Dimensions: [
cf.stackName,
cf.region,
options.prefix.toLowerCase()
]),
RetentionInDays: 14
}
};
if (options.dashboard) {
Resources[prefixed('Dashboard')] = {
Type: 'AWS::CloudWatch::Dashboard',
Properties: {
DashboardName: cf.join('-', [cf.ref('AWS::StackName'), prefixed(''), cf.region]),
DashboardBody: cf.sub(dashboard, {
WatchbotQueue: cf.getAtt(prefixed('Queue'), 'QueueName'),
WatchbotDeadLetterQueue: cf.getAtt(prefixed('DeadLetterQueue'), 'QueueName'),
WatchbotService: cf.getAtt(prefixed('Service'), 'Name'),
Cluster: options.cluster,
Prefix: options.prefix
})
}
};
}
Resources[prefixed('Role')] = {
Type: 'AWS::IAM::Role',
Properties: {
AssumeRolePolicyDocument: {
Statement: [
{
Effect: 'Allow',
Principal: { Service: ['ecs-tasks.amazonaws.com'] },
Action: 'sts:AssumeRole',
Principal: { Service: 'codebuild.amazonaws.com' }
}
]
},
Policies: [
{
PolicyName: cf.sub('BundlerPolicy'),
PolicyDocument: {
Statement: [
{
Effect: 'Allow',
Action: 'logs:*',
Resource: [
cf.getAtt('BundlerLogs', 'Arn'),
cf.getAtt('AlpineBundlerLogs', 'Arn')
]
},
{
Effect: 'Allow',
Action: [
's3:ListBucket',
's3:GetObject',
's3:PutObject',
's3:PutObjectAcl'
],
Resource: [
cf.sub('arn:${AWS::Partition}:s3:::watchbot-binaries'),
cf.sub('arn:${AWS::Partition}:s3:::watchbot-binaries/*')
]
}
]
Namespace: 'AWS/ECS',
MetricName: 'MemoryUtilization',
ComparisonOperator: 'GreaterThanThreshold',
Threshold: 100,
EvaluationPeriods: 10,
Statistic: 'Average',
Period: 60,
AlarmActions: [notify],
Dimensions: [
{
Name: 'ClusterName',
Value: options.cluster
},
{
Name: 'ServiceName',
Value: cf.getAtt(prefixed('Service'), 'Name')
}
]
}
};
Resources[prefixed('LambdaScalingRole')] = {
Type: 'AWS::IAM::Role',
Properties: {
AssumeRolePolicyDocument: {
Statement: [
{
Effect: 'Allow',
Principal: { Service: ['lambda.amazonaws.com'] },
Action: ['sts:AssumeRole']
}
]
TargetPipelineVersion: cf.getAtt('Pipeline', 'Version'),
TargetAction: 'GitHub',
Filters: [
{
JsonPath: '$.ref',
MatchEquals: 'refs/heads/{Branch}'
}
],
RegisterWithThirdParty: true
}
},
Pipeline: {
Type: 'AWS::CodePipeline::Pipeline',
Properties: {
Name: cf.stackName,
RoleArn: cf.getAtt('PipelineRole', 'Arn'),
ArtifactStore: {
Type: 'S3',
Location: 'watchbot-binaries'
},
Stages: [
{
Name: 'Source',
Actions: [
{
Name: 'GitHub',
ActionTypeId: {
Category: 'Source',
Owner: 'ThirdParty',
Version: '1',
Provider: 'GitHub'
},