UNPKG

@cloudsnorkel/cdk-github-runners

Version:

CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.

182 lines 22.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadOctokitRest = loadOctokitRest; exports.loadOctokitCore = loadOctokitCore; exports.loadOctokitAuthApp = loadOctokitAuthApp; exports.baseUrlFromDomain = baseUrlFromDomain; exports.getOctokit = getOctokit; exports.getAppOctokit = getAppOctokit; exports.getRunner = getRunner; exports.deleteRunner = deleteRunner; exports.redeliver = redeliver; const crypto_1 = require("crypto"); const lambda_helpers_1 = require("./lambda-helpers"); let restModulePromise; let coreModulePromise; let authAppModulePromise; function loadOctokitRest() { return (restModulePromise ?? (restModulePromise = Promise.resolve().then(() => require('@octokit/rest')))); } function loadOctokitCore() { return (coreModulePromise ?? (coreModulePromise = Promise.resolve().then(() => require('@octokit/core')))); } function loadOctokitAuthApp() { return (authAppModulePromise ?? (authAppModulePromise = Promise.resolve().then(() => require('@octokit/auth-app')))); } // ---- Other helpers ---- function baseUrlFromDomain(domain) { if (domain == 'github.com') { return 'https://api.github.com'; } return `https://${domain}/api/v3`; } const octokitCache = new Map(); async function getOctokit(installationId) { if (!process.env.GITHUB_SECRET_ARN || !process.env.GITHUB_PRIVATE_KEY_SECRET_ARN) { throw new Error('Missing environment variables'); } const [{ Octokit }, { createAppAuth }] = await Promise.all([ loadOctokitRest(), loadOctokitAuthApp(), ]); const githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); // Create cache key from installation ID and secrets (hash to avoid exposing sensitive data by accident) const cacheKey = (0, crypto_1.createHash)('sha256').update(`${installationId || 'no-install'}-${githubSecrets.domain}-${githubSecrets.appId}-${githubSecrets.personalAuthToken}`).digest('hex'); const cached = octokitCache.get(cacheKey); if (cached) { try { // Test if the cached octokit is still valid await cached.rest.meta.getOctocat(); console.log({ notice: 'Using cached octokit', }); return { octokit: cached, githubSecrets, }; } catch (e) { console.log({ notice: 'Octokit cache is invalid', error: e, }); octokitCache.delete(cacheKey); } } const baseUrl = baseUrlFromDomain(githubSecrets.domain); let token; if (githubSecrets.personalAuthToken) { token = githubSecrets.personalAuthToken; } else { const privateKey = await (0, lambda_helpers_1.getSecretValue)(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN); const appOctokit = new Octokit({ baseUrl, authStrategy: createAppAuth, auth: { appId: githubSecrets.appId, privateKey: privateKey, }, }); token = (await appOctokit.auth({ type: 'installation', installationId: installationId, })).token; } const octokit = new Octokit({ baseUrl, auth: token, }); // Store in cache octokitCache.set(cacheKey, octokit); return { octokit, githubSecrets, }; } // This function is used to get the Octokit instance for the app itself, not for a specific installation. // With PAT authentication, it returns undefined. async function getAppOctokit() { if (!process.env.GITHUB_SECRET_ARN || !process.env.GITHUB_PRIVATE_KEY_SECRET_ARN) { throw new Error('Missing environment variables'); } const [{ Octokit }, { createAppAuth }] = await Promise.all([ loadOctokitRest(), loadOctokitAuthApp(), ]); const githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); const baseUrl = baseUrlFromDomain(githubSecrets.domain); if (githubSecrets.personalAuthToken || !githubSecrets.appId) { return undefined; } const privateKey = await (0, lambda_helpers_1.getSecretValue)(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN); return new Octokit({ baseUrl, authStrategy: createAppAuth, auth: { appId: githubSecrets.appId, privateKey: privateKey, }, }); } async function getRunner(octokit, runnerLevel, owner, repo, name) { let page = 1; while (true) { let runners; if ((runnerLevel ?? 'repo') === 'repo') { runners = await octokit.rest.actions.listSelfHostedRunnersForRepo({ name: name, page: page, owner: owner, repo: repo, }); } else { runners = await octokit.rest.actions.listSelfHostedRunnersForOrg({ name: name, page: page, org: owner, }); } if (runners.data.runners.length == 0) { return; } for (const runner of runners.data.runners) { // we filter by name in the API call, but still double-check here // this is for backward compatibility with old GHES instances that may not support the name filter if (runner.name == name) { return runner; } } page++; } } async function deleteRunner(octokit, runnerLevel, owner, repo, runnerId) { if ((runnerLevel ?? 'repo') === 'repo') { await octokit.rest.actions.deleteSelfHostedRunnerFromRepo({ owner: owner, repo: repo, runner_id: runnerId, }); } else { await octokit.rest.actions.deleteSelfHostedRunnerFromOrg({ org: owner, runner_id: runnerId, }); } } async function redeliver(octokit, deliveryId) { const response = await octokit.rest.apps.redeliverWebhookDelivery({ // waiting for new octokit -- https://github.com/octokit/request.js/issues/797#issuecomment-3953274583 delivery_id: deliveryId, }); if (response.status !== 202) { throw new Error(`Failed to redeliver webhook delivery with ID ${deliveryId}`); } console.log({ notice: 'Successfully redelivered webhook delivery', deliveryId: String(deliveryId), }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLWdpdGh1Yi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9sYW1iZGEtZ2l0aHViLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBZUEsMENBRUM7QUFFRCwwQ0FFQztBQUVELGdEQUVDO0FBSUQsOENBS0M7QUFhRCxnQ0F1RUM7QUFJRCxzQ0EyQkM7QUFFRCw4QkFrQ0M7QUFFRCxvQ0FhQztBQUVELDhCQWFDO0FBdk5ELG1DQUFvQztBQUVwQyxxREFBc0U7QUFTdEUsSUFBSSxpQkFBeUQsQ0FBQztBQUM5RCxJQUFJLGlCQUF5RCxDQUFDO0FBQzlELElBQUksb0JBQStELENBQUM7QUFFcEUsU0FBZ0IsZUFBZTtJQUM3QixPQUFPLENBQUMsaUJBQWlCLEtBQWpCLGlCQUFpQixHQUFLLHFDQUFPLGVBQWUsRUFBK0IsRUFBQyxDQUFDO0FBQ3ZGLENBQUM7QUFFRCxTQUFnQixlQUFlO0lBQzdCLE9BQU8sQ0FBQyxpQkFBaUIsS0FBakIsaUJBQWlCLEdBQUsscUNBQU8sZUFBZSxFQUErQixFQUFDLENBQUM7QUFDdkYsQ0FBQztBQUVELFNBQWdCLGtCQUFrQjtJQUNoQyxPQUFPLENBQUMsb0JBQW9CLEtBQXBCLG9CQUFvQixHQUFLLHFDQUFPLG1CQUFtQixFQUFrQyxFQUFDLENBQUM7QUFDakcsQ0FBQztBQUVELDBCQUEwQjtBQUUxQixTQUFnQixpQkFBaUIsQ0FBQyxNQUFjO0lBQzlDLElBQUksTUFBTSxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQzNCLE9BQU8sd0JBQXdCLENBQUM7SUFDbEMsQ0FBQztJQUNELE9BQU8sV0FBVyxNQUFNLFNBQVMsQ0FBQztBQUNwQyxDQUFDO0FBV0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7QUFFN0MsS0FBSyxVQUFVLFVBQVUsQ0FBQyxjQUF1QjtJQUN0RCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENB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T0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsNkJBQTZCLENBQUM7WUFDdkQsR0FBRyxFQUFFLEtBQUs7WUFDVixTQUFTLEVBQUUsUUFBUTtTQUNwQixDQUFDLENBQUM7SUFDTCxDQUFDO0FBQ0gsQ0FBQztBQUVNLEtBQUssVUFBVSxTQUFTLENBQUMsT0FBb0IsRUFBRSxVQUFrQjtJQUN0RSxNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDO1FBQ2hFLHNHQUFzRztRQUN0RyxXQUFXLEVBQUUsVUFBK0I7S0FDN0MsQ0FBQyxDQUFDO0lBRUgsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0RBQWdELFVBQVUsRUFBRSxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUNELE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFDVixNQUFNLEVBQUUsMkNBQTJDO1FBQ25ELFVBQVUsRUFBRSxNQUFNLENBQUMsVUFBVSxDQUFDO0tBQy9CLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjcmVhdGVIYXNoIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB0eXBlIHsgT2N0b2tpdCBhcyBSZXN0T2N0b2tpdCB9IGZyb20gJ0BvY3Rva2l0L3Jlc3QnO1xuaW1wb3J0IHsgZ2V0U2VjcmV0SnNvblZhbHVlLCBnZXRTZWNyZXRWYWx1ZSB9IGZyb20gJy4vbGFtYmRhLWhlbHBlcnMnO1xuXG4vLyAtLS0tIE9jdG9raXQgRVNNIGxvYWRlciBoZWxwZXJzIChpbmxpbmVkKSAtLS0tXG4vLyBPY3Rva2l0IHBhY2thZ2VzIGFyZSBFU00sIGJ1dCBvdXIgTGFtYmRhIGFzc2V0cyBhcmUgYnVuZGxlZCBpbnRvIENKUy5cbi8vIFVzaW5nIGR5bmFtaWMgYGltcG9ydCgpYCBoZXJlIGxldHMgZXNidWlsZCBpbmNsdWRlIE9jdG9raXQgaW4gdGhlIGJ1bmRsZS5cbnR5cGUgT2N0b2tpdFJlc3RNb2R1bGUgPSB0eXBlb2YgaW1wb3J0KCdAb2N0b2tpdC9yZXN0Jyk7XG50eXBlIE9jdG9raXRDb3JlTW9kdWxlID0gdHlwZW9mIGltcG9ydCgnQG9jdG9raXQvY29yZScpO1xudHlwZSBPY3Rva2l0QXV0aEFwcE1vZHVsZSA9IHR5cGVvZiBpbXBvcnQoJ0BvY3Rva2l0L2F1dGgtYXBwJyk7XG5cbmxldCByZXN0TW9kdWxlUHJvbWlzZTogUHJvbWlzZTxPY3Rva2l0UmVzdE1vZHVsZT4gfCB1bmRlZmluZWQ7XG5sZXQgY29yZU1vZHVsZVByb21pc2U6IFByb21pc2U8T2N0b2tpdENvcmVNb2R1bGU+IHwgdW5kZWZpbmVkO1xubGV0IGF1dGhBcHBNb2R1bGVQcm9taXNlOiBQcm9taXNlPE9jdG9raXRBdXRoQXBwTW9kdWxlPiB8IHVuZGVmaW5lZDtcblxuZXhwb3J0IGZ1bmN0aW9uIGxvYWRPY3Rva2l0UmVzdCgpOiBQcm9taXNlPE9jdG9raXRSZXN0TW9kdWxlPiB7XG4gIHJldHVybiAocmVzdE1vZHVsZVByb21pc2UgPz89IGltcG9ydCgnQG9jdG9raXQvcmVzdCcpIGFzIFByb21pc2U8T2N0b2tpdFJlc3RNb2R1bGU+KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGxvYWRPY3Rva2l0Q29yZSgpOiBQcm9taXNlPE9jdG9raXRDb3JlTW9kdWxlPiB7XG4gIHJldHVybiAoY29yZU1vZHVsZVByb21pc2UgPz89IGltcG9ydCgnQG9jdG9raXQvY29yZScpIGFzIFByb21pc2U8T2N0b2tpdENvcmVNb2R1bGU+KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGxvYWRPY3Rva2l0QXV0aEFwcCgpOiBQcm9taXNlPE9jdG9raXRBdXRoQXBwTW9kdWxlPiB7XG4gIHJldHVybiAoYXV0aEFwcE1vZHVsZVByb21pc2UgPz89IGltcG9ydCgnQG9jdG9raXQvYXV0aC1hcHAnKSBhcyBQcm9taXNlPE9jdG9raXRBdXRoQXBwTW9kdWxlPik7XG59XG5cbi8vIC0tLS0gT3RoZXIgaGVscGVycyAtLS0tXG5cbmV4cG9ydCBmdW5jdGlvbiBiYXNlVXJsRnJvbURvbWFpbihkb21haW46IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmIChkb21haW4gPT0gJ2dpdGh1Yi5jb20nKSB7XG4gICAgcmV0dXJuICdodHRwczovL2FwaS5naXRodWIuY29tJztcbiAgfVxuICByZXR1cm4gYGh0dHBzOi8vJHtkb21haW59L2FwaS92M2A7XG59XG5cbnR5cGUgUnVubmVyTGV2ZWwgPSAncmVwbycgfCAnb3JnJyB8IHVuZGVmaW5lZDsgLy8gdW5kZWZpbmVkIGlzIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBhbmQgc2hvdWxkIGJlIHRyZWF0ZWQgYXMgJ3JlcG8nXG5cbmV4cG9ydCBpbnRlcmZhY2UgR2l0SHViU2VjcmV0cyB7XG4gIGRvbWFpbjogc3RyaW5nO1xuICBhcHBJZDogbnVtYmVyO1xuICBwZXJzb25hbEF1dGhUb2tlbjogc3RyaW5nO1xuICBydW5uZXJMZXZlbDogUnVubmVyTGV2ZWw7XG59XG5cbmNvbnN0IG9jdG9raXRDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBSZXN0T2N0b2tpdD4oKTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldE9jdG9raXQoaW5zdGFsbGF0aW9uSWQ/OiBudW1iZXIpOiBQcm9taXNlPHsgb2N0b2tpdDogUmVzdE9jdG9raXQ7IGdpdGh1YlNlY3JldHM6IEdpdEh1YlNlY3JldHMgfT4ge1xuICBpZiAoIXByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOIHx8ICFwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTikge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbnZpcm9ubWVudCB2YXJpYWJsZXMnKTtcbiAgfVxuXG4gIGNvbnN0IFt7IE9jdG9raXQgfSwgeyBjcmVhdGVBcHBBdXRoIH1dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGxvYWRPY3Rva2l0UmVzdCgpLFxuICAgIGxvYWRPY3Rva2l0QXV0aEFwcCgpLFxuICBdKTtcblxuICBjb25zdCBnaXRodWJTZWNyZXRzOiBHaXRIdWJTZWNyZXRzID0gYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOKTtcblxuICAvLyBDcmVhdGUgY2FjaGUga2V5IGZyb20gaW5zdGFsbGF0aW9uIElEIGFuZCBzZWNyZXRzIChoYXNoIHRvIGF2b2lkIGV4cG9zaW5nIHNlbnNpdGl2ZSBkYXRhIGJ5IGFjY2lkZW50KVxuICBjb25zdCBjYWNoZUtleSA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShgJHtpbnN0YWxsYXRpb25JZCB8fCAnbm8taW5zdGFsbCd9LSR7Z2l0aHViU2VjcmV0cy5kb21haW59LSR7Z2l0aHViU2VjcmV0cy5hcHBJZH0tJHtnaXRodWJTZWNyZXRzLnBlcnNvbmFsQXV0aFRva2VufWApLmRpZ2VzdCgnaGV4Jyk7XG5cbiAgY29uc3QgY2FjaGVkID0gb2N0b2tpdENhY2hlLmdldChjYWNoZUtleSk7XG4gIGlmIChjYWNoZWQpIHtcbiAgICB0cnkge1xuICAgICAgLy8gVGVzdCBpZiB0aGUgY2FjaGVkIG9jdG9raXQgaXMgc3RpbGwgdmFsaWRcbiAgICAgIGF3YWl0IGNhY2hlZC5yZXN0Lm1ldGEuZ2V0T2N0b2NhdCgpO1xuICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICBub3RpY2U6ICdVc2luZyBjYWNoZWQgb2N0b2tpdCcsXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG9jdG9raXQ6IGNhY2hlZCxcbiAgICAgICAgZ2l0aHViU2VjcmV0cyxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5sb2coe1xuICAgICAgICBub3RpY2U6ICdPY3Rva2l0IGNhY2hlIGlzIGludmFsaWQnLFxuICAgICAgICBlcnJvcjogZSxcbiAgICAgIH0pO1xuICAgICAgb2N0b2tpdENhY2hlLmRlbGV0ZShjYWNoZUtleSk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgYmFzZVVybCA9IGJhc2VVcmxGcm9tRG9tYWluKGdpdGh1YlNlY3JldHMuZG9tYWluKTtcblxuICBsZXQgdG9rZW47XG4gIGlmIChnaXRodWJTZWNyZXRzLnBlcnNvbmFsQXV0aFRva2VuKSB7XG4gICAgdG9rZW4gPSBnaXRodWJTZWNyZXRzLnBlcnNvbmFsQXV0aFRva2VuO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHByaXZhdGVLZXkgPSBhd2FpdCBnZXRTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTik7XG5cbiAgICBjb25zdCBhcHBPY3Rva2l0ID0gbmV3IE9jdG9raXQoe1xuICAgICAgYmFzZVVybCxcbiAgICAgIGF1dGhTdHJhdGVneTogY3JlYXRlQXBwQXV0aCxcbiAgICAgIGF1dGg6IHtcbiAgICAgICAgYXBwSWQ6IGdpdGh1YlNlY3JldHMuYXBwSWQsXG4gICAgICAgIHByaXZhdGVLZXk6IHByaXZhdGVLZXksXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgdG9rZW4gPSAoYXdhaXQgYXBwT2N0b2tpdC5hdXRoKHtcbiAgICAgIHR5cGU6ICdpbnN0YWxsYXRpb24nLFxuICAgICAgaW5zdGFsbGF0aW9uSWQ6IGluc3RhbGxhdGlvbklkLFxuICAgIH0pIGFzIGFueSkudG9rZW47XG4gIH1cblxuICBjb25zdCBvY3Rva2l0ID0gbmV3IE9jdG9raXQoe1xuICAgIGJhc2VVcmwsXG4gICAgYXV0aDogdG9rZW4sXG4gIH0pO1xuXG4gIC8vIFN0b3JlIGluIGNhY2hlXG4gIG9jdG9raXRDYWNoZS5zZXQoY2FjaGVLZXksIG9jdG9raXQpO1xuXG4gIHJldHVybiB7XG4gICAgb2N0b2tpdCxcbiAgICBnaXRodWJTZWNyZXRzLFxuICB9O1xufVxuXG4vLyBUaGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gZ2V0IHRoZSBPY3Rva2l0IGluc3RhbmNlIGZvciB0aGUgYXBwIGl0c2VsZiwgbm90IGZvciBhIHNwZWNpZmljIGluc3RhbGxhdGlvbi5cbi8vIFdpdGggUEFUIGF1dGhlbnRpY2F0aW9uLCBpdCByZXR1cm5zIHVuZGVmaW5lZC5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRBcHBPY3Rva2l0KCkge1xuICBpZiAoIXByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOIHx8ICFwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTikge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbnZpcm9ubWVudCB2YXJpYWJsZXMnKTtcbiAgfVxuXG4gIGNvbnN0IFt7IE9jdG9raXQgfSwgeyBjcmVhdGVBcHBBdXRoIH1dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGxvYWRPY3Rva2l0UmVzdCgpLFxuICAgIGxvYWRPY3Rva2l0QXV0aEFwcCgpLFxuICBdKTtcblxuICBjb25zdCBnaXRodWJTZWNyZXRzOiBHaXRIdWJTZWNyZXRzID0gYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOKTtcbiAgY29uc3QgYmFzZVVybCA9IGJhc2VVcmxGcm9tRG9tYWluKGdpdGh1YlNlY3JldHMuZG9tYWluKTtcblxuICBpZiAoZ2l0aHViU2VjcmV0cy5wZXJzb25hbEF1dGhUb2tlbiB8fCAhZ2l0aHViU2VjcmV0cy5hcHBJZCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBwcml2YXRlS2V5ID0gYXdhaXQgZ2V0U2VjcmV0VmFsdWUocHJvY2Vzcy5lbnYuR0lUSFVCX1BSSVZBVEVfS0VZX1NFQ1JFVF9BUk4pO1xuXG4gIHJldHVybiBuZXcgT2N0b2tpdCh7XG4gICAgYmFzZVVybCxcbiAgICBhdXRoU3RyYXRlZ3k6IGNyZWF0ZUFwcEF1dGgsXG4gICAgYXV0aDoge1xuICAgICAgYXBwSWQ6IGdpdGh1YlNlY3JldHMuYXBwSWQsXG4gICAgICBwcml2YXRlS2V5OiBwcml2YXRlS2V5LFxuICAgIH0sXG4gIH0pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UnVubmVyKG9jdG9raXQ6IFJlc3RPY3Rva2l0LCBydW5uZXJMZXZlbDogUnVubmVyTGV2ZWwsIG93bmVyOiBzdHJpbmcsIHJlcG86IHN0cmluZywgbmFtZTogc3RyaW5nKSB7XG4gIGxldCBwYWdlID0gMTtcbiAgd2hpbGUgKHRydWUpIHtcbiAgICBsZXQgcnVubmVycztcblxuICAgIGlmICgocnVubmVyTGV2ZWwgPz8gJ3JlcG8nKSA9PT0gJ3JlcG8nKSB7XG4gICAgICBydW5uZXJzID0gYXdhaXQgb2N0b2tpdC5yZXN0LmFjdGlvbnMubGlzdFNlbGZIb3N0ZWRSdW5uZXJzRm9yUmVwbyh7XG4gICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgIHBhZ2U6IHBhZ2UsXG4gICAgICAgIG93bmVyOiBvd25lcixcbiAgICAgICAgcmVwbzogcmVwbyxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBydW5uZXJzID0gYXdhaXQgb2N0b2tpdC5yZXN0LmFjdGlvbnMubGlzdFNlbGZIb3N0ZWRSdW5uZXJzRm9yT3JnKHtcbiAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgcGFnZTogcGFnZSxcbiAgICAgICAgb3JnOiBvd25lcixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChydW5uZXJzLmRhdGEucnVubmVycy5sZW5ndGggPT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgcnVubmVyIG9mIHJ1bm5lcnMuZGF0YS5ydW5uZXJzKSB7XG4gICAgICAvLyB3ZSBmaWx0ZXIgYnkgbmFtZSBpbiB0aGUgQVBJIGNhbGwsIGJ1dCBzdGlsbCBkb3VibGUtY2hlY2sgaGVyZVxuICAgICAgLy8gdGhpcyBpcyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSB3aXRoIG9sZCBHSEVTIGluc3RhbmNlcyB0aGF0IG1heSBub3Qgc3VwcG9ydCB0aGUgbmFtZSBmaWx0ZXJcbiAgICAgIGlmIChydW5uZXIubmFtZSA9PSBuYW1lKSB7XG4gICAgICAgIHJldHVybiBydW5uZXI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcGFnZSsrO1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWxldGVSdW5uZXIob2N0b2tpdDogUmVzdE9jdG9raXQsIHJ1bm5lckxldmVsOiBSdW5uZXJMZXZlbCwgb3duZXI6IHN0cmluZywgcmVwbzogc3RyaW5nLCBydW5uZXJJZDogbnVtYmVyKSB7XG4gIGlmICgocnVubmVyTGV2ZWwgPz8gJ3JlcG8nKSA9PT0gJ3JlcG8nKSB7XG4gICAgYXdhaXQgb2N0b2tpdC5yZXN0LmFjdGlvbnMuZGVsZXRlU2VsZkhvc3RlZFJ1bm5lckZyb21SZXBvKHtcbiAgICAgIG93bmVyOiBvd25lcixcbiAgICAgIHJlcG86IHJlcG8sXG4gICAgICBydW5uZXJfaWQ6IHJ1bm5lcklkLFxuICAgIH0pO1xuICB9IGVsc2Uge1xuICAgIGF3YWl0IG9jdG9raXQucmVzdC5hY3Rpb25zLmRlbGV0ZVNlbGZIb3N0ZWRSdW5uZXJGcm9tT3JnKHtcbiAgICAgIG9yZzogb3duZXIsXG4gICAgICBydW5uZXJfaWQ6IHJ1bm5lcklkLFxuICAgIH0pO1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWRlbGl2ZXIob2N0b2tpdDogUmVzdE9jdG9raXQsIGRlbGl2ZXJ5SWQ6IGJpZ2ludCkge1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IG9jdG9raXQucmVzdC5hcHBzLnJlZGVsaXZlcldlYmhvb2tEZWxpdmVyeSh7XG4gICAgLy8gd2FpdGluZyBmb3IgbmV3IG9jdG9raXQgLS0gaHR0cHM6Ly9naXRodWIuY29tL29jdG9raXQvcmVxdWVzdC5qcy9pc3N1ZXMvNzk3I2lzc3VlY29tbWVudC0zOTUzMjc0NTgzXG4gICAgZGVsaXZlcnlfaWQ6IGRlbGl2ZXJ5SWQgYXMgdW5rbm93biBhcyBudW1iZXIsXG4gIH0pO1xuXG4gIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMikge1xuICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHJlZGVsaXZlciB3ZWJob29rIGRlbGl2ZXJ5IHdpdGggSUQgJHtkZWxpdmVyeUlkfWApO1xuICB9XG4gIGNvbnNvbGUubG9nKHtcbiAgICBub3RpY2U6ICdTdWNjZXNzZnVsbHkgcmVkZWxpdmVyZWQgd2ViaG9vayBkZWxpdmVyeScsXG4gICAgZGVsaXZlcnlJZDogU3RyaW5nKGRlbGl2ZXJ5SWQpLFxuICB9KTtcbn1cbiJdfQ==