@cto.ai/ops
Version:
š» CTO.ai - The CLI built for Teams š
181 lines (180 loc) ⢠7.11 kB
JavaScript
;
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'],
}),
};