@datadog/datadog-ci 0.17.12 → 0.17.13

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.
Files changed (43) hide show
  1. package/README.md +6 -1
  2. package/dist/commands/junit/upload.js +1 -1
  3. package/dist/commands/lambda/__tests__/fixtures.d.ts +5 -1
  4. package/dist/commands/lambda/__tests__/fixtures.js +13 -2
  5. package/dist/commands/lambda/__tests__/functions/commons.test.js +221 -0
  6. package/dist/commands/lambda/__tests__/functions/instrument.test.js +64 -42
  7. package/dist/commands/lambda/__tests__/instrument.test.js +425 -4
  8. package/dist/commands/lambda/__tests__/prompt.test.d.ts +1 -0
  9. package/dist/commands/lambda/__tests__/prompt.test.js +216 -0
  10. package/dist/commands/lambda/__tests__/uninstrument.test.js +310 -4
  11. package/dist/commands/lambda/constants.d.ts +10 -0
  12. package/dist/commands/lambda/constants.js +36 -2
  13. package/dist/commands/lambda/functions/commons.d.ts +15 -0
  14. package/dist/commands/lambda/functions/commons.js +105 -2
  15. package/dist/commands/lambda/functions/instrument.d.ts +1 -1
  16. package/dist/commands/lambda/functions/instrument.js +17 -7
  17. package/dist/commands/lambda/functions/uninstrument.js +1 -0
  18. package/dist/commands/lambda/instrument.d.ts +2 -0
  19. package/dist/commands/lambda/instrument.js +100 -47
  20. package/dist/commands/lambda/interfaces.d.ts +4 -0
  21. package/dist/commands/lambda/prompt.d.ts +9 -0
  22. package/dist/commands/lambda/prompt.js +187 -0
  23. package/dist/commands/lambda/uninstrument.d.ts +1 -0
  24. package/dist/commands/lambda/uninstrument.js +68 -30
  25. package/dist/commands/synthetics/__tests__/cli.test.js +1 -0
  26. package/dist/commands/synthetics/__tests__/fixtures.js +1 -0
  27. package/dist/commands/synthetics/__tests__/run-test.test.js +48 -2
  28. package/dist/commands/synthetics/__tests__/utils.test.js +11 -0
  29. package/dist/commands/synthetics/command.d.ts +1 -0
  30. package/dist/commands/synthetics/command.js +11 -5
  31. package/dist/commands/synthetics/interfaces.d.ts +8 -3
  32. package/dist/commands/synthetics/interfaces.js +7 -3
  33. package/dist/commands/synthetics/reporters/default.js +5 -1
  34. package/dist/commands/synthetics/run-test.js +3 -1
  35. package/dist/commands/synthetics/utils.d.ts +3 -0
  36. package/dist/commands/synthetics/utils.js +20 -1
  37. package/dist/commands/trace/api.js +1 -1
  38. package/dist/helpers/__tests__/ci.test.js +71 -24
  39. package/dist/helpers/__tests__/user-provided-git.test.js +69 -27
  40. package/dist/helpers/ci.js +1 -1
  41. package/dist/helpers/user-provided-git.d.ts +2 -1
  42. package/dist/helpers/user-provided-git.js +18 -3
  43. package/package.json +1 -1
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ jest.mock('inquirer');
13
+ const chalk_1 = require("chalk");
14
+ const inquirer_1 = require("inquirer");
15
+ const constants_1 = require("../constants");
16
+ const prompt_1 = require("../prompt");
17
+ const fixtures_1 = require("./fixtures");
18
+ describe('prompt', () => {
19
+ describe('confirmationQuestion', () => {
20
+ test('returns question with provided message', () => {
21
+ const message = 'Do you want to continue?';
22
+ const question = prompt_1.confirmationQuestion(message);
23
+ expect(question.message).toBe(message);
24
+ });
25
+ });
26
+ describe('datadogApiKeyTypeQuestion', () => {
27
+ test('returns question with message pointing to the correct given site', () => {
28
+ const site = 'datadoghq.com';
29
+ const question = prompt_1.datadogApiKeyTypeQuestion(site);
30
+ expect(question.message).toBe(`Which type of Datadog API Key you want to set? \nLearn more at ${chalk_1.blueBright(`https://app.${site}/organization-settings/api-keys`)}`);
31
+ });
32
+ });
33
+ describe('datadogEnvVarsQuestions', () => {
34
+ test('returns correct message when user selects DATADOG_API_KEY', () => {
35
+ const datadogApiKeyType = {
36
+ envVar: constants_1.CI_API_KEY_ENV_VAR,
37
+ message: 'API Key:',
38
+ };
39
+ const question = prompt_1.datadogEnvVarsQuestions(datadogApiKeyType);
40
+ expect(question.message).toBe('API Key:');
41
+ expect(question.name).toBe(constants_1.CI_API_KEY_ENV_VAR);
42
+ });
43
+ test('returns correct message when user selects DATADOG_KMS_API_KEY', () => {
44
+ const datadogApiKeyType = {
45
+ envVar: constants_1.CI_KMS_API_KEY_ENV_VAR,
46
+ message: 'KMS API Key:',
47
+ };
48
+ const question = prompt_1.datadogEnvVarsQuestions(datadogApiKeyType);
49
+ expect(question.message).toBe('KMS API Key:');
50
+ expect(question.name).toBe(constants_1.CI_KMS_API_KEY_ENV_VAR);
51
+ });
52
+ test('returns correct message when user selects DATADOG_API_KEY_SECRET_ARN', () => {
53
+ const datadogApiKeyType = {
54
+ envVar: constants_1.CI_API_KEY_SECRET_ARN_ENV_VAR,
55
+ message: 'API Key Secret ARN:',
56
+ };
57
+ const question = prompt_1.datadogEnvVarsQuestions(datadogApiKeyType);
58
+ expect(question.message).toBe('API Key Secret ARN:');
59
+ expect(question.name).toBe(constants_1.CI_API_KEY_SECRET_ARN_ENV_VAR);
60
+ });
61
+ });
62
+ describe('functionSelectionQuestion', () => {
63
+ test('returns question with the provided function names being its choices', () => {
64
+ const functionNames = ['my-func', 'my-func-2', 'my-third-func'];
65
+ const question = prompt_1.functionSelectionQuestion(functionNames);
66
+ expect(question.choices).toBe(functionNames);
67
+ });
68
+ });
69
+ describe('requestAWSCrendentials', () => {
70
+ const OLD_ENV = process.env;
71
+ beforeEach(() => {
72
+ jest.resetModules();
73
+ process.env = {};
74
+ });
75
+ afterAll(() => {
76
+ process.env = OLD_ENV;
77
+ });
78
+ test('sets the AWS credentials as environment variables', () => __awaiter(void 0, void 0, void 0, function* () {
79
+ ;
80
+ inquirer_1.prompt.mockImplementation(() => Promise.resolve({
81
+ [constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]: fixtures_1.mockAwsAccessKeyId,
82
+ [constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]: fixtures_1.mockAwsSecretAccessKey,
83
+ [constants_1.AWS_DEFAULT_REGION_ENV_VAR]: 'sa-east-1',
84
+ }));
85
+ yield prompt_1.requestAWSCredentials();
86
+ expect(process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]).toBe(fixtures_1.mockAwsAccessKeyId);
87
+ expect(process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]).toBe(fixtures_1.mockAwsSecretAccessKey);
88
+ expect(process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR]).toBe('sa-east-1');
89
+ }));
90
+ test('sets the AWS credentials with session token as environment variables', () => __awaiter(void 0, void 0, void 0, function* () {
91
+ ;
92
+ inquirer_1.prompt.mockImplementation(() => Promise.resolve({
93
+ [constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]: fixtures_1.mockAwsAccessKeyId,
94
+ [constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]: fixtures_1.mockAwsSecretAccessKey,
95
+ [constants_1.AWS_DEFAULT_REGION_ENV_VAR]: 'sa-east-1',
96
+ [constants_1.AWS_SESSION_TOKEN_ENV_VAR]: 'some-session-token',
97
+ }));
98
+ yield prompt_1.requestAWSCredentials();
99
+ expect(process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]).toBe(fixtures_1.mockAwsAccessKeyId);
100
+ expect(process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]).toBe(fixtures_1.mockAwsSecretAccessKey);
101
+ expect(process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR]).toBe('sa-east-1');
102
+ expect(process.env[constants_1.AWS_SESSION_TOKEN_ENV_VAR]).toBe('some-session-token');
103
+ }));
104
+ test('throws error when something unexpected happens while prompting', () => __awaiter(void 0, void 0, void 0, function* () {
105
+ ;
106
+ inquirer_1.prompt.mockImplementation(() => Promise.reject(new Error('Unexpected error')));
107
+ let error;
108
+ try {
109
+ yield prompt_1.requestAWSCredentials();
110
+ }
111
+ catch (e) {
112
+ if (e instanceof Error) {
113
+ error = e;
114
+ }
115
+ }
116
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe("Couldn't set AWS Credentials. Unexpected error");
117
+ }));
118
+ });
119
+ describe('requestChangesConfirmation', () => {
120
+ test('returns boolean when users responds to confirmation question', () => __awaiter(void 0, void 0, void 0, function* () {
121
+ ;
122
+ inquirer_1.prompt.mockImplementation(() => Promise.resolve({
123
+ confirmation: true,
124
+ }));
125
+ const confirmation = yield prompt_1.requestChangesConfirmation('Do you want to continue?');
126
+ expect(confirmation).toBe(true);
127
+ }));
128
+ test('throws error when something unexpected happens while prompting', () => __awaiter(void 0, void 0, void 0, function* () {
129
+ ;
130
+ inquirer_1.prompt.mockImplementation(() => Promise.reject(new Error('Unexpected error')));
131
+ let error;
132
+ try {
133
+ yield prompt_1.requestChangesConfirmation('Do you wanna continue?');
134
+ }
135
+ catch (e) {
136
+ if (e instanceof Error) {
137
+ error = e;
138
+ }
139
+ }
140
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe("Couldn't receive confirmation. Unexpected error");
141
+ }));
142
+ });
143
+ describe('requestDatadogEnvVars', () => {
144
+ const OLD_ENV = process.env;
145
+ beforeEach(() => {
146
+ jest.resetModules();
147
+ process.env = {};
148
+ });
149
+ afterAll(() => {
150
+ process.env = OLD_ENV;
151
+ });
152
+ test('sets the Datadog Environment Variables as provided/selected by user', () => __awaiter(void 0, void 0, void 0, function* () {
153
+ const site = 'datadoghq.com';
154
+ inquirer_1.prompt.mockImplementation((question) => {
155
+ switch (question.name) {
156
+ case constants_1.CI_API_KEY_ENV_VAR:
157
+ return Promise.resolve({
158
+ [constants_1.CI_API_KEY_ENV_VAR]: fixtures_1.mockDatadogApiKey,
159
+ });
160
+ case constants_1.CI_SITE_ENV_VAR:
161
+ return Promise.resolve({
162
+ [constants_1.CI_SITE_ENV_VAR]: 'datadoghq.com',
163
+ });
164
+ case 'type':
165
+ return Promise.resolve({
166
+ type: {
167
+ envVar: constants_1.CI_API_KEY_ENV_VAR,
168
+ message: 'API Key:',
169
+ },
170
+ });
171
+ default:
172
+ }
173
+ });
174
+ yield prompt_1.requestDatadogEnvVars();
175
+ expect(process.env[constants_1.CI_SITE_ENV_VAR]).toBe(site);
176
+ expect(process.env[constants_1.CI_API_KEY_ENV_VAR]).toBe(fixtures_1.mockDatadogApiKey);
177
+ }));
178
+ test('throws error when something unexpected happens while prompting', () => __awaiter(void 0, void 0, void 0, function* () {
179
+ ;
180
+ inquirer_1.prompt.mockImplementation(() => Promise.reject(new Error('Unexpected error')));
181
+ let error;
182
+ try {
183
+ yield prompt_1.requestDatadogEnvVars();
184
+ }
185
+ catch (e) {
186
+ if (e instanceof Error) {
187
+ error = e;
188
+ }
189
+ }
190
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe("Couldn't set Datadog Environment Variables. Unexpected error");
191
+ }));
192
+ });
193
+ describe('requestFunctionSelection', () => {
194
+ const selectedFunctions = ['my-func', 'my-func-2', 'my-third-func'];
195
+ test('returns the selected functions', () => __awaiter(void 0, void 0, void 0, function* () {
196
+ ;
197
+ inquirer_1.prompt.mockImplementation(() => Promise.resolve({ functions: selectedFunctions }));
198
+ const functions = yield prompt_1.requestFunctionSelection(selectedFunctions);
199
+ expect(functions).toBe(selectedFunctions);
200
+ }));
201
+ test('throws error when something unexpected happens while prompting', () => __awaiter(void 0, void 0, void 0, function* () {
202
+ ;
203
+ inquirer_1.prompt.mockImplementation(() => Promise.reject(new Error('Unexpected error')));
204
+ let error;
205
+ try {
206
+ yield prompt_1.requestFunctionSelection(selectedFunctions);
207
+ }
208
+ catch (e) {
209
+ if (e instanceof Error) {
210
+ error = e;
211
+ }
212
+ }
213
+ expect(error === null || error === void 0 ? void 0 : error.message).toBe("Couldn't receive selected functions. Unexpected error");
214
+ }));
215
+ });
216
+ });
@@ -31,10 +31,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
31
31
  // tslint:disable: no-string-literal
