@openzeppelin/defender-serverless
Version:
Configure your Defender environment via code
170 lines (169 loc) • 8.82 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const prompt_1 = __importDefault(require("prompt"));
const logger_1 = __importDefault(require("../utils/logger"));
const utils_1 = require("../utils");
class DefenderRemove {
constructor(serverless, options, logging) {
this.serverless = serverless;
this.options = options;
this.logging = logging;
this.log = logger_1.default.getInstance();
this.hooks = {
'before:remove:remove': () => this.validateKeys(),
'remove:remove': this.requestConfirmation.bind(this),
};
}
validateKeys() {
this.teamKey = (0, utils_1.getTeamAPIkeysOrThrow)(this.serverless);
}
async wrapper(context, resourceType, resources, retrieveExistingResources, onRemove, output = []) {
try {
this.log.progress('component-info', `Retrieving ${resourceType}`);
const existing = (await retrieveExistingResources()).filter(e => (0, utils_1.isTemplateResource)(context, e, resourceType, resources ?? []));
this.log.progress('component-remove', `Removing ${resourceType} from Defender`);
await onRemove(existing);
output.push(...existing);
}
catch (e) {
this.log.tryLogDefenderError(e);
}
}
async requestConfirmation() {
if (process.stdout.isTTY) {
const properties = [
{
name: 'confirm',
validator: /^(y|n){1}$/i,
warning: 'Confirmation must be `y` (yes) or `n` (no)',
},
];
prompt_1.default.start({
message: 'This action will remove your resources from Defender permanently. Are you sure you wish to continue [y/n]?',
});
const { confirm } = await prompt_1.default.get(properties);
if (confirm.toString().toLowerCase() !== 'y') {
this.log.error('Confirmation not acquired. Terminating command');
return;
}
this.log.success('Confirmation acquired');
}
await this.remove();
}
async remove() {
this.log.notice('========================================================');
const stackName = (0, utils_1.getStackName)(this.serverless);
this.log.progress('remove', `Running Defender Remove on stack: ${stackName}`);
const stdOut = {
stack: stackName,
sentinels: [],
autotasks: [],
contracts: [],
relayers: [],
notifications: [],
categories: [],
secrets: [],
};
// Sentinels
const sentinelClient = (0, utils_1.getSentinelClient)(this.teamKey);
const listSentinels = () => sentinelClient.list().then(i => i.items);
await this.wrapper(this.serverless, 'Sentinels', this.serverless.service.resources?.Resources?.sentinels, listSentinels, async (sentinels) => {
await Promise.all(sentinels.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.subscriberId}) from Defender`);
await sentinelClient.delete(e.subscriberId);
this.log.success(`Removed ${e.stackResourceId} (${e.subscriberId})`);
}));
}, stdOut.sentinels);
// Autotasks
const autotaskClient = (0, utils_1.getAutotaskClient)(this.teamKey);
const listAutotasks = () => autotaskClient.list().then(i => i.items);
await this.wrapper(this.serverless, 'Autotasks', this.serverless.service.functions, listAutotasks, async (autotasks) => {
await Promise.all(autotasks.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.autotaskId}) from Defender`);
await autotaskClient.delete(e.autotaskId);
this.log.success(`Removed ${e.stackResourceId} (${e.autotaskId})`);
}));
}, stdOut.autotasks);
// Contracts
const adminClient = (0, utils_1.getAdminClient)(this.teamKey);
const listContracts = () => adminClient.listContracts();
await this.wrapper(this.serverless, 'Contracts', this.serverless.service.resources?.Resources?.contracts, listContracts, async (contracts) => {
await Promise.all(contracts.map(async (e) => {
const id = `${e.network}-${e.address}`;
this.log.progress('component-remove-extra', `Removing ${id} (${e.name}) from Defender`);
await adminClient.deleteContract(id);
this.log.success(`Removed ${id} (${e.name})`);
}));
}, stdOut.contracts);
try {
// Relayer API keys
const relayClient = (0, utils_1.getRelayClient)(this.teamKey);
const listRelayers = (await relayClient.list()).items;
const existingRelayers = listRelayers.filter(e => (0, utils_1.isTemplateResource)(this.serverless, e, 'Relayers', this.serverless.service.resources?.Resources?.relayers ?? []));
this.log.error('Deleting Relayers is currently only possible via the Defender UI.');
this.log.progress('component-info', `Retrieving Relayer API Keys`);
await Promise.all(existingRelayers.map(async (relayer) => {
this.log.progress('component-info', `Retrieving API Keys for relayer ${relayer.stackResourceId}`);
const relayerApiKeys = await relayClient.listKeys(relayer.relayerId);
await Promise.all(relayerApiKeys.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.keyId}) from Defender`);
await relayClient.deleteKey(e.relayerId, e.keyId);
this.log.success(`Removed ${e.stackResourceId} (${e.keyId})`);
}));
stdOut.relayers.push({ relayerId: relayer.relayerId, relayerApiKeys });
}));
}
catch (e) {
this.log.tryLogDefenderError(e);
}
// Notifications
const listNotifications = () => sentinelClient.listNotificationChannels();
await this.wrapper(this.serverless, 'Notifications', this.serverless.service.resources?.Resources?.notifications, listNotifications, async (notifications) => {
await Promise.all(notifications.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.notificationId}) from Defender`);
await sentinelClient.deleteNotificationChannel(e);
this.log.success(`Removed ${e.stackResourceId} (${e.notificationId})`);
}));
}, stdOut.notifications);
// Categories
// Temporarily Disabled
// const listNotificationCategories = () => sentinelClient.listNotificationCategories();
// await this.wrapper<YCategory, DefenderCategory>(
// this.serverless,
// 'Categories',
// this.serverless.service.resources?.Resources?.categories,
// listNotificationCategories,
// async (categories: DefenderCategory[]) => {
// await Promise.all(
// categories.map(async (e) => {
// this.log.progress(
// 'component-remove-extra',
// `Removing ${e.stackResourceId} (${e.categoryId}) from Defender`,
// );
// await sentinelClient.deleteNotificationCategory(e.categoryId);
// this.log.success(`Removed ${e.stackResourceId} (${e.categoryId})`);
// }),
// );
// },
// stdOut.categories,
// );
// Secrets
const listSecrets = () => autotaskClient.listSecrets().then(r => r.secretNames ?? []);
const allSecrets = (0, utils_1.getConsolidatedSecrets)(this.serverless);
await this.wrapper(this.serverless, 'Secrets', allSecrets, listSecrets, async (secrets) => {
this.log.progress('component-remove-extra', `Removing (${secrets.join(', ')}) from Defender`);
await autotaskClient.createSecrets({
deletes: secrets,
secrets: {},
});
this.log.success(`Removed (${secrets.join(', ')})`);
}, stdOut.secrets);
this.log.notice('========================================================');
if (!process.stdout.isTTY)
this.log.stdOut(JSON.stringify(stdOut, null, 2));
}
}
exports.default = DefenderRemove;