UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

493 lines 60.6 kB
"use strict"; /* eslint-disable import/order */ Object.defineProperty(exports, "__esModule", { value: true }); const deployStack = require("../../lib/api/deployments/deploy-stack"); const client_iam_1 = require("@aws-sdk/client-iam"); const api_1 = require("../../lib/api"); const mock_sdk_1 = require("../util/mock-sdk"); const cli_io_host_1 = require("../../lib/toolkit/cli-io-host"); const mockDeployStack = jest.spyOn(deployStack, 'deployStack'); let bootstrapper; let stderrMock; beforeEach(() => { cli_io_host_1.CliIoHost.instance().isCI = false; bootstrapper = new api_1.Bootstrapper({ source: 'default' }); stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; }); }); afterEach(() => { stderrMock.mockRestore(); }); function mockTheToolkitInfo(stackProps) { api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.fromStack((0, mock_sdk_1.mockBootstrapStack)(stackProps))); } describe('Bootstrapping v2', () => { const env = { account: '123456789012', region: 'us-east-1', name: 'mock', }; let sdk; beforeEach(() => { sdk = new mock_sdk_1.MockSdkProvider(); // By default, we'll return a non-found toolkit info api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.bootstrapStackNotFoundInfo('BootstrapStack')); const value = { Policy: { PolicyName: 'my-policy', Arn: 'arn:aws:iam::0123456789012:policy/my-policy', }, }; (0, mock_sdk_1.restoreSdkMocksToDefault)(); (0, mock_sdk_1.setDefaultSTSMocks)(); mock_sdk_1.mockIAMClient.on(client_iam_1.GetPolicyCommand).resolves(value); mock_sdk_1.mockIAMClient.on(client_iam_1.CreatePolicyCommand).resolves(value); mockDeployStack.mockResolvedValue({ type: 'did-deploy-stack', noOp: false, outputs: {}, stackArn: 'arn:stack', }); }); afterEach(() => { mockDeployStack.mockClear(); }); test('passes the bucket name as a CFN parameter', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { bucketName: 'my-bucket-name', cloudFormationExecutionPolicies: ['arn:policy'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ FileAssetsBucketName: 'my-bucket-name', PublicAccessBlockConfiguration: 'true', }), })); }); test('passes the KMS key ID as a CFN parameter', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], kmsKeyId: 'my-kms-key-id', }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ FileAssetsBucketKmsKeyId: 'my-kms-key-id', PublicAccessBlockConfiguration: 'true', }), })); }); test('passes false to PublicAccessBlockConfiguration', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], publicAccessBlockConfiguration: false, }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ PublicAccessBlockConfiguration: 'false', }), })); }); test('passes true to PermissionsBoundary', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { examplePermissionsBoundary: true, }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ InputPermissionsBoundary: 'cdk-hnb659fds-permissions-boundary', }), })); }); test('passes value to PermissionsBoundary', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'InputPermissionsBoundary', ParameterValue: 'existing-pb', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { customPermissionsBoundary: 'permissions-boundary-name', }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ InputPermissionsBoundary: 'permissions-boundary-name', }), })); expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ expect.arrayContaining([ expect.stringMatching(/Changing permissions boundary from existing-pb to permissions-boundary-name/), ]), ])); }); test('permission boundary switch message does not appear', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'InputPermissionsBoundary', ParameterValue: '', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk); expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([expect.not.arrayContaining([expect.stringMatching(/Changing permissions boundary/)])])); }); test('adding new permissions boundary', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'InputPermissionsBoundary', ParameterValue: '', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { customPermissionsBoundary: 'permissions-boundary-name', }, }); expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ expect.arrayContaining([expect.stringMatching(/Adding new permissions boundary permissions-boundary-name/)]), ])); }); test('removing existing permissions boundary', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'InputPermissionsBoundary', ParameterValue: 'permissions-boundary-name', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: {}, }); expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ expect.arrayContaining([ expect.stringMatching(/Removing existing permissions boundary permissions-boundary-name/), ]), ])); }); test('adding permission boundary with path in policy name', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'InputPermissionsBoundary', ParameterValue: '', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { customPermissionsBoundary: 'permissions-boundary-name/with/path', }, }); expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([ expect.arrayContaining([ expect.stringMatching(/Adding new permissions boundary permissions-boundary-name\/with\/path/), ]), ])); }); test('passing trusted accounts without CFN managed policies results in an error', async () => { await expect(bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { trustedAccounts: ['123456789012'], }, })).rejects.toThrow(/--cloudformation-execution-policies/); }); test('passing trusted accounts without CFN managed policies on the existing stack results in an error', async () => { mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'CloudFormationExecutionPolicies', ParameterValue: '', }, ], }); await expect(bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { trustedAccounts: ['123456789012'], }, })).rejects.toThrow(/--cloudformation-execution-policies/); }); test('passing no CFN managed policies without trusted accounts is okay', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: {}, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ CloudFormationExecutionPolicies: '', }), })); }); test('passing trusted accounts for lookup generates the correct stack parameter', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { trustedAccountsForLookup: ['123456789012'], cloudFormationExecutionPolicies: ['aws://foo'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ TrustedAccountsForLookup: '123456789012', }), })); }); test('allow adding trusted account if there was already a policy on the stack', async () => { // GIVEN mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'CloudFormationExecutionPolicies', ParameterValue: 'arn:aws:something', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { trustedAccounts: ['123456789012'], }, }); // Did not throw }); test('removes trusted account when it is listed as untrusted', async () => { // GIVEN mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'CloudFormationExecutionPolicies', ParameterValue: 'arn:aws:something', }, { ParameterKey: 'TrustedAccounts', ParameterValue: '111111111111,222222222222', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { untrustedAccounts: ['111111111111'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ TrustedAccounts: '222222222222', }), })); }); test('removes trusted account for lookup when it is listed as untrusted', async () => { // GIVEN mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'CloudFormationExecutionPolicies', ParameterValue: 'arn:aws:something', }, { ParameterKey: 'TrustedAccountsForLookup', ParameterValue: '111111111111,222222222222', }, ], }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { untrustedAccounts: ['111111111111'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ TrustedAccountsForLookup: '222222222222', }), })); }); test('do not allow accounts to be listed as both trusted and untrusted', async () => { await expect(bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { trustedAccountsForLookup: ['123456789012'], untrustedAccounts: ['123456789012'], }, })).rejects.toThrow('Accounts cannot be both trusted and untrusted. Found: 123456789012'); }); test('Do not allow downgrading bootstrap stack version', async () => { // GIVEN mockTheToolkitInfo({ Outputs: [ { OutputKey: 'BootstrapVersion', OutputValue: '999', }, ], }); await expect(bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, })).resolves.toEqual(expect.objectContaining({ noOp: true })); }); test('Do not allow overwriting bootstrap stack from a different vendor', async () => { // GIVEN mockTheToolkitInfo({ Parameters: [ { ParameterKey: 'BootstrapVariant', ParameterValue: 'JoeSchmoe', }, ], }); await expect(bootstrapper.bootstrapEnvironment(env, sdk, {})).resolves.toEqual(expect.objectContaining({ noOp: true })); }); test('bootstrap template has the right exports', async () => { let template; mockDeployStack.mockImplementation((args) => { template = args.stack.template; return Promise.resolve({ type: 'did-deploy-stack', noOp: false, outputs: {}, stackArn: 'arn:stack', }); }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, }); const exports = Object.values(template.Outputs ?? {}) .filter((o) => o.Export !== undefined) .map((o) => o.Export.Name); expect(exports).toEqual([ // This used to be used by aws-s3-assets { 'Fn::Sub': 'CdkBootstrap-${Qualifier}-FileAssetKeyArn' }, ]); }); describe('termination protection', () => { test('stack is not termination protected by default', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ stack: expect.objectContaining({ terminationProtection: false, }), })); }); test('stack is termination protected when option is set', async () => { await bootstrapper.bootstrapEnvironment(env, sdk, { terminationProtection: true, parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ stack: expect.objectContaining({ terminationProtection: true, }), })); }); test('termination protection is left alone when option is not given', async () => { mockTheToolkitInfo({ EnableTerminationProtection: true, }); await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ stack: expect.objectContaining({ terminationProtection: true, }), })); }); test('termination protection can be switched off', async () => { mockTheToolkitInfo({ EnableTerminationProtection: true, }); await bootstrapper.bootstrapEnvironment(env, sdk, { terminationProtection: false, parameters: { cloudFormationExecutionPolicies: ['arn:policy'], }, }); expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ stack: expect.objectContaining({ terminationProtection: false, }), })); }); }); describe('KMS key', () => { test.each([ // Default case [undefined, 'AWS_MANAGED_KEY'], // Create a new key [true, ''], // Don't create a new key [false, 'AWS_MANAGED_KEY'], ])('(new stack) createCustomerMasterKey=%p => parameter becomes %p ', async (createCustomerMasterKey, paramKeyId) => { // GIVEN: no existing stack // WHEN await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { createCustomerMasterKey, cloudFormationExecutionPolicies: ['arn:booh'], }, }); // THEN expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ FileAssetsBucketKmsKeyId: paramKeyId, }), })); }); test.each([ // Old bootstrap stack being upgraded to new one [undefined, undefined, 'AWS_MANAGED_KEY'], // There is a value, user doesn't request a change ['arn:aws:key', undefined, undefined], // Switch off existing key ['arn:aws:key', false, 'AWS_MANAGED_KEY'], // Switch on existing key ['AWS_MANAGED_KEY', true, ''], ])('(upgrading) current param %p, createCustomerMasterKey=%p => parameter becomes %p ', async (currentKeyId, createCustomerMasterKey, paramKeyId) => { // GIVEN mockTheToolkitInfo({ Parameters: currentKeyId ? [ { ParameterKey: 'FileAssetsBucketKmsKeyId', ParameterValue: currentKeyId, }, ] : undefined, }); // WHEN await bootstrapper.bootstrapEnvironment(env, sdk, { parameters: { createCustomerMasterKey, cloudFormationExecutionPolicies: ['arn:booh'], }, }); // THEN expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({ parameters: expect.objectContaining({ FileAssetsBucketKmsKeyId: paramKeyId, }), })); }); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwMi50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYm9vdHN0cmFwMi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxpQ0FBaUM7O0FBRWpDLHNFQUFzRTtBQUV0RSxvREFBNEU7QUFDNUUsdUNBQTBEO0FBQzFELCtDQUswQjtBQUMxQiwrREFBMEQ7QUFFMUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFFL0QsSUFBSSxZQUEwQixDQUFDO0FBQy9CLElBQUksVUFBNEIsQ0FBQztBQUVqQyxVQUFVLENBQUMsR0FBRyxFQUFFO0lBQ2QsdUJBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDO0lBQ2xDLFlBQVksR0FBRyxJQUFJLGtCQUFZLENBQUMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUN2RCxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDLGtCQUFrQixDQUFDLEdBQUcsRUFBRTtRQUN2RSxPQUFPLElBQUksQ0FBQztJQUNkLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ2IsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQzNCLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxrQkFBa0IsQ0FBQyxVQUEwQjtJQUNuRCxpQkFBbUIsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLGlCQUFXLENBQUMsU0FBUyxDQUFDLElBQUEsNkJBQWtCLEVBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ25ILENBQUM7QUFFRCxRQUFRLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFO0lBQ2hDLE1BQU0sR0FBRyxHQUFH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LFVBQVUsRUFBRSxZQUFZO29CQUN0QixDQUFDLENBQUM7d0JBQ0E7NEJBQ0UsWUFBWSxFQUFFLDBCQUEwQjs0QkFDeEMsY0FBYyxFQUFFLFlBQVk7eUJBQzdCO3FCQUNGO29CQUNELENBQUMsQ0FBQyxTQUFTO2FBQ2QsQ0FBQyxDQUFDO1lBRUgsT0FBTztZQUNQLE1BQU0sWUFBWSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUU7Z0JBQ2hELFVBQVUsRUFBRTtvQkFDVix1QkFBdUI7b0JBQ3ZCLCtCQUErQixFQUFFLENBQUMsVUFBVSxDQUFDO2lCQUM5QzthQUNGLENBQUMsQ0FBQztZQUVILE9BQU87WUFDUCxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsb0JBQW9CLENBQzFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDdEIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDbEMsd0JBQXdCLEVBQUUsVUFBVTtpQkFDckMsQ0FBQzthQUNILENBQUMsQ0FDSCxDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L29yZGVyICovXG5cbmltcG9ydCAqIGFzIGRlcGxveVN0YWNrIGZyb20gJy4uLy4uL2xpYi9hcGkvZGVwbG95bWVudHMvZGVwbG95LXN0YWNrJztcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNsb3VkZm9ybWF0aW9uJztcbmltcG9ydCB7IENyZWF0ZVBvbGljeUNvbW1hbmQsIEdldFBvbGljeUNvbW1hbmQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtaWFtJztcbmltcG9ydCB7IEJvb3RzdHJhcHBlciwgVG9vbGtpdEluZm8gfSBmcm9tICcuLi8uLi9saWIvYXBpJztcbmltcG9ydCB7XG4gIG1vY2tCb290c3RyYXBTdGFjayxcbiAgbW9ja0lBTUNsaWVudCxcbiAgTW9ja1Nka1Byb3ZpZGVyLFxuICByZXN0b3JlU2RrTW9ja3NUb0RlZmF1bHQsIHNldERlZmF1bHRTVFNNb2Nrcyxcbn0gZnJvbSAnLi4vdXRpbC9tb2NrLXNkayc7XG5pbXBvcnQgeyBDbGlJb0hvc3QgfSBmcm9tICcuLi8uLi9saWIvdG9vbGtpdC9jbGktaW8taG9zdCc7XG5cbmNvbnN0IG1vY2tEZXBsb3lTdGFjayA9IGplc3Quc3B5T24oZGVwbG95U3RhY2ssICdkZXBsb3lTdGFjaycpO1xuXG5sZXQgYm9vdHN0cmFwcGVyOiBCb290c3RyYXBwZXI7XG5sZXQgc3RkZXJyTW9jazogamVzdC5TcHlJbnN0YW5jZTtcblxuYmVmb3JlRWFjaCgoKSA9PiB7XG4gIENsaUlvSG9zdC5pbnN0YW5jZSgpLmlzQ0kgPSBmYWxzZTtcbiAgYm9vdHN0cmFwcGVyID0gbmV3IEJvb3RzdHJhcHBlcih7IHNvdXJjZTogJ2RlZmF1bHQnIH0pO1xuICBzdGRlcnJNb2NrID0gamVzdC5zcHlPbihwcm9jZXNzLnN0ZGVyciwgJ3dyaXRlJykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSk7XG59KTtcblxuYWZ0ZXJFYWNoKCgpID0+IHtcbiAgc3RkZXJyTW9jay5tb2NrUmVzdG9yZSgpO1xufSk7XG5cbmZ1bmN0aW9uIG1vY2tUaGVUb29sa2l0SW5mbyhzdGFja1Byb3BzOiBQYXJ0aWFsPFN0YWNrPikge1xuICAoVG9vbGtpdEluZm8gYXMgYW55KS5sb29rdXAgPSBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoVG9vbGtpdEluZm8uZnJvbVN0YWNrKG1vY2tCb290c3RyYXBTdGFjayhzdGFja1Byb3BzKSkpO1xufVxuXG5kZXNjcmliZSgnQm9vdHN0cmFwcGluZyB2MicsICgpID0+IHtcbiAgY29uc3QgZW52ID0ge1xuICAgIGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLFxuICAgIHJlZ2lvbjogJ3VzLWVhc3QtMScsXG4gICAgbmFtZTogJ21vY2snLFxuICB9O1xuXG4gIGxldCBzZGs6IE1vY2tTZGtQcm92aWRlcjtcbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgc2RrID0gbmV3IE1vY2tTZGtQcm92aWRlcigpO1xuICAgIC8vIEJ5IGRlZmF1bHQsIHdlJ2xsIHJldHVybiBhIG5vbi1mb3VuZCB0b29sa2l0IGluZm9cbiAgICAoVG9vbGtpdEluZm8gYXMgYW55KS5sb29rdXAgPSBqZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoVG9vbGtpdEluZm8uYm9vdHN0cmFwU3RhY2tOb3RGb3VuZEluZm8oJ0Jvb3RzdHJhcFN0YWNrJykpO1xuICAgIGNvbnN0IHZhbHVlID0ge1xuICAgICAgUG9saWN5OiB7XG4gICAgICAgIFBvbGljeU5hbWU6ICdteS1wb2xpY3knLFxuICAgICAgICBBcm46ICdhcm46YXdzOmlhbTo6MDEyMzQ1Njc4OTAxMjpwb2xpY3kvbXktcG9saWN5JyxcbiAgICAgIH0sXG4gICAgfTtcbiAgICByZXN0b3JlU2RrTW9ja3NUb0RlZmF1bHQoKTtcbiAgICBzZXREZWZhdWx0U1RTTW9ja3MoKTtcbiAgICBtb2NrSUFNQ2xpZW50Lm9uKEdldFBvbGljeUNvbW1hbmQpLnJlc29sdmVzKHZhbHVlKTtcbiAgICBtb2NrSUFNQ2xpZW50Lm9uKENyZWF0ZVBvbGljeUNvbW1hbmQpLnJlc29sdmVzKHZhbHVlKTtcbiAgICBtb2NrRGVwbG95U3RhY2subW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgdHlwZTogJ2RpZC1kZXBsb3ktc3RhY2snLFxuICAgICAgbm9PcDogZmFsc2UsXG4gICAgICBvdXRwdXRzOiB7fSxcbiAgICAgIHN0YWNrQXJuOiAnYXJuOnN0YWNrJyxcbiAgICB9KTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBtb2NrRGVwbG95U3RhY2subW9ja0NsZWFyKCk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyB0aGUgYnVja2V0IG5hbWUgYXMgYSBDRk4gcGFyYW1ldGVyJywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBidWNrZXROYW1lOiAnbXktYnVja2V0LW5hbWUnLFxuICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIEZpbGVBc3NldHNCdWNrZXROYW1lOiAnbXktYnVja2V0LW5hbWUnLFxuICAgICAgICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjogJ3RydWUnLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyB0aGUgS01TIGtleSBJRCBhcyBhIENGTiBwYXJhbWV0ZXInLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgICBrbXNLZXlJZDogJ215LWttcy1rZXktaWQnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBwYXJhbWV0ZXJzOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgRmlsZUFzc2V0c0J1Y2tldEttc0tleUlkOiAnbXkta21zLWtleS1pZCcsXG4gICAgICAgICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiAndHJ1ZScsXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2VzIGZhbHNlIHRvIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46cG9saWN5J10sXG4gICAgICAgIHB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjogZmFsc2UsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246ICdmYWxzZScsXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2VzIHRydWUgdG8gUGVybWlzc2lvbnNCb3VuZGFyeScsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgZXhhbXBsZVBlcm1pc3Npb25zQm91bmRhcnk6IHRydWUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICBJbnB1dFBlcm1pc3Npb25zQm91bmRhcnk6ICdjZGstaG5iNjU5ZmRzLXBlcm1pc3Npb25zLWJvdW5kYXJ5JyxcbiAgICAgICAgfSksXG4gICAgICB9KSxcbiAgICApO1xuICB9KTtcblxuICB0ZXN0KCdwYXNzZXMgdmFsdWUgdG8gUGVybWlzc2lvbnNCb3VuZGFyeScsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5JyxcbiAgICAgICAgICBQYXJhbWV0ZXJWYWx1ZTogJ2V4aXN0aW5nLXBiJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGN1c3RvbVBlcm1pc3Npb25zQm91bmRhcnk6ICdwZXJtaXNzaW9ucy1ib3VuZGFyeS1uYW1lJyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIElucHV0UGVybWlzc2lvbnNCb3VuZGFyeTogJ3Blcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWUnLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgZXhwZWN0KHN0ZGVyck1vY2subW9jay5jYWxscykudG9FcXVhbChcbiAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL0NoYW5naW5nIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGZyb20gZXhpc3RpbmctcGIgdG8gcGVybWlzc2lvbnMtYm91bmRhcnktbmFtZS8pLFxuICAgICAgICBdKSxcbiAgICAgIF0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Blcm1pc3Npb24gYm91bmRhcnkgc3dpdGNoIG1lc3NhZ2UgZG9lcyBub3QgYXBwZWFyJywgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICBQYXJhbWV0ZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBQYXJhbWV0ZXJLZXk6ICdJbnB1dFBlcm1pc3Npb25zQm91bmRhcnknLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrKTtcblxuICAgIGV4cGVjdChzdGRlcnJNb2NrLm1vY2suY2FsbHMpLnRvRXF1YWwoXG4gICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtleHBlY3Qubm90LmFycmF5Q29udGFpbmluZyhbZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9DaGFuZ2luZyBwZXJtaXNzaW9ucyBib3VuZGFyeS8pXSldKSxcbiAgICApO1xuICB9KTtcblxuICB0ZXN0KCdhZGRpbmcgbmV3IHBlcm1pc3Npb25zIGJvdW5kYXJ5JywgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICBQYXJhbWV0ZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBQYXJhbWV0ZXJLZXk6ICdJbnB1dFBlcm1pc3Npb25zQm91bmRhcnknLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGN1c3RvbVBlcm1pc3Npb25zQm91bmRhcnk6ICdwZXJtaXNzaW9ucy1ib3VuZGFyeS1uYW1lJyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3Qoc3RkZXJyTW9jay5tb2NrLmNhbGxzKS50b0VxdWFsKFxuICAgICAgZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW2V4cGVjdC5zdHJpbmdNYXRjaGluZygvQWRkaW5nIG5ldyBwZXJtaXNzaW9ucyBib3VuZGFyeSBwZXJtaXNzaW9ucy1ib3VuZGFyeS1uYW1lLyldKSxcbiAgICAgIF0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ3JlbW92aW5nIGV4aXN0aW5nIHBlcm1pc3Npb25zIGJvdW5kYXJ5JywgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICBQYXJhbWV0ZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBQYXJhbWV0ZXJLZXk6ICdJbnB1dFBlcm1pc3Npb25zQm91bmRhcnknLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAncGVybWlzc2lvbnMtYm91bmRhcnktbmFtZScsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge30sXG4gICAgfSk7XG5cbiAgICBleHBlY3Qoc3RkZXJyTW9jay5tb2NrLmNhbGxzKS50b0VxdWFsKFxuICAgICAgZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvUmVtb3ZpbmcgZXhpc3RpbmcgcGVybWlzc2lvbnMgYm91bmRhcnkgcGVybWlzc2lvbnMtYm91bmRhcnktbmFtZS8pLFxuICAgICAgICBdKSxcbiAgICAgIF0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ2FkZGluZyBwZXJtaXNzaW9uIGJvdW5kYXJ5IHdpdGggcGF0aCBpbiBwb2xpY3kgbmFtZScsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5JyxcbiAgICAgICAgICBQYXJhbWV0ZXJWYWx1ZTogJycsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBjdXN0b21QZXJtaXNzaW9uc0JvdW5kYXJ5OiAncGVybWlzc2lvbnMtYm91bmRhcnktbmFtZS93aXRoL3BhdGgnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChzdGRlcnJNb2NrLm1vY2suY2FsbHMpLnRvRXF1YWwoXG4gICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9BZGRpbmcgbmV3IHBlcm1pc3Npb25zIGJvdW5kYXJ5IHBlcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWVcXC93aXRoXFwvcGF0aC8pLFxuICAgICAgICBdKSxcbiAgICAgIF0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NpbmcgdHJ1c3RlZCBhY2NvdW50cyB3aXRob3V0IENGTiBtYW5hZ2VkIHBvbGljaWVzIHJlc3VsdHMgaW4gYW4gZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgZXhwZWN0KFxuICAgICAgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICB0cnVzdGVkQWNjb3VudHM6IFsnMTIzNDU2Nzg5MDEyJ10sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICApLnJlamVjdHMudG9UaHJvdygvLS1jbG91ZGZvcm1hdGlvbi1leGVjdXRpb24tcG9saWNpZXMvKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2luZyB0cnVzdGVkIGFjY291bnRzIHdpdGhvdXQgQ0ZOIG1hbmFnZWQgcG9saWNpZXMgb24gdGhlIGV4aXN0aW5nIHN0YWNrIHJlc3VsdHMgaW4gYW4gZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXMnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoXG4gICAgICBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIHRydXN0ZWRBY2NvdW50czogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICkucmVqZWN0cy50b1Rocm93KC8tLWNsb3VkZm9ybWF0aW9uLWV4ZWN1dGlvbi1wb2xpY2llcy8pO1xuICB9KTtcblxuICB0ZXN0KCdwYXNzaW5nIG5vIENGTiBtYW5hZ2VkIHBvbGljaWVzIHdpdGhvdXQgdHJ1c3RlZCBhY2NvdW50cyBpcyBva2F5JywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge30sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIENsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6ICcnLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NpbmcgdHJ1c3RlZCBhY2NvdW50cyBmb3IgbG9va3VwIGdlbmVyYXRlcyB0aGUgY29ycmVjdCBzdGFjayBwYXJhbWV0ZXInLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhd3M6Ly9mb28nXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgIGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIFRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogJzEyMzQ1Njc4OTAxMicsXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgKTtcbiAgfSk7XG5cbiAgdGVzdCgnYWxsb3cgYWRkaW5nIHRydXN0ZWQgYWNjb3VudCBpZiB0aGVyZSB3YXMgYWxyZWFkeSBhIHBvbGljeSBvbiB0aGUgc3RhY2snLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnQ2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llcycsXG4gICAgICAgICAgUGFyYW1ldGVyVmFsdWU6ICdhcm46YXdzOnNvbWV0aGluZycsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50czogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgLy8gRGlkIG5vdCB0aHJvd1xuICB9KTtcblxuICB0ZXN0KCdyZW1vdmVzIHRydXN0ZWQgYWNjb3VudCB3aGVuIGl0IGlzIGxpc3RlZCBhcyB1bnRydXN0ZWQnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnQ2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llcycsXG4gICAgICAgICAgUGFyYW1ldGVyVmFsdWU6ICdh