32
32
  jest.mock('fs');
33
33
  jest.mock('aws-sdk');
34
+ jest.mock('../prompt');
34
35
  const aws_sdk_1 = require("aws-sdk");
35
36
  const chalk_1 = require("chalk");
36
37
  const fs = __importStar(require("fs"));
37
38
  const constants_1 = require("../constants");
39
+ const prompt_1 = require("../prompt");
38
40
  const uninstrument_1 = require("../uninstrument");
39
41
  const fixtures_1 = require("./fixtures");
40
42
  describe('uninstrument', () => {
@@ -170,7 +172,7 @@ UpdateFunctionConfiguration -> arn:aws:lambda:us-east-1:000000000000:function:un
170
172
  const code = yield command['execute']();
171
173
  const output = command.context.stdout.toString();
172
174
  expect(code).toBe(1);
173
- expect(output).toMatch(`${chalk_1.red('[Error]')} Couldn't fetch lambda functions. Lambda failed\n`);
175
+ expect(output).toMatch(`${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. Lambda failed\n`);
174
176
  }));
175
177
  test("aborts early when function regions can't be found", () => __awaiter(void 0, void 0, void 0, function* () {
176
178
  ;
@@ -193,7 +195,7 @@ UpdateFunctionConfiguration -> arn:aws:lambda:us-east-1:000000000000:function:un
193
195
  const output = context.stdout.toString();
194
196
  expect(code).toBe(1);
195
197
  expect(output).toMatchInlineSnapshot(`
196
- "No functions specified for un-instrumentation.
198
+ "${chalk_1.red('[Error]')} No functions specified for un-instrumentation.
197
199
  "
198
200
  `);
199
201
  }));
