UNPKG

@cto.ai/ops

Version:

šŸ’» CTO.ai - The CLI built for Teams šŸš€

181 lines (180 loc) • 7.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const cli_sdk_1 = require("@cto.ai/cli-sdk"); const base_1 = tslib_1.__importDefault(require("./../../base")); const utils_1 = require("./../../utils"); const fs = tslib_1.__importStar(require("fs-extra")); const CustomErrors_1 = require("./../../errors/CustomErrors"); const parser_1 = require("@oclif/parser"); const { white, reset } = cli_sdk_1.ux.colors; class SecretsSet extends base_1.default { constructor() { super(...arguments); this.validateKeyInput = async (input) => { if (!input) { return `šŸ˜ž Sorry, the key cannot be empty`; } if (!utils_1.KEY_REGEX.test(input)) { return `šŸ˜ž Secret keys cannot begin with a number and may only contain letters, numbers, underscores, hyphens, and periods`; } return true; }; this.validateValueInput = async (input) => { if (!input) { return `šŸ˜ž Sorry, the value cannot be empty`; } return true; }; this.resolveFileSecret = async (input) => { if (!input.valueFilename) { return input; } try { const value = await fs.readFile(input.valueFilename, 'utf8'); return Object.assign(Object.assign({}, input), { value }); } catch (err) { this.debug('%O', err); throw new CustomErrors_1.ValueFileError(err); } }; this.promptForSecret = async (input) => { await cli_sdk_1.ux.print(`\nšŸ”‘ Add a secret to secret storage for team ${input.config.team.name} ${reset.green('→')}`); let key = ''; if (input.key) { const keyValidationResult = await this.validateKeyInput(input.key); if (keyValidationResult === true) { key = input.key; } else { await this.ux.print(keyValidationResult); } } key = key || (await cli_sdk_1.ux.prompt({ type: 'input', name: 'key', message: `Enter the name of the secret to be stored ${reset.green('→')}`, afterMessage: `${reset.white('Secret name:')}`, validate: this.validateKeyInput, })).key; let value = ''; if (input.value) { const valueValidationResult = await this.validateValueInput(input.value); if (valueValidationResult === true) { value = input.value; } else { await this.ux.print(valueValidationResult); } } value = value || (await cli_sdk_1.ux.prompt({ type: 'editor', name: 'value', message: `\nNext add the secret's value to be stored ${reset.green('→')}`, validate: this.validateValueInput, })).value.trim(); return Object.assign(Object.assign({}, input), { key, value }); }; this.setSecret = async (inputs) => { try { await this.services.api.create(`/private/teams/${inputs.config.team.name}/secrets`, { secrets: { [inputs.key]: inputs.value, }, }, { headers: { Authorization: this.accessToken, }, }); return inputs; } catch (err) { this.debug('%O', err); switch (err.error[0].code) { case 400: throw new CustomErrors_1.InvalidSecretVault(err); case 401: throw new CustomErrors_1.UserUnauthorized(err); case 403: if (err.error[0].message.includes('invalid secret token')) { throw new CustomErrors_1.InvalidSecretToken(err); } else { throw new CustomErrors_1.NoSecretsProviderFound(err); } default: throw new CustomErrors_1.SetSecretsProvider(err); } } }; this.logMessage = (inputs) => { this.log(`\n ${white(`šŸ™Œ Great job! Secret ${cli_sdk_1.ux.colors.callOutCyan(inputs.key)} has been added to your team ${cli_sdk_1.ux.colors.blueBright(inputs.config.team.name)}!`)}`); return inputs; }; this.sendAnalytics = async (inputs) => { const { config, key } = inputs; try { this.services.analytics.track('Ops CLI Secrets:Set', { username: config.user.username, setSecretKey: key, }, config); return inputs; } catch (err) { this.debug('%O', err); throw new CustomErrors_1.AnalyticsError(err); } }; } async run() { let { flags: { key, value, 'from-file': valueFilename }, } = this.parse(SecretsSet); const config = await this.isLoggedIn(); try { this.ux.spinner.start('Initializing'); const secretProviderErr = await this.services.secretService.checkForSecretProviderErrors(this.services.api, config); //@ts-ignore this.ux.spinner.stop(); if (secretProviderErr instanceof Error) { throw secretProviderErr; } const switchPipeline = (0, utils_1.asyncPipe)(this.resolveFileSecret, this.promptForSecret, this.setSecret, this.sendAnalytics, this.logMessage); await switchPipeline({ config, key, value, valueFilename, }); } catch (err) { this.debug('%O', err); this.config.runHook('error', { err, accessToken: config.tokens.accessToken, }); } } } exports.default = SecretsSet; SecretsSet.description = 'Add a key & value'; SecretsSet.flags = { key: parser_1.flags.string({ char: 'k', description: 'the key of the secret to set', }), value: parser_1.flags.string({ char: 'v', description: 'the value of the secret to set', exclusive: ['from-file'], }), 'from-file': parser_1.flags.string({ char: 'f', description: 'path to a file containing the value of the secret to set', exclusive: ['value'], }), };