UNPKG

@mapbox/cloudfriend

Version:

Helper functions for assembling CloudFormation templates in JavaScript

411 lines 11.6 kB
{ "AWSTemplateFormatVersion": "2010-09-09", "Metadata": {}, "Parameters": {}, "Rules": {}, "Mappings": {}, "Conditions": {}, "Resources": { "PassApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { "Name": { "Fn::Sub": "${AWS::StackName}-webhook" }, "FailOnWarnings": true, "EndpointConfiguration": { "Types": [ "REGIONAL" ] } } }, "PassStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { "Ref": "PassDeploymentbdbc0f16" }, "StageName": "hookshot", "RestApiId": { "Ref": "PassApi" }, "MethodSettings": [ { "HttpMethod": "*", "ResourcePath": "/*", "ThrottlingBurstLimit": 20, "ThrottlingRateLimit": 5, "LoggingLevel": "OFF", "DataTraceEnabled": false, "MetricsEnabled": false } ] } }, "PassDeploymentbdbc0f16": { "Type": "AWS::ApiGateway::Deployment", "DependsOn": "PassMethod", "Properties": { "RestApiId": { "Ref": "PassApi" }, "StageName": "unused" } }, "PassResource": { "Type": "AWS::ApiGateway::Resource", "Properties": { "ParentId": { "Fn::GetAtt": [ "PassApi", "RootResourceId" ] }, "RestApiId": { "Ref": "PassApi" }, "PathPart": "webhook" } }, "PassOptionsMethod": { "Type": "AWS::ApiGateway::Method", "Properties": { "RestApiId": { "Ref": "PassApi" }, "ResourceId": { "Ref": "PassResource" }, "ApiKeyRequired": false, "AuthorizationType": "NONE", "HttpMethod": "OPTIONS", "Integration": { "Type": "AWS_PROXY", "IntegrationHttpMethod": "POST", "Uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PassFunction.Arn}/invocations" } } } }, "PassMethod": { "Type": "AWS::ApiGateway::Method", "Properties": { "RestApiId": { "Ref": "PassApi" }, "ResourceId": { "Ref": "PassResource" }, "ApiKeyRequired": false, "AuthorizationType": "NONE", "HttpMethod": "POST", "Integration": { "Type": "AWS_PROXY", "IntegrationHttpMethod": "POST", "Uri": { "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PassFunction.Arn}/invocations" } } } }, "PassPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "FunctionName": { "Ref": "PassFunction" }, "Action": "lambda:InvokeFunction", "Principal": "apigateway.amazonaws.com", "SourceArn": { "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PassApi}/*" } } }, "PassSecret": { "Type": "AWS::ApiGateway::ApiKey", "Properties": { "Enabled": false } }, "PassFunctionLogs": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": { "Fn::Sub": [ "/aws/lambda/${name}", { "name": { "Fn::Sub": "${AWS::StackName}-Pass" } } ] }, "RetentionInDays": 14 } }, "PassFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "ZipFile": { "Fn::Sub": "'use strict';\n\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\n\nmodule.exports.lambda = (event, context, callback) => {\n if (event.httpMethod === 'OPTIONS') {\n const requestHeaders = event.headers['Access-Control-Request-Headers'] || event.headers['access-control-request-headers'];\n const response = {\n statusCode: 200,\n body: '',\n headers: {\n 'Access-Control-Allow-Headers': requestHeaders,\n 'Access-Control-Allow-Methods': 'POST, OPTIONS',\n 'Access-Control-Allow-Origin': '*'\n }\n };\n return callback(null, response);\n }\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event)\n });\n\n client.send(command)\n .then((response) => {\n if (!response || !response.Payload)\n return callback(new Error('Your Lambda function Destination did not provide a payload'));\n\n var payload = JSON.parse(Buffer.from(response.Payload).toString());\n payload.headers = payload.headers || {};\n payload.headers['Access-Control-Allow-Origin'] = '*';\n callback(null, payload);\n })\n .catch((err) => callback(err));\n};" } }, "Description": { "Fn::Sub": "Passthrough function for ${AWS::StackName}" }, "FunctionName": { "Fn::Sub": "${AWS::StackName}-Pass" }, "Handler": "index.lambda", "MemorySize": 128, "Runtime": "nodejs22.x", "Timeout": 30, "Role": { "Fn::GetAtt": [ "PassFunctionRole", "Arn" ] } } }, "PassFunctionErrorAlarm": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "AlarmName": { "Fn::Sub": "${AWS::StackName}-PassFunction-Errors-${AWS::Region}" }, "AlarmDescription": { "Fn::Sub": [ "Error alarm for ${name} lambda function in ${AWS::StackName} stack", { "name": { "Fn::Sub": "${AWS::StackName}-Pass" } } ] }, "AlarmActions": [], "Period": 60, "EvaluationPeriods": 1, "DatapointsToAlarm": 1, "Statistic": "Sum", "Threshold": 0, "ComparisonOperator": "GreaterThanThreshold", "TreatMissingData": "notBreaching", "Namespace": "AWS/Lambda", "Dimensions": [ { "Name": "FunctionName", "Value": { "Ref": "PassFunction" } } ], "MetricName": "Errors" } }, "PassFunctionLogPolicy": { "Type": "AWS::IAM::Policy", "DependsOn": "PassFunctionRole", "Properties": { "PolicyName": "PassFunction-lambda-log-access", "Roles": [ { "Ref": "PassFunctionRole" } ], "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:*", "Resource": { "Fn::GetAtt": [ "PassFunctionLogs", "Arn" ] } } ] } } }, "PassFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Principal": { "Service": { "Fn::Sub": "lambda.amazonaws.com" } } } ] }, "Policies": [ { "PolicyName": "main", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": { "Fn::GetAtt": [ "Destination", "Arn" ] } } ] } } ] } }, "DestinationLogs": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": { "Fn::Sub": [ "/aws/lambda/${name}", { "name": { "Fn::Sub": "${AWS::StackName}-Destination" } } ] }, "RetentionInDays": 14 } }, "Destination": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "ZipFile": "module.exports.handler = (e, c, cb) => cb();" }, "Description": { "Fn::Sub": "Destination in the ${AWS::StackName} stack" }, "FunctionName": { "Fn::Sub": "${AWS::StackName}-Destination" }, "Handler": "index.handler", "MemorySize": 128, "Runtime": "nodejs22.x", "Timeout": 300, "Role": { "Fn::GetAtt": [ "DestinationRole", "Arn" ] } } }, "DestinationErrorAlarm": { "Type": "AWS::CloudWatch::Alarm", "Properties": { "AlarmName": { "Fn::Sub": "${AWS::StackName}-Destination-Errors-${AWS::Region}" }, "AlarmDescription": { "Fn::Sub": [ "Error alarm for ${name} lambda function in ${AWS::StackName} stack", { "name": { "Fn::Sub": "${AWS::StackName}-Destination" } } ] }, "AlarmActions": [], "Period": 60, "EvaluationPeriods": 5, "DatapointsToAlarm": 1, "Statistic": "Sum", "Threshold": 0, "ComparisonOperator": "GreaterThanThreshold", "TreatMissingData": "notBreaching", "Namespace": "AWS/Lambda", "Dimensions": [ { "Name": "FunctionName", "Value": { "Ref": "Destination" } } ], "MetricName": "Errors" } }, "DestinationLogPolicy": { "Type": "AWS::IAM::Policy", "DependsOn": "DestinationRole", "Properties": { "PolicyName": "Destination-lambda-log-access", "Roles": [ { "Ref": "DestinationRole" } ], "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:*", "Resource": { "Fn::GetAtt": [ "DestinationLogs", "Arn" ] } } ] } } }, "DestinationRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Principal": { "Service": { "Fn::Sub": "lambda.amazonaws.com" } } } ] } } } }, "Outputs": { "PassEndpointOutput": { "Description": "The HTTPS endpoint used to send github webhooks", "Value": { "Fn::Sub": "https://${PassApi}.execute-api.${AWS::Region}.amazonaws.com/hookshot/webhook" } }, "PassSecretOutput": { "Description": "A secret key to give Github to use when signing webhook requests", "Value": { "Ref": "PassSecret" } } } }