@@ -206,7 +208,7 @@ UpdateFunctionConfiguration -> arn:aws:lambda:us-east-1:000000000000:function:un
206
208
  yield command['execute']();
207
209
  const output = command.context.stdout.toString();
208
210
  expect(output).toMatchInlineSnapshot(`
209
- "No functions specified for un-instrumentation.
211
+ "${chalk_1.red('[Error]')} No functions specified for un-instrumentation.
210
212
  "
211
213
  `);
212
214
  }));
@@ -263,7 +265,311 @@ UpdateFunctionConfiguration -> arn:aws:lambda:us-east-1:000000000000:function:un
263
265
  const code = yield command['execute']();
264
266
  const output = command.context.stdout.toString();
265
267
  expect(code).toBe(1);
266
- expect(output).toMatch("Fetching lambda functions, this might take a while.\nCouldn't fetch lambda functions. Error: Max retry count exceeded.\n");
268
+ expect(output).toMatch(`Fetching Lambda functions, this might take a while.\n${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. Error: Max retry count exceeded.\n`);
269
+ }));
270
+ test('uninstrument multiple functions interactively', () => __awaiter(void 0, void 0, void 0, function* () {
271
+ ;
272
+ fs.readFile.mockImplementation((a, b, callback) => callback({ code: 'ENOENT' }));
273
+ aws_sdk_1.Lambda.mockImplementation(() => fixtures_1.makeMockLambda({
274
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world': {
275
+ Architectures: ['x86_64'],
276
+ Environment: {
277
+ Variables: {
278
+ [constants_1.ENVIRONMENT_ENV_VAR]: 'staging',
279
+ [constants_1.FLUSH_TO_LOG_ENV_VAR]: 'true',
280
+ [constants_1.LAMBDA_HANDLER_ENV_VAR]: 'lambda_function.lambda_handler',
281
+ [constants_1.LOG_LEVEL_ENV_VAR]: 'debug',
282
+ [constants_1.MERGE_XRAY_TRACES_ENV_VAR]: 'false',
283
+ [constants_1.SERVICE_ENV_VAR]: 'middletier',
284
+ [constants_1.SITE_ENV_VAR]: 'datadoghq.com',
285
+ [constants_1.TRACE_ENABLED_ENV_VAR]: 'true',
286
+ [constants_1.VERSION_ENV_VAR]: '0.2',
287
+ USER_VARIABLE: 'shouldnt be deleted by uninstrumentation',
288
+ },
289
+ },
290
+ FunctionArn: 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world',
291
+ FunctionName: 'lambda-hello-world',
292
+ Handler: 'datadog_lambda.handler.handler',
293
+ Layers: [
294
+ {
295
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Extension:11',
296
+ CodeSize: 0,
297
+ SigningJobArn: 'some-signing-job-arn',
298
+ SigningProfileVersionArn: 'some-signing-profile',
299
+ },
300
+ {
301
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Python38:49',
302
+ CodeSize: 0,
303
+ SigningJobArn: 'some-signing-job-arn',
304
+ SigningProfileVersionArn: 'some-signing-profile',
305
+ },
306
+ ],
307
+ Runtime: 'python3.8',
308
+ },
309
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2': {
310
+ Architectures: ['x86_64'],
311
+ Environment: {
312
+ Variables: {
313
+ [constants_1.ENVIRONMENT_ENV_VAR]: 'staging',
314
+ [constants_1.FLUSH_TO_LOG_ENV_VAR]: 'true',
315
+ [constants_1.LAMBDA_HANDLER_ENV_VAR]: 'lambda_function.lambda_handler',
316
+ [constants_1.LOG_LEVEL_ENV_VAR]: 'debug',
317
+ [constants_1.MERGE_XRAY_TRACES_ENV_VAR]: 'false',
318
+ [constants_1.SERVICE_ENV_VAR]: 'middletier',
319
+ [constants_1.SITE_ENV_VAR]: 'datadoghq.com',
320
+ [constants_1.TRACE_ENABLED_ENV_VAR]: 'true',
321
+ [constants_1.VERSION_ENV_VAR]: '0.2',
322
+ },
323
+ },
324
+ FunctionArn: 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2',
325
+ FunctionName: 'lambda-hello-world-2',
326
+ Handler: 'datadog_lambda.handler.handler',
327
+ Layers: [
328
+ {
329
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Extension:11',
330
+ CodeSize: 0,
331
+ SigningJobArn: 'some-signing-job-arn',
332
+ SigningProfileVersionArn: 'some-signing-profile',
333
+ },
334
+ {
335
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Python39:49',
336
+ CodeSize: 0,
337
+ SigningJobArn: 'some-signing-job-arn',
338
+ SigningProfileVersionArn: 'some-signing-profile',
339
+ },
340
+ ],
341
+ Runtime: 'python3.9',
342
+ },
343
+ }));
344
+ prompt_1.requestAWSCredentials.mockImplementation(() => {
345
+ process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR] = fixtures_1.mockAwsAccessKeyId;
346
+ process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR] = fixtures_1.mockAwsSecretAccessKey;
347
+ process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR] = 'sa-east-1';
348
+ });
349
+ prompt_1.requestFunctionSelection.mockImplementation(() => [
350
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world',
351
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2',
352
+ ]);
353
+ prompt_1.requestChangesConfirmation.mockImplementation(() => true);
354
+ const cli = fixtures_1.makeCli();
355
+ const context = fixtures_1.createMockContext();
356
+ const code = yield cli.run(['lambda', 'uninstrument', '-i'], context);
357
+ const output = context.stdout.toString();
358
+ expect(code).toBe(0);
359
+ expect(output).toMatchInlineSnapshot(`
360
+ "${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!
361
+ Fetching Lambda functions, this might take a while.\n
362
+ ${chalk_1.bold(chalk_1.yellow('[!]'))} Functions to be updated:
363
+ \t- ${chalk_1.bold('arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world')}
364
+ \t- ${chalk_1.bold('arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2')}\n
365
+ Will apply the following updates:
366
+ UpdateFunctionConfiguration -> arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world
367
+ {
368
+ \\"FunctionName\\": \\"arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world\\",
369
+ \\"Handler\\": \\"lambda_function.lambda_handler\\",
370
+ \\"Environment\\": {
371
+ \\"Variables\\": {
372
+ \\"USER_VARIABLE\\": \\"shouldnt be deleted by uninstrumentation\\"
373
+ }
374
+ },
375
+ \\"Layers\\": []
376
+ }
377
+ UpdateFunctionConfiguration -> arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2
378
+ {
379
+ \\"FunctionName\\": \\"arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2\\",
380
+ \\"Handler\\": \\"lambda_function.lambda_handler\\",
381
+ \\"Environment\\": {
382
+ \\"Variables\\": {}
383
+ },
384
+ \\"Layers\\": []
385
+ }
386
+ ${chalk_1.yellow('[!]')} Confirmation needed.
387
+ ${chalk_1.yellow('[!]')} Uninstrumenting functions.
388
+ "
389
+ `);
390
+ }));
391
+ test('uninstrument multiple specified functions interactively', () => __awaiter(void 0, void 0, void 0, function* () {
392
+ ;
393
+ fs.readFile.mockImplementation((a, b, callback) => callback({ code: 'ENOENT' }));
394
+ aws_sdk_1.Lambda.mockImplementation(() => fixtures_1.makeMockLambda({
395
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world': {
396
+ Architectures: ['x86_64'],
397
+ Environment: {
398
+ Variables: {
399
+ [constants_1.ENVIRONMENT_ENV_VAR]: 'staging',
400
+ [constants_1.FLUSH_TO_LOG_ENV_VAR]: 'true',
401
+ [constants_1.LAMBDA_HANDLER_ENV_VAR]: 'lambda_function.lambda_handler',
402
+ [constants_1.LOG_LEVEL_ENV_VAR]: 'debug',
403
+ [constants_1.MERGE_XRAY_TRACES_ENV_VAR]: 'false',
404
+ [constants_1.SERVICE_ENV_VAR]: 'middletier',
405
+ [constants_1.SITE_ENV_VAR]: 'datadoghq.com',
406
+ [constants_1.TRACE_ENABLED_ENV_VAR]: 'true',
407
+ [constants_1.VERSION_ENV_VAR]: '0.2',
408
+ USER_VARIABLE: 'shouldnt be deleted by uninstrumentation',
409
+ },
410
+ },
411
+ FunctionArn: 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world',
412
+ FunctionName: 'lambda-hello-world',
413
+ Handler: 'datadog_lambda.handler.handler',
414
+ Layers: [
415
+ {
416
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Extension:11',
417
+ CodeSize: 0,
418
+ SigningJobArn: 'some-signing-job-arn',
419
+ SigningProfileVersionArn: 'some-signing-profile',
420
+ },
421
+ {
422
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Python38:49',
423
+ CodeSize: 0,
424
+ SigningJobArn: 'some-signing-job-arn',
425
+ SigningProfileVersionArn: 'some-signing-profile',
426
+ },
427
+ ],
428
+ Runtime: 'python3.8',
429
+ },
430
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2': {
431
+ Architectures: ['x86_64'],
432
+ Environment: {
433
+ Variables: {
434
+ [constants_1.ENVIRONMENT_ENV_VAR]: 'staging',
435
+ [constants_1.FLUSH_TO_LOG_ENV_VAR]: 'true',
436
+ [constants_1.LAMBDA_HANDLER_ENV_VAR]: 'lambda_function.lambda_handler',
437
+ [constants_1.LOG_LEVEL_ENV_VAR]: 'debug',
438
+ [constants_1.MERGE_XRAY_TRACES_ENV_VAR]: 'false',
439
+ [constants_1.SERVICE_ENV_VAR]: 'middletier',
440
+ [constants_1.SITE_ENV_VAR]: 'datadoghq.com',
441
+ [constants_1.TRACE_ENABLED_ENV_VAR]: 'true',
442
+ [constants_1.VERSION_ENV_VAR]: '0.2',
443
+ },
444
+ },
445
+ FunctionArn: 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2',
446
+ FunctionName: 'lambda-hello-world-2',
447
+ Handler: 'datadog_lambda.handler.handler',
448
+ Layers: [
449
+ {
450
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Extension:11',
451
+ CodeSize: 0,
452
+ SigningJobArn: 'some-signing-job-arn',
453
+ SigningProfileVersionArn: 'some-signing-profile',
454
+ },
455
+ {
456
+ Arn: 'arn:aws:lambda:sa-east-1:000000000000:layer:Datadog-Python39:49',
457
+ CodeSize: 0,
458
+ SigningJobArn: 'some-signing-job-arn',
459
+ SigningProfileVersionArn: 'some-signing-profile',
460
+ },
461
+ ],
462
+ Runtime: 'python3.9',
463
+ },
464
+ }));
465
+ prompt_1.requestAWSCredentials.mockImplementation(() => {
466
+ process.env[constants_1.AWS_ACCESS_KEY_ID_ENV_VAR] = fixtures_1.mockAwsAccessKeyId;
467
+ process.env[constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR] = fixtures_1.mockAwsSecretAccessKey;
468
+ process.env[constants_1.AWS_DEFAULT_REGION_ENV_VAR] = 'sa-east-1';
469
+ });
470
+ prompt_1.requestFunctionSelection.mockImplementation(() => [
471
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world',
472
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2',
473
+ ]);
474
+ prompt_1.requestChangesConfirmation.mockImplementation(() => true);
475
+ const cli = fixtures_1.makeCli();
476
+ const context = fixtures_1.createMockContext();
477
+ const code = yield cli.run([
478
+ 'lambda',
479
+ 'uninstrument',
480
+ '-i',
481
+ '-f',
482
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world',
483
+ '-f',
484
+ 'arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2',
485
+ ], context);
486
+ const output = context.stdout.toString();
487
+ expect(code).toBe(0);
488
+ expect(output).toMatchInlineSnapshot(`
489
+ "${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!\n
490
+ ${chalk_1.bold(chalk_1.yellow('[!]'))} Functions to be updated:
491
+ \t- ${chalk_1.bold('arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world')}
492
+ \t- ${chalk_1.bold('arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2')}\n
493
+ Will apply the following updates:
494
+ UpdateFunctionConfiguration -> arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world
495
+ {
496
+ \\"FunctionName\\": \\"arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world\\",
497
+ \\"Handler\\": \\"lambda_function.lambda_handler\\",
498
+ \\"Environment\\": {
499
+ \\"Variables\\": {
500
+ \\"USER_VARIABLE\\": \\"shouldnt be deleted by uninstrumentation\\"
501
+ }
502
+ },
503
+ \\"Layers\\": []
504
+ }
505
+ UpdateFunctionConfiguration -> arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2
506
+ {
507
+ \\"FunctionName\\": \\"arn:aws:lambda:sa-east-1:123456789012:function:lambda-hello-world-2\\",
508
+ \\"Handler\\": \\"lambda_function.lambda_handler\\",
509
+ \\"Environment\\": {
510
+ \\"Variables\\": {}
511
+ },
512
+ \\"Layers\\": []
513
+ }
514
+ ${chalk_1.yellow('[!]')} Confirmation needed.
515
+ ${chalk_1.yellow('[!]')} Uninstrumenting functions.
516
+ "
517
+ `);
518
+ }));
519
+ test('aborts if a problem occurs while setting the AWS credentials interactively', () => __awaiter(void 0, void 0, void 0, function* () {
520
+ ;
521
+ fs.readFile.mockImplementation((a, b, callback) => callback({ code: 'ENOENT' }));
522
+ prompt_1.requestAWSCredentials.mockImplementation(() => Promise.reject('Unexpected error'));
523
+ const cli = fixtures_1.makeCli();
524
+ const context = fixtures_1.createMockContext();
525
+ const code = yield cli.run(['lambda', 'uninstrument', '-i'], context);
526
+ const output = context.stdout.toString();
527
+ expect(code).toBe(1);
528
+ expect(output).toMatchInlineSnapshot(`
529
+ "${chalk_1.bold(chalk_1.yellow('[!]'))} No existing AWS credentials found, let's set them up!
530
+ ${chalk_1.red('[Error]')} Unexpected error
531
+ "
532
+ `);
533
+ }));
534
+ test('aborts if there are no functions to uninstrument in the user AWS account', () => __awaiter(void 0, void 0, void 0, function* () {
535
+ process.env = {
536
+ [constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]: fixtures_1.mockAwsAccessKeyId,
537
+ [constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]: fixtures_1.mockAwsSecretAccessKey,
538
+ [constants_1.AWS_DEFAULT_REGION_ENV_VAR]: 'sa-east-1',
539
+ };
540
+ fs.readFile.mockImplementation((a, b, callback) => callback({ code: 'ENOENT' }));
541
+ aws_sdk_1.Lambda.mockImplementation(() => fixtures_1.makeMockLambda({}));
542
+ const cli = fixtures_1.makeCli();
543
+ const context = fixtures_1.createMockContext();
544
+ const code = yield cli.run(['lambda', 'uninstrument', '-i'], context);
545
+ const output = context.stdout.toString();
546
+ expect(code).toBe(1);
547
+ expect(output).toMatchInlineSnapshot(`
548
+ "Fetching Lambda functions, this might take a while.
549
+ ${chalk_1.red('[Error]')} Couldn't find any Lambda functions in the specified region.
550
+ "
551
+ `);
552
+ }));
553
+ test('aborts early when the aws-sdk throws an error while uninstrumenting interactively', () => __awaiter(void 0, void 0, void 0, function* () {
554
+ process.env = {
555
+ [constants_1.AWS_ACCESS_KEY_ID_ENV_VAR]: fixtures_1.mockAwsAccessKeyId,
556
+ [constants_1.AWS_SECRET_ACCESS_KEY_ENV_VAR]: fixtures_1.mockAwsSecretAccessKey,
557
+ [constants_1.AWS_DEFAULT_REGION_ENV_VAR]: 'sa-east-1',
558
+ };
559
+ fs.readFile.mockImplementation((a, b, callback) => callback({ code: 'ENOENT' }));
560
+ aws_sdk_1.Lambda.mockImplementation(() => ({
561
+ listFunctions: jest.fn().mockImplementation(() => ({ promise: () => Promise.reject('Lambda failed') })),
562
+ }));
563
+ const cli = fixtures_1.makeCli();
564
+ const context = fixtures_1.createMockContext();
565
+ const code = yield cli.run(['lambda', 'uninstrument', '-i'], context);
566
+ const output = context.stdout.toString();
567
+ expect(code).toBe(1);
568
+ expect(output).toMatchInlineSnapshot(`
569
+ "Fetching Lambda functions, this might take a while.
570
+ ${chalk_1.red('[Error]')} Couldn't fetch Lambda functions. Error: Max retry count exceeded.
571
+ "
572
+ `);
267
573
  }));
