{
  "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": "PassDeployment2a35d33e"
        },
        "StageName": "hookshot",
        "RestApiId": {
          "Ref": "PassApi"
        },
        "MethodSettings": [
          {
            "HttpMethod": "*",
            "ResourcePath": "/*",
            "ThrottlingBurstLimit": 20,
            "ThrottlingRateLimit": 5,
            "LoggingLevel": "INFO",
            "DataTraceEnabled": false,
            "MetricsEnabled": false
          }
        ]
      }
    },
    "PassDeployment2a35d33e": {
      "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": "nodejs18.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": "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": "nodejs18.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": "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"
      }
    }
  }
}