@openzeppelin/defender-as-code
Version:
Configure your Defender environment via code
199 lines (198 loc) • 11.3 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.resources = this.serverless.service.resources;
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,
monitors: [],
actions: [],
contracts: [],
relayers: [],
relayerGroups: [],
notifications: [],
secrets: [],
forkedNetworks: [],
privateNetworks: [],
};
// Forked Networks
const forkedNetworkClient = (0, utils_1.getNetworkClient)(this.teamKey);
const listForkedNetworks = () => forkedNetworkClient.listForkedNetworks();
await this.wrapper(this.serverless, 'Forked Networks', (0, utils_1.removeDefenderIdReferences)(this.resources?.['forked-networks']), listForkedNetworks, async (forkedNetworks) => {
await Promise.all(forkedNetworks.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.tenantNetworkId}) from Defender`);
await forkedNetworkClient.deleteForkedNetwork(e.tenantNetworkId);
this.log.success(`Removed ${e.stackResourceId} (${e.tenantNetworkId})`);
}));
}, stdOut.forkedNetworks);
// Private Networks
const privateNetworkClient = (0, utils_1.getNetworkClient)(this.teamKey);
const listPrivateNetworks = () => privateNetworkClient.listPrivateNetworks();
await this.wrapper(this.serverless, 'Private Networks', (0, utils_1.removeDefenderIdReferences)(this.resources?.['private-networks']), listPrivateNetworks, async (privateNetworks) => {
await Promise.all(privateNetworks.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.tenantNetworkId}) from Defender`);
await privateNetworkClient.deletePrivateNetwork(e.tenantNetworkId);
this.log.success(`Removed ${e.stackResourceId} (${e.tenantNetworkId})`);
}));
}, stdOut.privateNetworks);
// Monitors
const monitorClient = (0, utils_1.getMonitorClient)(this.teamKey);
const listMonitors = () => monitorClient.list().then((i) => i.items);
await this.wrapper(this.serverless, 'Monitors', (0, utils_1.removeDefenderIdReferences)(this.resources?.monitors), listMonitors, async (monitors) => {
await Promise.all(monitors.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.monitorId}) from Defender`);
await monitorClient.delete(e.monitorId);
this.log.success(`Removed ${e.stackResourceId} (${e.monitorId})`);
}));
}, stdOut.monitors);
// Actions
const actionClient = (0, utils_1.getActionClient)(this.teamKey);
const listActions = () => actionClient.list().then((i) => i.items);
await this.wrapper(this.serverless, 'Actions', (0, utils_1.removeDefenderIdReferences)(this.resources.actions), listActions, async (actions) => {
await Promise.all(actions.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.actionId}) from Defender`);
await actionClient.delete(e.actionId);
this.log.success(`Removed ${e.stackResourceId} (${e.actionId})`);
}));
}, stdOut.actions);
// Contracts
const adminClient = (0, utils_1.getProposalClient)(this.teamKey);
const listContracts = () => adminClient.listContracts();
await this.wrapper(this.serverless, 'Contracts', (0, utils_1.removeDefenderIdReferences)(this.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', (0, utils_1.removeDefenderIdReferences)(this.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);
}
try {
// Relayer Group API keys
const relayGroupClient = (0, utils_1.getRelayGroupClient)(this.teamKey);
const listRelayerGroups = await relayGroupClient.list();
const existingRelayerGroups = listRelayerGroups.filter((e) => (0, utils_1.isTemplateResource)(this.serverless, e, 'Relayer Groups', (0, utils_1.removeDefenderIdReferences)(this.resources?.['relayer-groups']) ?? {}));
this.log.error('Deleting Relayer Groups is currently only possible via the Defender UI.');
this.log.progress('component-info', `Retrieving Relayer Group API Keys`);
await Promise.all(existingRelayerGroups.map(async (relayerGroup) => {
this.log.progress('component-info', `Retrieving API Keys for relayer group ${relayerGroup.stackResourceId}`);
const relayerGroupApiKeys = await relayGroupClient.listKeys(relayerGroup.relayerGroupId);
await Promise.all(relayerGroupApiKeys.map(async (e) => {
this.log.progress('component-remove-extra', `Removing ${e.stackResourceId} (${e.keyId}) from Defender`);
await relayGroupClient.deleteKey(e.relayerId, e.keyId);
this.log.success(`Removed ${e.stackResourceId} (${e.keyId})`);
}));
stdOut.relayerGroups.push({
relayerGroupId: relayerGroup.relayerGroupId,
relayerGroupApiKeys,
});
}));
}
catch (e) {
this.log.tryLogDefenderError(e);
}
// Notifications
const listNotifications = () => monitorClient.listNotificationChannels();
await this.wrapper(this.serverless, 'Notifications', (0, utils_1.removeDefenderIdReferences)(this.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 monitorClient.deleteNotificationChannel(e.notificationId, e.type);
this.log.success(`Removed ${e.stackResourceId} (${e.notificationId})`);
}));
}, stdOut.notifications);
// Secrets
const listSecrets = () => actionClient.listSecrets().then((r) => r.secretNames ?? []);
const allSecrets = (0, utils_1.getConsolidatedSecrets)(this.serverless, this.resources);
await this.wrapper(this.serverless, 'Secrets', allSecrets, listSecrets, async (secrets) => {
this.log.progress('component-remove-extra', `Removing (${secrets.join(', ')}) from Defender`);
await actionClient.createSecrets({
deletes: secrets,
secrets: {},
});
if (secrets.length)
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;