@mapbox/cloudfriend 7.0.0 → 7.0.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nyc_output/5173def1-e652-48eb-b821-68e4c28e98bf.json +1 -0
- package/.nyc_output/da9b250c-7fe3-4849-a7b9-5dcb7ad608aa.json +1 -0
- package/.nyc_output/processinfo/{2c9b3698-f822-47f6-a941-eea13e638ffc.json → 5173def1-e652-48eb-b821-68e4c28e98bf.json} +1 -1
- package/.nyc_output/processinfo/{1983e39b-fcbb-4618-a9dd-36f2ec3b1532.json → da9b250c-7fe3-4849-a7b9-5dcb7ad608aa.json} +1 -1
- package/.nyc_output/processinfo/index.json +1 -1
- package/lib/shortcuts/hookshot.js +23 -12
- package/package.json +1 -1
- package/test/fixtures/shortcuts/hookshot-github-compatible-legacy-node-runtimes.json +423 -0
- package/test/fixtures/shortcuts/hookshot-github-secret-ref.json +3 -3
- package/test/fixtures/shortcuts/hookshot-github-secret-string.json +3 -3
- package/test/fixtures/shortcuts/hookshot-github.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough-access-log-format.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough-alarms.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough-compatible-legacy-node-runtimes.json +411 -0
- package/test/fixtures/shortcuts/hookshot-passthrough-enhanced-logging.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough-full-blown-logging.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough-logging.json +3 -3
- package/test/fixtures/shortcuts/hookshot-passthrough.json +3 -3
- package/test/shortcuts.test.js +46 -0
- package/.nyc_output/1983e39b-fcbb-4618-a9dd-36f2ec3b1532.json +0 -1
- package/.nyc_output/2c9b3698-f822-47f6-a941-eea13e638ffc.json +0 -1
|
@@ -7,6 +7,16 @@ const merge = require('../merge');
|
|
|
7
7
|
|
|
8
8
|
const random = crypto.randomBytes(4).toString('hex');
|
|
9
9
|
|
|
10
|
+
function assertNodeVersion(runtime) {
|
|
11
|
+
if (runtime.match(/^nodejs[\d+]+.x$/)) {
|
|
12
|
+
const version = runtime.match(/\d+/)[0];
|
|
13
|
+
if (Number(version) < 18)
|
|
14
|
+
throw new Error(`Only nodejs runtimes >= 18 are supported for hookshot lambdas, received: '${runtime}'`);
|
|
15
|
+
} else {
|
|
16
|
+
throw new Error(`Only valid nodejs runtimes are supported for hookshot lambdas, received: '${runtime}'`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
/**
|
|
11
21
|
* The hookshot.Passthrough class defines resources that set up a single API Gateway
|
|
12
22
|
* endpoint that responds to `POST` and `OPTIONS` requests. You are expected to
|
|
@@ -86,6 +96,8 @@ class Passthrough {
|
|
|
86
96
|
WebhookSecret
|
|
87
97
|
} = options;
|
|
88
98
|
|
|
99
|
+
if (options.Runtime) assertNodeVersion(options.Runtime);
|
|
100
|
+
|
|
89
101
|
let {
|
|
90
102
|
LoggingLevel = 'OFF'
|
|
91
103
|
} = options;
|
|
@@ -260,10 +272,9 @@ class Passthrough {
|
|
|
260
272
|
code() {
|
|
261
273
|
return {
|
|
262
274
|
'Fn::Sub': redent(`
|
|
263
|
-
'use strict';
|
|
264
275
|
|
|
265
|
-
const
|
|
266
|
-
const
|
|
276
|
+
const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');
|
|
277
|
+
const client = new LambdaClient();
|
|
267
278
|
|
|
268
279
|
module.exports.lambda = (event, context, callback) => {
|
|
269
280
|
if (event.httpMethod === 'OPTIONS') {
|
|
@@ -280,17 +291,17 @@ class Passthrough {
|
|
|
280
291
|
return callback(null, response);
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
const
|
|
294
|
+
const command = new InvokeCommand({
|
|
284
295
|
FunctionName: '\${${this.PassthroughTo}}',
|
|
285
296
|
Payload: JSON.stringify(event)
|
|
286
|
-
};
|
|
297
|
+
});
|
|
287
298
|
|
|
288
|
-
|
|
299
|
+
client.send(command)
|
|
289
300
|
.then((response) => {
|
|
290
301
|
if (!response || !response.Payload)
|
|
291
302
|
return callback(new Error('Your Lambda function ${this.PassthroughTo} did not provide a payload'));
|
|
292
303
|
|
|
293
|
-
var payload = JSON.parse(response.Payload);
|
|
304
|
+
var payload = JSON.parse(Buffer.from(response.Payload).toString());
|
|
294
305
|
payload.headers = payload.headers || {};
|
|
295
306
|
payload.headers['Access-Control-Allow-Origin'] = '*';
|
|
296
307
|
callback(null, payload);
|
|
@@ -420,8 +431,8 @@ class Github extends Passthrough {
|
|
|
420
431
|
'use strict';
|
|
421
432
|
|
|
422
433
|
const crypto = require('crypto');
|
|
423
|
-
const
|
|
424
|
-
const
|
|
434
|
+
const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');
|
|
435
|
+
const client = new LambdaClient();
|
|
425
436
|
const secret = '\${WebhookSecret}';
|
|
426
437
|
|
|
427
438
|
module.exports.lambda = (event, context, callback) => {
|
|
@@ -436,13 +447,13 @@ class Github extends Passthrough {
|
|
|
436
447
|
|
|
437
448
|
if (body.zen) return callback(null, 'ignored ping request');
|
|
438
449
|
|
|
439
|
-
const
|
|
450
|
+
const command = new InvokeCommand({
|
|
440
451
|
FunctionName: '\${${this.PassthroughTo}}',
|
|
441
452
|
Payload: JSON.stringify(event.body),
|
|
442
453
|
InvocationType: 'Event'
|
|
443
|
-
};
|
|
454
|
+
});
|
|
444
455
|
|
|
445
|
-
|
|
456
|
+
client.send(command)
|
|
446
457
|
.then(() => callback(null, 'success'))
|
|
447
458
|
.catch((err) => callback(err));
|
|
448
459
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
{
|
|
2
|
+
"AWSTemplateFormatVersion": "2010-09-09",
|
|
3
|
+
"Metadata": {},
|
|
4
|
+
"Parameters": {},
|
|
5
|
+
"Rules": {},
|
|
6
|
+
"Mappings": {},
|
|
7
|
+
"Conditions": {},
|
|
8
|
+
"Resources": {
|
|
9
|
+
"PassApi": {
|
|
10
|
+
"Type": "AWS::ApiGateway::RestApi",
|
|
11
|
+
"Properties": {
|
|
12
|
+
"Name": {
|
|
13
|
+
"Fn::Sub": "${AWS::StackName}-webhook"
|
|
14
|
+
},
|
|
15
|
+
"FailOnWarnings": true,
|
|
16
|
+
"EndpointConfiguration": {
|
|
17
|
+
"Types": [
|
|
18
|
+
"REGIONAL"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"PassStage": {
|
|
24
|
+
"Type": "AWS::ApiGateway::Stage",
|
|
25
|
+
"Properties": {
|
|
26
|
+
"DeploymentId": {
|
|
27
|
+
"Ref": "PassDeployment5dcf4ca7"
|
|
28
|
+
},
|
|
29
|
+
"StageName": "hookshot",
|
|
30
|
+
"RestApiId": {
|
|
31
|
+
"Ref": "PassApi"
|
|
32
|
+
},
|
|
33
|
+
"MethodSettings": [
|
|
34
|
+
{
|
|
35
|
+
"HttpMethod": "*",
|
|
36
|
+
"ResourcePath": "/*",
|
|
37
|
+
"ThrottlingBurstLimit": 20,
|
|
38
|
+
"ThrottlingRateLimit": 5,
|
|
39
|
+
"LoggingLevel": "OFF",
|
|
40
|
+
"DataTraceEnabled": false,
|
|
41
|
+
"MetricsEnabled": false
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"PassDeployment5dcf4ca7": {
|
|
47
|
+
"Type": "AWS::ApiGateway::Deployment",
|
|
48
|
+
"DependsOn": "PassMethod",
|
|
49
|
+
"Properties": {
|
|
50
|
+
"RestApiId": {
|
|
51
|
+
"Ref": "PassApi"
|
|
52
|
+
},
|
|
53
|
+
"StageName": "unused"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"PassResource": {
|
|
57
|
+
"Type": "AWS::ApiGateway::Resource",
|
|
58
|
+
"Properties": {
|
|
59
|
+
"ParentId": {
|
|
60
|
+
"Fn::GetAtt": [
|
|
61
|
+
"PassApi",
|
|
62
|
+
"RootResourceId"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"RestApiId": {
|
|
66
|
+
"Ref": "PassApi"
|
|
67
|
+
},
|
|
68
|
+
"PathPart": "webhook"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"PassMethod": {
|
|
72
|
+
"Type": "AWS::ApiGateway::Method",
|
|
73
|
+
"Properties": {
|
|
74
|
+
"RestApiId": {
|
|
75
|
+
"Ref": "PassApi"
|
|
76
|
+
},
|
|
77
|
+
"ResourceId": {
|
|
78
|
+
"Ref": "PassResource"
|
|
79
|
+
},
|
|
80
|
+
"ApiKeyRequired": false,
|
|
81
|
+
"AuthorizationType": "NONE",
|
|
82
|
+
"HttpMethod": "POST",
|
|
83
|
+
"Integration": {
|
|
84
|
+
"Type": "AWS",
|
|
85
|
+
"IntegrationHttpMethod": "POST",
|
|
86
|
+
"IntegrationResponses": [
|
|
87
|
+
{
|
|
88
|
+
"StatusCode": "200"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"StatusCode": "500",
|
|
92
|
+
"SelectionPattern": "^error.*"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"StatusCode": "403",
|
|
96
|
+
"SelectionPattern": "^invalid.*"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"Uri": {
|
|
100
|
+
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PassFunction.Arn}/invocations"
|
|
101
|
+
},
|
|
102
|
+
"RequestTemplates": {
|
|
103
|
+
"application/json": "{\"signature\":\"$input.params('X-Hub-Signature')\",\"body\":$input.json('$')}"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"MethodResponses": [
|
|
107
|
+
{
|
|
108
|
+
"StatusCode": "200",
|
|
109
|
+
"ResponseModels": {
|
|
110
|
+
"application/json": "Empty"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"StatusCode": "500",
|
|
115
|
+
"ResponseModels": {
|
|
116
|
+
"application/json": "Empty"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"StatusCode": "403",
|
|
121
|
+
"ResponseModels": {
|
|
122
|
+
"application/json": "Empty"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"PassPermission": {
|
|
129
|
+
"Type": "AWS::Lambda::Permission",
|
|
130
|
+
"Properties": {
|
|
131
|
+
"FunctionName": {
|
|
132
|
+
"Ref": "PassFunction"
|
|
133
|
+
},
|
|
134
|
+
"Action": "lambda:InvokeFunction",
|
|
135
|
+
"Principal": "apigateway.amazonaws.com",
|
|
136
|
+
"SourceArn": {
|
|
137
|
+
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PassApi}/*"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"PassFunctionLogs": {
|
|
142
|
+
"Type": "AWS::Logs::LogGroup",
|
|
143
|
+
"Properties": {
|
|
144
|
+
"LogGroupName": {
|
|
145
|
+
"Fn::Sub": [
|
|
146
|
+
"/aws/lambda/${name}",
|
|
147
|
+
{
|
|
148
|
+
"name": {
|
|
149
|
+
"Fn::Sub": "${AWS::StackName}-Pass"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
"RetentionInDays": 14
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"PassFunction": {
|
|
158
|
+
"Type": "AWS::Lambda::Function",
|
|
159
|
+
"Properties": {
|
|
160
|
+
"Code": {
|
|
161
|
+
"ZipFile": {
|
|
162
|
+
"Fn::Sub": [
|
|
163
|
+
"'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
|
|
164
|
+
{
|
|
165
|
+
"WebhookSecret": "abc123"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"Description": {
|
|
171
|
+
"Fn::Sub": "Passthrough function for ${AWS::StackName}"
|
|
172
|
+
},
|
|
173
|
+
"FunctionName": {
|
|
174
|
+
"Fn::Sub": "${AWS::StackName}-Pass"
|
|
175
|
+
},
|
|
176
|
+
"Handler": "index.lambda",
|
|
177
|
+
"MemorySize": 128,
|
|
178
|
+
"Runtime": "nodejs16.x",
|
|
179
|
+
"Timeout": 30,
|
|
180
|
+
"Role": {
|
|
181
|
+
"Fn::GetAtt": [
|
|
182
|
+
"PassFunctionRole",
|
|
183
|
+
"Arn"
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"PassFunctionErrorAlarm": {
|
|
189
|
+
"Type": "AWS::CloudWatch::Alarm",
|
|
190
|
+
"Properties": {
|
|
191
|
+
"AlarmName": {
|
|
192
|
+
"Fn::Sub": "${AWS::StackName}-PassFunction-Errors-${AWS::Region}"
|
|
193
|
+
},
|
|
194
|
+
"AlarmDescription": {
|
|
195
|
+
"Fn::Sub": [
|
|
196
|
+
"Error alarm for ${name} lambda function in ${AWS::StackName} stack",
|
|
197
|
+
{
|
|
198
|
+
"name": {
|
|
199
|
+
"Fn::Sub": "${AWS::StackName}-Pass"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
"AlarmActions": [],
|
|
205
|
+
"Period": 60,
|
|
206
|
+
"EvaluationPeriods": 1,
|
|
207
|
+
"DatapointsToAlarm": 1,
|
|
208
|
+
"Statistic": "Sum",
|
|
209
|
+
"Threshold": 0,
|
|
210
|
+
"ComparisonOperator": "GreaterThanThreshold",
|
|
211
|
+
"TreatMissingData": "notBreaching",
|
|
212
|
+
"Namespace": "AWS/Lambda",
|
|
213
|
+
"Dimensions": [
|
|
214
|
+
{
|
|
215
|
+
"Name": "FunctionName",
|
|
216
|
+
"Value": {
|
|
217
|
+
"Ref": "PassFunction"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
],
|
|
221
|
+
"MetricName": "Errors"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
"PassFunctionLogPolicy": {
|
|
225
|
+
"Type": "AWS::IAM::Policy",
|
|
226
|
+
"DependsOn": "PassFunctionRole",
|
|
227
|
+
"Properties": {
|
|
228
|
+
"PolicyName": "lambda-log-access",
|
|
229
|
+
"Roles": [
|
|
230
|
+
{
|
|
231
|
+
"Ref": "PassFunctionRole"
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
"PolicyDocument": {
|
|
235
|
+
"Version": "2012-10-17",
|
|
236
|
+
"Statement": [
|
|
237
|
+
{
|
|
238
|
+
"Effect": "Allow",
|
|
239
|
+
"Action": "logs:*",
|
|
240
|
+
"Resource": {
|
|
241
|
+
"Fn::GetAtt": [
|
|
242
|
+
"PassFunctionLogs",
|
|
243
|
+
"Arn"
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"PassFunctionRole": {
|
|
252
|
+
"Type": "AWS::IAM::Role",
|
|
253
|
+
"Properties": {
|
|
254
|
+
"AssumeRolePolicyDocument": {
|
|
255
|
+
"Statement": [
|
|
256
|
+
{
|
|
257
|
+
"Effect": "Allow",
|
|
258
|
+
"Action": "sts:AssumeRole",
|
|
259
|
+
"Principal": {
|
|
260
|
+
"Service": {
|
|
261
|
+
"Fn::Sub": "lambda.amazonaws.com"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
"Policies": [
|
|
268
|
+
{
|
|
269
|
+
"PolicyName": "main",
|
|
270
|
+
"PolicyDocument": {
|
|
271
|
+
"Version": "2012-10-17",
|
|
272
|
+
"Statement": [
|
|
273
|
+
{
|
|
274
|
+
"Effect": "Allow",
|
|
275
|
+
"Action": "lambda:InvokeFunction",
|
|
276
|
+
"Resource": {
|
|
277
|
+
"Fn::GetAtt": [
|
|
278
|
+
"Destination",
|
|
279
|
+
"Arn"
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
"DestinationLogs": {
|
|
290
|
+
"Type": "AWS::Logs::LogGroup",
|
|
291
|
+
"Properties": {
|
|
292
|
+
"LogGroupName": {
|
|
293
|
+
"Fn::Sub": [
|
|
294
|
+
"/aws/lambda/${name}",
|
|
295
|
+
{
|
|
296
|
+
"name": {
|
|
297
|
+
"Fn::Sub": "${AWS::StackName}-Destination"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
},
|
|
302
|
+
"RetentionInDays": 14
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"Destination": {
|
|
306
|
+
"Type": "AWS::Lambda::Function",
|
|
307
|
+
"Properties": {
|
|
308
|
+
"Code": {
|
|
309
|
+
"ZipFile": "module.exports.handler = (e, c, cb) => cb();"
|
|
310
|
+
},
|
|
311
|
+
"Description": {
|
|
312
|
+
"Fn::Sub": "Destination in the ${AWS::StackName} stack"
|
|
313
|
+
},
|
|
314
|
+
"FunctionName": {
|
|
315
|
+
"Fn::Sub": "${AWS::StackName}-Destination"
|
|
316
|
+
},
|
|
317
|
+
"Handler": "index.handler",
|
|
318
|
+
"MemorySize": 128,
|
|
319
|
+
"Runtime": "nodejs18.x",
|
|
320
|
+
"Timeout": 300,
|
|
321
|
+
"Role": {
|
|
322
|
+
"Fn::GetAtt": [
|
|
323
|
+
"DestinationRole",
|
|
324
|
+
"Arn"
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"DestinationErrorAlarm": {
|
|
330
|
+
"Type": "AWS::CloudWatch::Alarm",
|
|
331
|
+
"Properties": {
|
|
332
|
+
"AlarmName": {
|
|
333
|
+
"Fn::Sub": "${AWS::StackName}-Destination-Errors-${AWS::Region}"
|
|
334
|
+
},
|
|
335
|
+
"AlarmDescription": {
|
|
336
|
+
"Fn::Sub": [
|
|
337
|
+
"Error alarm for ${name} lambda function in ${AWS::StackName} stack",
|
|
338
|
+
{
|
|
339
|
+
"name": {
|
|
340
|
+
"Fn::Sub": "${AWS::StackName}-Destination"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
"AlarmActions": [],
|
|
346
|
+
"Period": 60,
|
|
347
|
+
"EvaluationPeriods": 5,
|
|
348
|
+
"DatapointsToAlarm": 1,
|
|
349
|
+
"Statistic": "Sum",
|
|
350
|
+
"Threshold": 0,
|
|
351
|
+
"ComparisonOperator": "GreaterThanThreshold",
|
|
352
|
+
"TreatMissingData": "notBreaching",
|
|
353
|
+
"Namespace": "AWS/Lambda",
|
|
354
|
+
"Dimensions": [
|
|
355
|
+
{
|
|
356
|
+
"Name": "FunctionName",
|
|
357
|
+
"Value": {
|
|
358
|
+
"Ref": "Destination"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"MetricName": "Errors"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"DestinationLogPolicy": {
|
|
366
|
+
"Type": "AWS::IAM::Policy",
|
|
367
|
+
"DependsOn": "DestinationRole",
|
|
368
|
+
"Properties": {
|
|
369
|
+
"PolicyName": "lambda-log-access",
|
|
370
|
+
"Roles": [
|
|
371
|
+
{
|
|
372
|
+
"Ref": "DestinationRole"
|
|
373
|
+
}
|
|
374
|
+
],
|
|
375
|
+
"PolicyDocument": {
|
|
376
|
+
"Version": "2012-10-17",
|
|
377
|
+
"Statement": [
|
|
378
|
+
{
|
|
379
|
+
"Effect": "Allow",
|
|
380
|
+
"Action": "logs:*",
|
|
381
|
+
"Resource": {
|
|
382
|
+
"Fn::GetAtt": [
|
|
383
|
+
"DestinationLogs",
|
|
384
|
+
"Arn"
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
"DestinationRole": {
|
|
393
|
+
"Type": "AWS::IAM::Role",
|
|
394
|
+
"Properties": {
|
|
395
|
+
"AssumeRolePolicyDocument": {
|
|
396
|
+
"Statement": [
|
|
397
|
+
{
|
|
398
|
+
"Effect": "Allow",
|
|
399
|
+
"Action": "sts:AssumeRole",
|
|
400
|
+
"Principal": {
|
|
401
|
+
"Service": {
|
|
402
|
+
"Fn::Sub": "lambda.amazonaws.com"
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
"Outputs": {
|
|
412
|
+
"PassEndpointOutput": {
|
|
413
|
+
"Description": "The HTTPS endpoint used to send github webhooks",
|
|
414
|
+
"Value": {
|
|
415
|
+
"Fn::Sub": "https://${PassApi}.execute-api.${AWS::Region}.amazonaws.com/hookshot/webhook"
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
"PassSecretOutput": {
|
|
419
|
+
"Description": "A secret key to give Github to use when signing webhook requests",
|
|
420
|
+
"Value": "abc123"
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"Type": "AWS::ApiGateway::Stage",
|
|
29
29
|
"Properties": {
|
|
30
30
|
"DeploymentId": {
|
|
31
|
-
"Ref": "
|
|
31
|
+
"Ref": "PassDeployment467809dc"
|
|
32
32
|
},
|
|
33
33
|
"StageName": "hookshot",
|
|
34
34
|
"RestApiId": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
]
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
|
-
"
|
|
50
|
+
"PassDeployment467809dc": {
|
|
51
51
|
"Type": "AWS::ApiGateway::Deployment",
|
|
52
52
|
"DependsOn": "PassMethod",
|
|
53
53
|
"Properties": {
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"Code": {
|
|
165
165
|
"ZipFile": {
|
|
166
166
|
"Fn::Sub": [
|
|
167
|
-
"'use strict';\n\nconst crypto = require('crypto');\nconst
|
|
167
|
+
"'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
|
|
168
168
|
{
|
|
169
169
|
"WebhookSecret": {
|
|
170
170
|
"Ref": "SomeParameter"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"Type": "AWS::ApiGateway::Stage",
|
|
25
25
|
"Properties": {
|
|
26
26
|
"DeploymentId": {
|
|
27
|
-
"Ref": "
|
|
27
|
+
"Ref": "PassDeployment467809dc"
|
|
28
28
|
},
|
|
29
29
|
"StageName": "hookshot",
|
|
30
30
|
"RestApiId": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
]
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"PassDeployment467809dc": {
|
|
47
47
|
"Type": "AWS::ApiGateway::Deployment",
|
|
48
48
|
"DependsOn": "PassMethod",
|
|
49
49
|
"Properties": {
|
|
@@ -160,7 +160,7 @@
|
|
|
160
160
|
"Code": {
|
|
161
161
|
"ZipFile": {
|
|
162
162
|
"Fn::Sub": [
|
|
163
|
-
"'use strict';\n\nconst crypto = require('crypto');\nconst
|
|
163
|
+
"'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
|
|
164
164
|
{
|
|
165
165
|
"WebhookSecret": "abc123"
|
|
166
166
|
}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"Type": "AWS::ApiGateway::Stage",
|
|
25
25
|
"Properties": {
|
|
26
26
|
"DeploymentId": {
|
|
27
|
-
"Ref": "
|
|
27
|
+
"Ref": "PassDeployment467809dc"
|
|
28
28
|
},
|
|
29
29
|
"StageName": "hookshot",
|
|
30
30
|
"RestApiId": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
]
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"PassDeployment467809dc": {
|
|
47
47
|
"Type": "AWS::ApiGateway::Deployment",
|
|
48
48
|
"DependsOn": "PassMethod",
|
|
49
49
|
"Properties": {
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"Code": {
|
|
167
167
|
"ZipFile": {
|
|
168
168
|
"Fn::Sub": [
|
|
169
|
-
"'use strict';\n\nconst crypto = require('crypto');\nconst
|
|
169
|
+
"'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
|
|
170
170
|
{
|
|
171
171
|
"WebhookSecret": {
|
|
172
172
|
"Ref": "PassSecret"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"Type": "AWS::ApiGateway::Stage",
|
|
25
25
|
"Properties": {
|
|
26
26
|
"DeploymentId": {
|
|
27
|
-
"Ref": "
|
|
27
|
+
"Ref": "PassDeployment467809dc"
|
|
28
28
|
},
|
|
29
29
|
"StageName": "hookshot",
|
|
30
30
|
"RestApiId": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
-
"
|
|
55
|
+
"PassDeployment467809dc": {
|
|
56
56
|
"Type": "AWS::ApiGateway::Deployment",
|
|
57
57
|
"DependsOn": "PassMethod",
|
|
58
58
|
"Properties": {
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"Properties": {
|
|
169
169
|
"Code": {
|
|
170
170
|
"ZipFile": {
|
|
171
|
-
"Fn::Sub": "
|
|
171
|
+
"Fn::Sub": "const { 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};"
|
|
172
172
|
}
|
|
173
173
|
},
|
|
174
174
|
"Description": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"Type": "AWS::ApiGateway::Stage",
|
|
25
25
|
"Properties": {
|
|
26
26
|
"DeploymentId": {
|
|
27
|
-
"Ref": "
|
|
27
|
+
"Ref": "PassDeployment467809dc"
|
|
28
28
|
},
|
|
29
29
|
"StageName": "hookshot",
|
|
30
30
|
"RestApiId": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
]
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"PassDeployment467809dc": {
|
|
47
47
|
"Type": "AWS::ApiGateway::Deployment",
|
|
48
48
|
"DependsOn": "PassMethod",
|
|
49
49
|
"Properties": {
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
"Properties": {
|
|
151
151
|
"Code": {
|
|
152
152
|
"ZipFile": {
|
|
153
|
-
"Fn::Sub": "
|
|
153
|
+
"Fn::Sub": "const { 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};"
|
|
154
154
|
}
|
|
155
155
|
},
|
|
156
156
|
"Description": {
|