268
574
  });
269
575
  describe('printPlannedActions', () => {
@@ -29,6 +29,7 @@ export declare const HANDLER_LOCATION: {
29
29
  'python3.9': string;
30
30
  };
31
31
  export declare const SITES: string[];
32
+ export declare const AWS_REGIONS: string[];
32
33
  export declare const DEFAULT_LAYER_AWS_ACCOUNT = "464622532012";
33
34
  export declare const GOVCLOUD_LAYER_AWS_ACCOUNT = "002406178527";
34
35
  export declare const SUBSCRIPTION_FILTER_NAME = "datadog-ci-filter";
@@ -46,10 +47,19 @@ export declare const SERVICE_ENV_VAR = "DD_SERVICE";
46
47
  export declare const VERSION_ENV_VAR = "DD_VERSION";
47
48
  export declare const ENVIRONMENT_ENV_VAR = "DD_ENV";
48
49
  export declare const EXTRA_TAGS_ENV_VAR = "DD_TAGS";
50
+ export declare const CAPTURE_LAMBDA_PAYLOAD_ENV_VAR = "DD_CAPTURE_LAMBDA_PAYLOAD";
49
51
  export declare const CI_SITE_ENV_VAR = "DATADOG_SITE";
50
52
  export declare const CI_API_KEY_ENV_VAR = "DATADOG_API_KEY";
51
53
  export declare const CI_API_KEY_SECRET_ARN_ENV_VAR = "DATADOG_API_KEY_SECRET_ARN";
52
54
  export declare const CI_KMS_API_KEY_ENV_VAR = "DATADOG_KMS_API_KEY";
55
+ export declare const AWS_ACCESS_KEY_ID_ENV_VAR = "AWS_ACCESS_KEY_ID";
56
+ export declare const AWS_SECRET_ACCESS_KEY_ENV_VAR = "AWS_SECRET_ACCESS_KEY";
57
+ export declare const AWS_DEFAULT_REGION_ENV_VAR = "AWS_DEFAULT_REGION";
58
+ export declare const AWS_SESSION_TOKEN_ENV_VAR = "AWS_SESSION_TOKEN";
53
59
  export declare const LIST_FUNCTIONS_MAX_RETRY_COUNT = 2;
54
60
  export declare const MAX_LAMBDA_STATE_CHECK_ATTEMPTS = 3;
55
61
  export declare const EXTRA_TAGS_REG_EXP: RegExp;
62
+ export declare const AWS_ACCESS_KEY_ID_REG_EXP: RegExp;
63
+ export declare const AWS_SECRET_ACCESS_KEY_REG_EXP: RegExp;
64
+ export declare const DATADOG_API_KEY_REG_EXP: RegExp;
65
+ export declare const DATADOG_APP_KEY_REG_EXP: RegExp;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EXTRA_TAGS_REG_EXP = exports.MAX_LAMBDA_STATE_CHECK_ATTEMPTS = exports.LIST_FUNCTIONS_MAX_RETRY_COUNT = exports.CI_KMS_API_KEY_ENV_VAR = exports.CI_API_KEY_SECRET_ARN_ENV_VAR = exports.CI_API_KEY_ENV_VAR = exports.CI_SITE_ENV_VAR = exports.EXTRA_TAGS_ENV_VAR = exports.ENVIRONMENT_ENV_VAR = exports.VERSION_ENV_VAR = exports.SERVICE_ENV_VAR = exports.LAMBDA_HANDLER_ENV_VAR = exports.LOG_LEVEL_ENV_VAR = exports.FLUSH_TO_LOG_ENV_VAR = exports.MERGE_XRAY_TRACES_ENV_VAR = exports.TRACE_ENABLED_ENV_VAR = exports.SITE_ENV_VAR = exports.KMS_API_KEY_ENV_VAR = exports.API_KEY_SECRET_ARN_ENV_VAR = exports.API_KEY_ENV_VAR = exports.TAG_VERSION_NAME = exports.SUBSCRIPTION_FILTER_NAME = exports.GOVCLOUD_LAYER_AWS_ACCOUNT = exports.DEFAULT_LAYER_AWS_ACCOUNT = exports.SITES = exports.HANDLER_LOCATION = exports.RUNTIME_LOOKUP = exports.RuntimeType = exports.ARM_LAYER_SUFFIX = exports.ARM64_ARCHITECTURE = exports.ARM_RUNTIMES = exports.RUNTIME_LAYER_LOOKUP = exports.EXTENSION_LAYER_KEY = exports.DD_LAMBDA_EXTENSION_LAYER_NAME = void 0;
3
+ exports.DATADOG_APP_KEY_REG_EXP = exports.DATADOG_API_KEY_REG_EXP = exports.AWS_SECRET_ACCESS_KEY_REG_EXP = exports.AWS_ACCESS_KEY_ID_REG_EXP = exports.EXTRA_TAGS_REG_EXP = exports.MAX_LAMBDA_STATE_CHECK_ATTEMPTS = exports.LIST_FUNCTIONS_MAX_RETRY_COUNT = exports.AWS_SESSION_TOKEN_ENV_VAR = exports.AWS_DEFAULT_REGION_ENV_VAR = exports.AWS_SECRET_ACCESS_KEY_ENV_VAR = exports.AWS_ACCESS_KEY_ID_ENV_VAR = exports.CI_KMS_API_KEY_ENV_VAR = exports.CI_API_KEY_SECRET_ARN_ENV_VAR = exports.CI_API_KEY_ENV_VAR = exports.CI_SITE_ENV_VAR = exports.CAPTURE_LAMBDA_PAYLOAD_ENV_VAR = exports.EXTRA_TAGS_ENV_VAR = exports.ENVIRONMENT_ENV_VAR = exports.VERSION_ENV_VAR = exports.SERVICE_ENV_VAR = exports.LAMBDA_HANDLER_ENV_VAR = exports.LOG_LEVEL_ENV_VAR = exports.FLUSH_TO_LOG_ENV_VAR = exports.MERGE_XRAY_TRACES_ENV_VAR = exports.TRACE_ENABLED_ENV_VAR = exports.SITE_ENV_VAR = exports.KMS_API_KEY_ENV_VAR = exports.API_KEY_SECRET_ARN_ENV_VAR = exports.API_KEY_ENV_VAR = exports.TAG_VERSION_NAME = exports.SUBSCRIPTION_FILTER_NAME = exports.GOVCLOUD_LAYER_AWS_ACCOUNT = exports.DEFAULT_LAYER_AWS_ACCOUNT = exports.AWS_REGIONS = exports.SITES = exports.HANDLER_LOCATION = exports.RUNTIME_LOOKUP = exports.RuntimeType = exports.ARM_LAYER_SUFFIX = exports.ARM64_ARCHITECTURE = exports.ARM_RUNTIMES = exports.RUNTIME_LAYER_LOOKUP = exports.EXTENSION_LAYER_KEY = exports.DD_LAMBDA_EXTENSION_LAYER_NAME = void 0;
4
4
  exports.DD_LAMBDA_EXTENSION_LAYER_NAME = 'Datadog-Extension';
5
5
  exports.EXTENSION_LAYER_KEY = 'extension';
6
6
  exports.RUNTIME_LAYER_LOOKUP = {
@@ -43,7 +43,32 @@ exports.SITES = [
43
43
  'datadoghq.eu',
44
44
  'us3.datadoghq.com',
45
45
  'us5.datadoghq.com',
46
- 'ddog-gov.,com',
46
+ 'ddog-gov.com',
47
+ ];
48
+ exports.AWS_REGIONS = [
49
+ 'us-east-1',
50
+ 'us-east-2',
51
+ 'us-west-1',
52
+ 'us-west-2',
53
+ 'af-south-1',
54
+ 'ap-east-1',
55
+ 'ap-south-1',
56
+ 'ap-northeast-3',
57
+ 'ap-northeast-2',
58
+ 'ap-southeast-1',
59
+ 'ap-southeast-2',
60
+ 'ap-northeast-1',
61
+ 'ca-central-1',
62
+ 'eu-central-1',
63
+ 'eu-west-1',
64
+ 'eu-west-2',
65
+ 'eu-south-1',
66
+ 'eu-west-3',
67
+ 'eu-north-1',
68
+ 'me-south-1',
69
+ 'sa-east-1',
70
+ 'us-gov-east-1',
71
+ 'us-gov-west-1',
47
72
  ];
48
73
  exports.DEFAULT_LAYER_AWS_ACCOUNT = '464622532012';
49
74
  exports.GOVCLOUD_LAYER_AWS_ACCOUNT = '002406178527';
@@ -63,11 +88,16 @@ exports.SERVICE_ENV_VAR = 'DD_SERVICE';
63
88
  exports.VERSION_ENV_VAR = 'DD_VERSION';
64
89
  exports.ENVIRONMENT_ENV_VAR = 'DD_ENV';
65
90
  exports.EXTRA_TAGS_ENV_VAR = 'DD_TAGS';
91
+ exports.CAPTURE_LAMBDA_PAYLOAD_ENV_VAR = 'DD_CAPTURE_LAMBDA_PAYLOAD';
66
92
  // Environment variables used by Datadog CI
67
93
  exports.CI_SITE_ENV_VAR = 'DATADOG_SITE';
68
94
  exports.CI_API_KEY_ENV_VAR = 'DATADOG_API_KEY';
69
95
  exports.CI_API_KEY_SECRET_ARN_ENV_VAR = 'DATADOG_API_KEY_SECRET_ARN';
70
96
  exports.CI_KMS_API_KEY_ENV_VAR = 'DATADOG_KMS_API_KEY';
97
+ exports.AWS_ACCESS_KEY_ID_ENV_VAR = 'AWS_ACCESS_KEY_ID';
98
+ exports.AWS_SECRET_ACCESS_KEY_ENV_VAR = 'AWS_SECRET_ACCESS_KEY';
99
+ exports.AWS_DEFAULT_REGION_ENV_VAR = 'AWS_DEFAULT_REGION';
100
+ exports.AWS_SESSION_TOKEN_ENV_VAR = 'AWS_SESSION_TOKEN';
71
101
  exports.LIST_FUNCTIONS_MAX_RETRY_COUNT = 2;
72
102
  exports.MAX_LAMBDA_STATE_CHECK_ATTEMPTS = 3;
73
103
  // DD_TAGS Regular Expression
@@ -75,3 +105,7 @@ exports.MAX_LAMBDA_STATE_CHECK_ATTEMPTS = 3;
75
105
  // matches a list of <key>:<value> separated by commas
76
106
  // such as: layer:api,team:intake
77
107
  exports.EXTRA_TAGS_REG_EXP = /^(([a-zA-Z]+)\w+:[\w\-/\.]+)+((\,)([a-zA-Z]+)\w+:[\w\-/\.]+)*$/g;
108
+ exports.AWS_ACCESS_KEY_ID_REG_EXP = /(?<![A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])/g;
109
+ exports.AWS_SECRET_ACCESS_KEY_REG_EXP = /(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])/g;
110
+ exports.DATADOG_API_KEY_REG_EXP = /(?<![a-f0-9])[a-f0-9]{32}(?![a-f0-9])/g;
111
+ exports.DATADOG_APP_KEY_REG_EXP = /(?<![a-f0-9])[a-f0-9]{40}(?![a-f0-9])/g;