bootstrap.test.js
  1  "use strict";
  2  Object.defineProperty(exports, "__esModule", { value: true });
  3  const bootstrap_1 = require("../../lib/api/bootstrap");
  4  const serialize_1 = require("../../lib/serialize");
  5  const mock_sdk_1 = require("../util/mock-sdk");
  6  const env = {
  7      account: '123456789012',
  8      region: 'us-east-1',
  9      name: 'mock',
 10  };
 11  let sdk;
 12  let executed;
 13  let protectedTermination;
 14  let cfnMocks;
 15  let changeSetTemplate;
 16  let bootstrapper;
 17  beforeEach(() => {
 18      sdk = new mock_sdk_1.MockSdkProvider();
 19      executed = false;
 20      protectedTermination = false;
 21      bootstrapper = new bootstrap_1.Bootstrapper({ source: 'legacy' });
 22      cfnMocks = {
 23          describeStackEvents: jest.fn().mockReturnValue({}),
 24          describeStacks: jest.fn()
 25              // First two calls, no stacks exist (first is for version checking, second is in deploy-stack.ts)
 26              .mockImplementationOnce(() => ({ Stacks: [] }))
 27              .mockImplementationOnce(() => ({ Stacks: [] }))
 28              // Second call, stack has been created
 29              .mockImplementationOnce(() => ({
 30              Stacks: [
 31                  {
 32                      StackStatus: 'CREATE_COMPLETE',
 33                      StackStatusReason: 'It is magic',
 34                      EnableTerminationProtection: false,
 35                  },
 36              ],
 37          })),
 38          createChangeSet: jest.fn((info) => {
 39              changeSetTemplate = serialize_1.deserializeStructure(info.TemplateBody);
 40              return {};
 41          }),
 42          describeChangeSet: jest.fn(() => ({
 43              Status: 'CREATE_COMPLETE',
 44              Changes: [],
 45          })),
 46          executeChangeSet: jest.fn(() => {
 47              executed = true;
 48              return {};
 49          }),
 50          deleteChangeSet: jest.fn(),
 51          getTemplate: jest.fn(() => {
 52              executed = true;
 53              return {};
 54          }),
 55          deleteStack: jest.fn(),
 56          updateTerminationProtection: jest.fn(() => {
 57              protectedTermination = true;
 58              return {};
 59          }),
 60      };
 61      sdk.stubCloudFormation(cfnMocks);
 62  });
 63  test('do bootstrap', async () => {
 64      // WHEN
 65      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, { toolkitStackName: 'mockStack' });
 66      // THEN
 67      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
 68      expect(bucketProperties.BucketName).toBeUndefined();
 69      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
 70          .toBeUndefined();
 71      expect(changeSetTemplate.Conditions.UsePublicAccessBlockConfiguration['Fn::Equals'][0]).toBe('true');
 72      expect(ret.noOp).toBeFalsy();
 73      expect(executed).toBeTruthy();
 74  });
 75  test('do bootstrap using custom bucket name', async () => {
 76      // WHEN
 77      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, {
 78          toolkitStackName: 'mockStack',
 79          parameters: {
 80              bucketName: 'foobar',
 81          },
 82      });
 83      // THEN
 84      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
 85      expect(bucketProperties.BucketName).toBe('foobar');
 86      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
 87          .toBeUndefined();
 88      expect(changeSetTemplate.Conditions.UsePublicAccessBlockConfiguration['Fn::Equals'][0]).toBe('true');
 89      expect(ret.noOp).toBeFalsy();
 90      expect(executed).toBeTruthy();
 91  });
 92  test('do bootstrap using KMS CMK', async () => {
 93      // WHEN
 94      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, {
 95          toolkitStackName: 'mockStack',
 96          parameters: {
 97              kmsKeyId: 'myKmsKey',
 98          },
 99      });
100      // THEN
101      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
102      expect(bucketProperties.BucketName).toBeUndefined();
103      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
104          .toBe('myKmsKey');
105      expect(changeSetTemplate.Conditions.UsePublicAccessBlockConfiguration['Fn::Equals'][0]).toBe('true');
106      expect(ret.noOp).toBeFalsy();
107      expect(executed).toBeTruthy();
108  });
109  test('bootstrap disable bucket Public Access Block Configuration', async () => {
110      // WHEN
111      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, {
112          toolkitStackName: 'mockStack',
113          parameters: {
114              publicAccessBlockConfiguration: false,
115          },
116      });
117      // THEN
118      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
119      expect(bucketProperties.BucketName).toBeUndefined();
120      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
121          .toBeUndefined();
122      expect(changeSetTemplate.Conditions.UsePublicAccessBlockConfiguration['Fn::Equals'][0]).toBe('false');
123      expect(ret.noOp).toBeFalsy();
124      expect(executed).toBeTruthy();
125  });
126  test('do bootstrap with custom tags for toolkit stack', async () => {
127      // WHEN
128      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, {
129          toolkitStackName: 'mockStack',
130          tags: [{ Key: 'Foo', Value: 'Bar' }],
131      });
132      // THEN
133      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
134      expect(bucketProperties.BucketName).toBeUndefined();
135      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
136          .toBeUndefined();
137      expect(changeSetTemplate.Conditions.UsePublicAccessBlockConfiguration['Fn::Equals'][0]).toBe('true');
138      expect(ret.noOp).toBeFalsy();
139      expect(executed).toBeTruthy();
140  });
141  test('passing trusted accounts to the old bootstrapping results in an error', async () => {
142      await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
143          toolkitStackName: 'mockStack',
144          parameters: {
145              trustedAccounts: ['0123456789012'],
146          },
147      }))
148          .rejects
149          .toThrow('--trust can only be passed for the modern bootstrap experience.');
150  });
151  test('passing CFN execution policies to the old bootstrapping results in an error', async () => {
152      await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
153          toolkitStackName: 'mockStack',
154          parameters: {
155              cloudFormationExecutionPolicies: ['arn:aws:iam::aws:policy/AdministratorAccess'],
156          },
157      }))
158          .rejects
159          .toThrow('--cloudformation-execution-policies can only be passed for the modern bootstrap experience.');
160  });
161  test('even if the bootstrap stack is in a rollback state, can still retry bootstrapping it', async () => {
162      cfnMocks.describeStacks
163          .mockReset()
164          // First two calls, the stack exists with a 'rollback complete' status
165          // (first is for version checking, second is in deploy-stack.ts)
166          .mockImplementationOnce(() => ({
167          Stacks: [
168              {
169                  StackStatus: 'UPDATE_ROLLBACK_COMPLETE',
170                  StackStatusReason: 'It is magic',
171                  Outputs: [
172                      { OutputKey: 'BucketName', OutputValue: 'bucket' },
173                      { OutputKey: 'BucketDomainName', OutputValue: 'aws.com' },
174                  ],
175              },
176          ],
177      }))
178          .mockImplementationOnce(() => ({
179          Stacks: [
180              {
181                  StackStatus: 'UPDATE_ROLLBACK_COMPLETE',
182                  StackStatusReason: 'It is magic',
183                  Outputs: [
184                      { OutputKey: 'BucketName', OutputValue: 'bucket' },
185                      { OutputKey: 'BucketDomainName', OutputValue: 'aws.com' },
186                  ],
187              },
188          ],
189      }))
190          // Third call, stack has been created
191          .mockImplementationOnce(() => ({
192          Stacks: [
193              {
194                  StackStatus: 'CREATE_COMPLETE',
195                  StackStatusReason: 'It is magic',
196                  EnableTerminationProtection: false,
197              },
198          ],
199      }));
200      // WHEN
201      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, { toolkitStackName: 'mockStack' });
202      // THEN
203      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
204      expect(bucketProperties.BucketName).toBeUndefined();
205      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
206          .toBeUndefined();
207      expect(ret.noOp).toBeFalsy();
208      expect(executed).toBeTruthy();
209  });
210  test('even if the bootstrap stack failed to create, can still retry bootstrapping it', async () => {
211      cfnMocks.describeStacks
212          .mockReset()
213          // First two calls, the stack exists with a 'rollback complete' status
214          // (first is for version checking, second is in deploy-stack.ts)
215          .mockImplementationOnce(() => ({
216          Stacks: [
217              {
218                  StackStatus: 'ROLLBACK_COMPLETE',
219                  StackStatusReason: 'It is magic',
220                  Outputs: [
221                      { OutputKey: 'BucketName', OutputValue: 'bucket' },
222                  ],
223              },
224          ],
225      }))
226          .mockImplementationOnce(() => ({
227          Stacks: [
228              {
229                  StackStatus: 'ROLLBACK_COMPLETE',
230                  StackStatusReason: 'It is magic',
231                  Outputs: [
232                      { OutputKey: 'BucketName', OutputValue: 'bucket' },
233                  ],
234              },
235          ],
236      }))
237          // Third call, we just did a delete and want to see it gone
238          .mockImplementationOnce(() => ({ Stacks: [] }))
239          // Fourth call, stack has been created
240          .mockImplementationOnce(() => ({
241          Stacks: [
242              {
243                  StackStatus: 'CREATE_COMPLETE',
244                  StackStatusReason: 'It is magic',
245                  EnableTerminationProtection: false,
246              },
247          ],
248      }));
249      // WHEN
250      const ret = await bootstrapper.bootstrapEnvironment(env, sdk, { toolkitStackName: 'mockStack' });
251      // THEN
252      const bucketProperties = changeSetTemplate.Resources.StagingBucket.Properties;
253      expect(bucketProperties.BucketName).toBeUndefined();
254      expect(bucketProperties.BucketEncryption.ServerSideEncryptionConfiguration[0].ServerSideEncryptionByDefault.KMSMasterKeyID)
255          .toBeUndefined();
256      expect(ret.noOp).toBeFalsy();
257      expect(executed).toBeTruthy();
258      expect(cfnMocks.deleteStack).toHaveBeenCalled();
259  });
260  test('stack is not termination protected by default', async () => {
261      // WHEN
262      await bootstrapper.bootstrapEnvironment(env, sdk);
263      // THEN
264      expect(executed).toBeTruthy();
265      expect(protectedTermination).toBeFalsy();
266  });
267  test('stack is termination protected when set', async () => {
268      // WHEN
269      await bootstrapper.bootstrapEnvironment(env, sdk, {
270          terminationProtection: true,
271      });
272      // THEN
273      expect(executed).toBeTruthy();
274      expect(protectedTermination).toBeTruthy();
275  });
276  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJib290c3RyYXAudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUNBLHVEQUF1RDtBQUN2RCxtREFBMkQ7QUFDM0QsK0NBQXdFO0FBRXhFLE1BQU0sR0FBRyxHQUFHO0lBQ1YsT0FBTyxFQUFFLGNBQWM7SUFDdkIsTUFBTSxFQUFFLFdBQVc7SUFDbkIsSUFBSSxFQUFFLE1BQU07Q0FDYixDQUFDO0FBRUYsSUFBSSxHQUFvQixDQUFDO0FBQ3pCLElBQUksUUFBaUIsQ0FBQztBQUN0QixJQUFJLG9CQUE2QixDQUFDO0FBQ2xDLElBQUksUUFBOEQsQ0FBQztBQUNuRSxJQUFJLGlCQUFrQyxDQUFDO0FBQ3ZDLElBQUksWUFBMEIsQ0FBQztBQUMvQixVQUFVLENBQUMsR0FBRyxFQUFFO0lBQ2QsR0FBRyxHQUFHLElBQUksMEJBQWUsRUFBRSxDQUFDO0lBQzVCLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDakIsb0JBQW9CLEdBQUcsS0FBSyxDQUFDO0lBQzdCLFlBQVksR0FBRyxJQUFJLHdCQUFZLENBQUMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUV0RCxRQUFRLEdBQUc7UUFDVCxtQkFBbUIsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUNsRCxjQUFjLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtZQUN2QixpR0FBaUc7YUFDaEcsc0JBQXNCLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2FBQzlDLHNCQUFzQixDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUMvQyxzQ0FBc0M7YUFDckMsc0JBQXNCLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUM3QixNQUFNLEVBQUU7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RUFBRSxDQUFDO0lBQzdCLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUM5QixNQUFNLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDLGdCQUFnQixFQUFFLENBQUM7QUFDbEQsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsK0NBQStDLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDL0QsT0FBTztJQUNQLE1BQU0sWUFBWSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUVsRCxPQUFPO0lBQ1AsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQzlCLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDO0FBQzNDLENBQUMsQ0FBQyxDQUFDO0FBRUgsSUFBSSxDQUFDLHlDQUF5QyxFQUFFLEtBQUssSUFBSSxFQUFFO0lBQ3pELE9BQU87SUFDUCxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1FBQ2hELHFCQUFxQixFQUFFLElBQUk7S0FDNUIsQ0FBQyxDQUFDO0lBRUgsT0FBTztJQUNQLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUM5QixNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztBQUM1QyxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENyZWF0ZUNoYW5nZVNldElucHV0IH0gZnJvbSAnYXdzLXNkay9jbGllbnRzL2Nsb3VkZm9ybWF0aW9uJztcbmltcG9ydCB7IEJvb3RzdHJhcHBlciB9IGZyb20gJy4uLy4uL2xpYi9hcGkvYm9vdHN0cmFwJztcbmltcG9ydCB7IGRlc2VyaWFsaXplU3RydWN0dXJlIH0gZnJvbSAnLi4vLi4vbGliL3NlcmlhbGl6ZSc7XG5pbXBvcnQgeyBNb2NrU2RrUHJvdmlkZXIsIFN5bmNIYW5kbGVyU3Vic2V0T2YgfSBmcm9tICcuLi91dGlsL21vY2stc2RrJztcblxuY29uc3QgZW52ID0ge1xuICBhY2NvdW50OiAnMTIzNDU2Nzg5MDEyJyxcbiAgcmVnaW9uOiAndXMtZWFzdC0xJyxcbiAgbmFtZTogJ21vY2snLFxufTtcblxubGV0IHNkazogTW9ja1Nka1Byb3ZpZGVyO1xubGV0IGV4ZWN1dGVkOiBib29sZWFuO1xubGV0IHByb3RlY3RlZFRlcm1pbmF0aW9uOiBib29sZWFuO1xubGV0IGNmbk1vY2tzOiBqZXN0Lk1vY2tlZDxTeW5jSGFuZGxlclN1YnNldE9mPEFXUy5DbG91ZEZvcm1hdGlvbj4+O1xubGV0IGNoYW5nZVNldFRlbXBsYXRlOiBhbnkgfCB1bmRlZmluZWQ7XG5sZXQgYm9vdHN0cmFwcGVyOiBCb290c3RyYXBwZXI7XG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgc2RrID0gbmV3IE1vY2tTZGtQcm92aWRlcigpO1xuICBleGVjdXRlZCA9IGZhbHNlO1xuICBwcm90ZWN0ZWRUZXJtaW5hdGlvbiA9IGZhbHNlO1xuICBib290c3RyYXBwZXIgPSBuZXcgQm9vdHN0cmFwcGVyKHsgc291cmNlOiAnbGVnYWN5JyB9KTtcblxuICBjZm5Nb2NrcyA9IHtcbiAgICBkZXNjcmliZVN0YWNrRXZlbnRzOiBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKHt9KSxcbiAgICBkZXNjcmliZVN0YWNrczogamVzdC5mbigpXG4gICAgICAvLyBGaXJzdCB0d28gY2FsbHMsIG5vIHN0YWNrcyBleGlzdCAoZmlyc3QgaXMgZm9yIHZlcnNpb24gY2hlY2tpbmcsIHNlY29uZCBpcyBpbiBkZXBsb3ktc3RhY2sudHMpXG4gICAgICAubW9ja0ltcGxlbWVudGF0aW9uT25jZSgoKSA9PiAoeyBTdGFja3M6IFtdIH0pKVxuICAgICAgLm1vY2tJbXBsZW1lbnRhdGlvbk9uY2UoKCkgPT4gKHsgU3RhY2tzOiBbXSB9KSlcbiAgICAgIC8vIFNlY29uZCBjYWxsLCBzdGFjayBoYXMgYmVlbiBjcmVhdGVkXG4gICAgICAubW9ja0ltcGxlbWVudGF0aW9uT25jZSgoKSA9PiAoe1xuICAgICAgICBTdGFja3M6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBTdGFja1N0YXR1czogJ0NSRUFURV9DT01QTEVURScsXG4gICAgICAgICAgICBTdGFja1N0YXR1c1JlYXNvbjogJ0l0IGlzIG1hZ2ljJyxcbiAgICAgICAgICAgIEVuYWJsZVRlcm1pbmF0aW9uUHJvdGVjdGlvbjogZmFsc2UsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pKSxcbiAgICBjcmVhdGVDaGFuZ2VTZXQ6IGplc3QuZm4oKGluZm86IENyZWF0ZUNoYW5nZVNldElucHV0KSA9PiB7XG4gICAgICBjaGFuZ2VTZXRUZW1wbGF0ZSA9IGRlc2VyaWFsaXplU3RydWN0dXJlKGluZm8uVGVtcGxhdGVCb2R5IGFzIHN0cmluZyk7XG4gICAgICByZXR1cm4ge307XG4gICAgfSksXG4gICAgZGVzY3JpYmVDaGFuZ2VTZXQ6IGplc3QuZm4oKCkgPT4gKHtcbiAgICAgIFN0YXR1czogJ0NSRUFURV9DT01QTEVURScsXG4gICAgICBDaGFuZ2VzOiBbXSxcbiAgICB9KSksXG4gICAgZXhlY3V0ZUNoYW5nZVNldDogamVzdC5mbigoKSA9PiB7XG4gICAgICBleGVjdXRlZCA9IHRydWU7XG4gICAgICByZXR1cm4ge307XG4gICAgfSksXG4gICAgZGVsZXRlQ2hhbmdlU2V0OiBqZXN0LmZuKCksXG4gICAgZ2V0VGVtcGxhdGU6IGplc3QuZm4oKCkgPT4ge1xuICAgICAgZXhlY3V0ZWQgPSB0cnVlO1xuICAgICAgcmV0dXJuIHt9O1xuICAgIH0pLFxuICAgIGRlbGV0ZVN0YWNrOiBqZXN0LmZuKCksXG4gICAgdXBkYXRlVGVybWluYXRpb25Qcm90ZWN0aW9uOiBqZXN0LmZuKCgpID0+IHtcbiAgICAgIHByb3RlY3RlZFRlcm1pbmF0aW9uID0gdHJ1ZTtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9KSxcbiAgfTtcbiAgc2RrLnN0dWJDbG91ZEZvcm1hdGlvbihjZm5Nb2Nrcyk7XG59KTtcblxudGVzdCgnZG8gYm9vdHN0cmFwJywgYXN5bmMgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IHJldCA9IGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywgeyB0b29sa2l0U3RhY2tOYW1lOiAnbW9ja1N0YWNrJyB9KTtcblxuICAvLyBUSEVOXG4gIGNvbnN0IGJ1Y2tldFByb3BlcnRpZXMgPSBjaGFuZ2VTZXRUZW1wbGF0ZS5SZXNvdXJjZXMuU3RhZ2luZ0J1Y2tldC5Qcm9wZXJ0aWVzO1xuICBleHBlY3QoYnVja2V0UHJvcGVydGllcy5CdWNrZXROYW1lKS50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChidWNrZXRQcm9wZXJ0aWVzLkJ1Y2tldEVuY3J5cHRpb24uU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uWzBdLlNlcnZlclNpZGVFbmNyeXB0aW9uQnlEZWZhdWx0LktNU01hc3RlcktleUlEKVxuICAgIC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChjaGFuZ2VTZXRUZW1wbGF0ZS5Db25kaXRpb25zLlVzZVB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvblsnRm46OkVxdWFscyddWzBdKS50b0JlKCd0cnVlJyk7XG4gIGV4cGVjdChyZXQubm9PcCkudG9CZUZhbHN5KCk7XG4gIGV4cGVjdChleGVjdXRlZCkudG9CZVRydXRoeSgpO1xufSk7XG5cbnRlc3QoJ2RvIGJvb3RzdHJhcCB1c2luZyBjdXN0b20gYnVja2V0IG5hbWUnLCBhc3luYyAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgcmV0ID0gYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogJ21vY2tTdGFjaycsXG4gICAgcGFyYW1ldGVyczoge1xuICAgICAgYnVja2V0TmFtZTogJ2Zvb2JhcicsXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gVEhFTlxuICBjb25zdCBidWNrZXRQcm9wZXJ0aWVzID0gY2hhbmdlU2V0VGVtcGxhdGUuUmVzb3VyY2VzLlN0YWdpbmdCdWNrZXQuUHJvcGVydGllcztcbiAgZXhwZWN0KGJ1Y2tldFByb3BlcnRpZXMuQnVja2V0TmFtZSkudG9CZSgnZm9vYmFyJyk7XG4gIGV4cGVjdChidWNrZXRQcm9wZXJ0aWVzLkJ1Y2tldEVuY3J5cHRpb24uU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uWzBdLlNlcnZlclNpZGVFbmNyeXB0aW9uQnlEZWZhdWx0LktNU01hc3RlcktleUlEKVxuICAgIC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChjaGFuZ2VTZXRUZW1wbGF0ZS5Db25kaXRpb25zLlVzZVB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvblsnRm46OkVxdWFscyddWzBdKS50b0JlKCd0cnVlJyk7XG4gIGV4cGVjdChyZXQubm9PcCkudG9CZUZhbHN5KCk7XG4gIGV4cGVjdChleGVjdXRlZCkudG9CZVRydXRoeSgpO1xufSk7XG5cbnRlc3QoJ2RvIGJvb3RzdHJhcCB1c2luZyBLTVMgQ01LJywgYXN5bmMgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGNvbnN0IHJldCA9IGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgIHRvb2xraXRTdGFja05hbWU6ICdtb2NrU3RhY2snLFxuICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgIGttc0tleUlkOiAnbXlLbXNLZXknLFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIFRIRU5cbiAgY29uc3QgYnVja2V0UHJvcGVydGllcyA9IGNoYW5nZVNldFRlbXBsYXRlLlJlc291cmNlcy5TdGFnaW5nQnVja2V0LlByb3BlcnRpZXM7XG4gIGV4cGVjdChidWNrZXRQcm9wZXJ0aWVzLkJ1Y2tldE5hbWUpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KGJ1Y2tldFByb3BlcnRpZXMuQnVja2V0RW5jcnlwdGlvbi5TZXJ2ZXJTaWRlRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb25bMF0uU2VydmVyU2lkZUVuY3J5cHRpb25CeURlZmF1bHQuS01TTWFzdGVyS2V5SUQpXG4gICAgLnRvQmUoJ215S21zS2V5Jyk7XG4gIGV4cGVjdChjaGFuZ2VTZXRUZW1wbGF0ZS5Db25kaXRpb25zLlVzZVB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvblsnRm46OkVxdWFscyddWzBdKS50b0JlKCd0cnVlJyk7XG4gIGV4cGVjdChyZXQubm9PcCkudG9CZUZhbHN5KCk7XG4gIGV4cGVjdChleGVjdXRlZCkudG9CZVRydXRoeSgpO1xufSk7XG5cbnRlc3QoJ2Jvb3RzdHJhcCBkaXNhYmxlIGJ1Y2tldCBQdWJsaWMgQWNjZXNzIEJsb2NrIENvbmZpZ3VyYXRpb24nLCBhc3luYyAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgY29uc3QgcmV0ID0gYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogJ21vY2tTdGFjaycsXG4gICAgcGFyYW1ldGVyczoge1xuICAgICAgcHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiBmYWxzZSxcbiAgICB9LFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGNvbnN0IGJ1Y2tldFByb3BlcnRpZXMgPSBjaGFuZ2VTZXRUZW1wbGF0ZS5SZXNvdXJjZXMuU3RhZ2luZ0J1Y2tldC5Qcm9wZXJ0aWVzO1xuICBleHBlY3QoYnVja2V0UHJvcGVydGllcy5CdWNrZXROYW1lKS50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChidWNrZXRQcm9wZXJ0aWVzLkJ1Y2tldEVuY3J5cHRpb24uU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uWzBdLlNlcnZlclNpZGVFbmNyeXB0aW9uQnlEZWZhdWx0LktNU01hc3RlcktleUlEKVxuICAgIC50b0JlVW5kZWZpbmVkKCk7XG4gIGV4cGVjdChjaGFuZ2VTZXRUZW1wbGF0ZS5Db25kaXRpb25zLlVzZVB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvblsnRm46OkVxdWFscyddWzBdKS50b0JlKCdmYWxzZScpO1xuICBleHBlY3QocmV0Lm5vT3ApLnRvQmVGYWxzeSgpO1xuICBleHBlY3QoZXhlY3V0ZWQpLnRvQmVUcnV0aHkoKTtcbn0pO1xuXG50ZXN0KCdkbyBib290c3RyYXAgd2l0aCBjdXN0b20gdGFncyBmb3IgdG9vbGtpdCBzdGFjaycsIGFzeW5jICgpID0+IHtcbiAgLy8gV0hFTlxuICBjb25zdCByZXQgPSBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICB0b29sa2l0U3RhY2tOYW1lOiAnbW9ja1N0YWNrJyxcbiAgICB0YWdzOiBbeyBLZXk6ICdGb28nLCBWYWx1ZTogJ0JhcicgfV0sXG4gIH0pO1xuXG4gIC8vIFRIRU5cbiAgY29uc3QgYnVja2V0UHJvcGVydGllcyA9IGNoYW5nZVNldFRlbXBsYXRlLlJlc291cmNlcy5TdGFnaW5nQnVja2V0LlByb3BlcnRpZXM7XG4gIGV4cGVjdChidWNrZXRQcm9wZXJ0aWVzLkJ1Y2tldE5hbWUpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KGJ1Y2tldFByb3BlcnRpZXMuQnVja2V0RW5jcnlwdGlvbi5TZXJ2ZXJTaWRlRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb25bMF0uU2VydmVyU2lkZUVuY3J5cHRpb25CeURlZmF1bHQuS01TTWFzdGVyS2V5SUQpXG4gICAgLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KGNoYW5nZVNldFRlbXBsYXRlLkNvbmRpdGlvbnMuVXNlUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uWydGbjo6RXF1YWxzJ11bMF0pLnRvQmUoJ3RydWUnKTtcbiAgZXhwZWN0KHJldC5ub09wKS50b0JlRmFsc3koKTtcbiAgZXhwZWN0KGV4ZWN1dGVkKS50b0JlVHJ1dGh5KCk7XG59KTtcblxudGVzdCgncGFzc2luZyB0cnVzdGVkIGFjY291bnRzIHRvIHRoZSBvbGQgYm9vdHN0cmFwcGluZyByZXN1bHRzIGluIGFuIGVycm9yJywgYXN5bmMgKCkgPT4ge1xuICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgdG9vbGtpdFN0YWNrTmFtZTogJ21vY2tTdGFjaycsXG4gICAgcGFyYW1ldGVyczoge1xuICAgICAgdHJ1c3RlZEFjY291bnRzOiBbJzAxMjM0NTY3ODkwMTInXSxcbiAgICB9LFxuICB9KSlcbiAgICAucmVqZWN0c1xuICAgIC50b1Rocm93KCctLXRydXN0IGNhbiBvbmx5IGJlIHBhc3NlZCBmb3IgdGhlIG1vZGVybiBib290c3RyYXAgZXhwZXJpZW5jZS4nKTtcbn0pO1xuXG50ZXN0KCdwYXNzaW5nIENGTiBleGVjdXRpb24gcG9saWNpZXMgdG8gdGhlIG9sZCBib290c3RyYXBwaW5nIHJlc3VsdHMgaW4gYW4gZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gIGF3YWl0IGV4cGVjdChib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICB0b29sa2l0U3RhY2tOYW1lOiAnbW9ja1N0YWNrJyxcbiAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjphd3M6aWFtOjphd3M6cG9saWN5L0FkbWluaXN0cmF0b3JBY2Nlc3MnXSxcbiAgICB9LFxuICB9KSlcbiAgICAucmVqZWN0c1xuICAgIC50b1Rocm93KCctLWNsb3VkZm9ybWF0aW9uLWV4ZWN1dGlvbi1wb2xpY2llcyBjYW4gb25seSBiZSBwYXNzZWQgZm9yIHRoZSBtb2Rlcm4gYm9vdHN0cmFwIGV4cGVyaWVuY2UuJyk7XG59KTtcblxudGVzdCgnZXZlbiBpZiB0aGUgYm9vdHN0cmFwIHN0YWNrIGlzIGluIGEgcm9sbGJhY2sgc3RhdGUsIGNhbiBzdGlsbCByZXRyeSBib290c3RyYXBwaW5nIGl0JywgYXN5bmMgKCkgPT4ge1xuICAoY2ZuTW9ja3MuZGVzY3JpYmVTdGFja3MhIGFzIGplc3QuTW9jaylcbiAgICAubW9ja1Jlc2V0KClcbiAgICAvLyBGaXJzdCB0d28gY2FsbHMsIHRoZSBzdGFjayBleGlzdHMgd2l0aCBhICdyb2xsYmFjayBjb21wbGV0ZScgc3RhdHVzXG4gICAgLy8gKGZpcnN0IGlzIGZvciB2ZXJzaW9uIGNoZWNraW5nLCBzZWNvbmQgaXMgaW4gZGVwbG95LXN0YWNrLnRzKVxuICAgIC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKCgpID0+ICh7XG4gICAgICBTdGFja3M6IFtcbiAgICAgICAge1xuICAgICAgICAgIFN0YWNrU3RhdHVzOiAnVVBEQVRFX1JPTExCQUNLX0NPTVBMRVRFJyxcbiAgICAgICAgICBTdGFja1N0YXR1c1JlYXNvbjogJ0l0IGlzIG1hZ2ljJyxcbiAgICAgICAgICBPdXRwdXRzOiBbXG4gICAgICAgICAgICB7IE91dHB1dEtleTogJ0J1Y2tldE5hbWUnLCBPdXRwdXRWYWx1ZTogJ2J1Y2tldCcgfSxcbiAgICAgICAgICAgIHsgT3V0cHV0S2V5OiAnQnVja2V0RG9tYWluTmFtZScsIE91dHB1dFZhbHVlOiAnYXdzLmNvbScgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KSlcbiAgICAubW9ja0ltcGxlbWVudGF0aW9uT25jZSgoKSA9PiAoe1xuICAgICAgU3RhY2tzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBTdGFja1N0YXR1czogJ1VQREFURV9ST0xMQkFDS19DT01QTEVURScsXG4gICAgICAgICAgU3RhY2tTdGF0dXNSZWFzb246ICdJdCBpcyBtYWdpYycsXG4gICAgICAgICAgT3V0cHV0czogW1xuICAgICAgICAgICAgeyBPdXRwdXRLZXk6ICdCdWNrZXROYW1lJywgT3V0cHV0VmFsdWU6ICdidWNrZXQnIH0sXG4gICAgICAgICAgICB7IE91dHB1dEtleTogJ0J1Y2tldERvbWFpbk5hbWUnLCBPdXRwdXRWYWx1ZTogJ2F3cy5jb20nIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSkpXG4gICAgLy8gVGhpcmQgY2FsbCwgc3RhY2sgaGFzIGJlZW4gY3JlYXRlZFxuICAgIC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKCgpID0+ICh7XG4gICAgICBTdGFja3M6IFtcbiAgICAgICAge1xuICAgICAgICAgIFN0YWNrU3RhdHVzOiAnQ1JFQVRFX0NPTVBMRVRFJyxcbiAgICAgICAgICBTdGFja1N0YXR1c1JlYXNvbjogJ0l0IGlzIG1hZ2ljJyxcbiAgICAgICAgICBFbmFibGVUZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCByZXQgPSBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHsgdG9vbGtpdFN0YWNrTmFtZTogJ21vY2tTdGFjaycgfSk7XG5cbiAgLy8gVEhFTlxuICBjb25zdCBidWNrZXRQcm9wZXJ0aWVzID0gY2hhbmdlU2V0VGVtcGxhdGUuUmVzb3VyY2VzLlN0YWdpbmdCdWNrZXQuUHJvcGVydGllcztcbiAgZXhwZWN0KGJ1Y2tldFByb3BlcnRpZXMuQnVja2V0TmFtZSkudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QoYnVja2V0UHJvcGVydGllcy5CdWNrZXRFbmNyeXB0aW9uLlNlcnZlclNpZGVFbmNyeXB0aW9uQ29uZmlndXJhdGlvblswXS5TZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdC5LTVNNYXN0ZXJLZXlJRClcbiAgICAudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QocmV0Lm5vT3ApLnRvQmVGYWxzeSgpO1xuICBleHBlY3QoZXhlY3V0ZWQpLnRvQmVUcnV0aHkoKTtcbn0pO1xuXG50ZXN0KCdldmVuIGlmIHRoZSBib290c3RyYXAgc3RhY2sgZmFpbGVkIHRvIGNyZWF0ZSwgY2FuIHN0aWxsIHJldHJ5IGJvb3RzdHJhcHBpbmcgaXQnLCBhc3luYyAoKSA9PiB7XG4gIChjZm5Nb2Nrcy5kZXNjcmliZVN0YWNrcyEgYXMgamVzdC5Nb2NrKVxuICAgIC5tb2NrUmVzZXQoKVxuICAgIC8vIEZpcnN0IHR3byBjYWxscywgdGhlIHN0YWNrIGV4aXN0cyB3aXRoIGEgJ3JvbGxiYWNrIGNvbXBsZXRlJyBzdGF0dXNcbiAgICAvLyAoZmlyc3QgaXMgZm9yIHZlcnNpb24gY2hlY2tpbmcsIHNlY29uZCBpcyBpbiBkZXBsb3ktc3RhY2sudHMpXG4gICAgLm1vY2tJbXBsZW1lbnRhdGlvbk9uY2UoKCkgPT4gKHtcbiAgICAgIFN0YWNrczogW1xuICAgICAgICB7XG4gICAgICAgICAgU3RhY2tTdGF0dXM6ICdST0xMQkFDS19DT01QTEVURScsXG4gICAgICAgICAgU3RhY2tTdGF0dXNSZWFzb246ICdJdCBpcyBtYWdpYycsXG4gICAgICAgICAgT3V0cHV0czogW1xuICAgICAgICAgICAgeyBPdXRwdXRLZXk6ICdCdWNrZXROYW1lJywgT3V0cHV0VmFsdWU6ICdidWNrZXQnIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSBhcyBBV1MuQ2xvdWRGb3JtYXRpb24uU3RhY2ssXG4gICAgICBdLFxuICAgIH0pKVxuICAgIC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKCgpID0+ICh7XG4gICAgICBTdGFja3M6IFtcbiAgICAgICAge1xuICAgICAgICAgIFN0YWNrU3RhdHVzOiAnUk9MTEJBQ0tfQ09NUExFVEUnLFxuICAgICAgICAgIFN0YWNrU3RhdHVzUmVhc29uOiAnSXQgaXMgbWFnaWMnLFxuICAgICAgICAgIE91dHB1dHM6IFtcbiAgICAgICAgICAgIHsgT3V0cHV0S2V5OiAnQnVja2V0TmFtZScsIE91dHB1dFZhbHVlOiAnYnVja2V0JyB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pKVxuICAgIC8vIFRoaXJkIGNhbGwsIHdlIGp1c3QgZGlkIGEgZGVsZXRlIGFuZCB3YW50IHRvIHNlZSBpdCBnb25lXG4gICAgLm1vY2tJbXBsZW1lbnRhdGlvbk9uY2UoKCkgPT4gKHsgU3RhY2tzOiBbXSB9KSlcbiAgICAvLyBGb3VydGggY2FsbCwgc3RhY2sgaGFzIGJlZW4gY3JlYXRlZFxuICAgIC5tb2NrSW1wbGVtZW50YXRpb25PbmNlKCgpID0+ICh7XG4gICAgICBTdGFja3M6IFtcbiAgICAgICAge1xuICAgICAgICAgIFN0YWNrU3RhdHVzOiAnQ1JFQVRFX0NPTVBMRVRFJyxcbiAgICAgICAgICBTdGFja1N0YXR1c1JlYXNvbjogJ0l0IGlzIG1hZ2ljJyxcbiAgICAgICAgICBFbmFibGVUZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCByZXQgPSBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHsgdG9vbGtpdFN0YWNrTmFtZTogJ21vY2tTdGFjaycgfSk7XG5cbiAgLy8gVEhFTlxuICBjb25zdCBidWNrZXRQcm9wZXJ0aWVzID0gY2hhbmdlU2V0VGVtcGxhdGUuUmVzb3VyY2VzLlN0YWdpbmdCdWNrZXQuUHJvcGVydGllcztcbiAgZXhwZWN0KGJ1Y2tldFByb3BlcnRpZXMuQnVja2V0TmFtZSkudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QoYnVja2V0UHJvcGVydGllcy5CdWNrZXRFbmNyeXB0aW9uLlNlcnZlclNpZGVFbmNyeXB0aW9uQ29uZmlndXJhdGlvblswXS5TZXJ2ZXJTaWRlRW5jcnlwdGlvbkJ5RGVmYXVsdC5LTVNNYXN0ZXJLZXlJRClcbiAgICAudG9CZVVuZGVmaW5lZCgpO1xuICBleHBlY3QocmV0Lm5vT3ApLnRvQmVGYWxzeSgpO1xuICBleHBlY3QoZXhlY3V0ZWQpLnRvQmVUcnV0aHkoKTtcbiAgZXhwZWN0KGNmbk1vY2tzLmRlbGV0ZVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG59KTtcblxudGVzdCgnc3RhY2sgaXMgbm90IHRlcm1pbmF0aW9uIHByb3RlY3RlZCBieSBkZWZhdWx0JywgYXN5bmMgKCkgPT4ge1xuICAvLyBXSEVOXG4gIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkayk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZXhlY3V0ZWQpLnRvQmVUcnV0aHkoKTtcbiAgZXhwZWN0KHByb3RlY3RlZFRlcm1pbmF0aW9uKS50b0JlRmFsc3koKTtcbn0pO1xuXG50ZXN0KCdzdGFjayBpcyB0ZXJtaW5hdGlvbiBwcm90ZWN0ZWQgd2hlbiBzZXQnLCBhc3luYyAoKSA9PiB7XG4gIC8vIFdIRU5cbiAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiB0cnVlLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChleGVjdXRlZCkudG9CZVRydXRoeSgpO1xuICBleHBlY3QocHJvdGVjdGVkVGVybWluYXRpb24pLnRvQmVUcnV0aHkoKTtcbn0pO1xuIl19