UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

929 lines 32.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CreateNATS = exports.CreateDictionary = exports.CreateKeyPair = exports.CreateTls = exports.CreateDocker = exports.CreateOpaque = exports.CreateAzureConnector = exports.CreateAzureSDK = exports.CreateGcp = exports.CreateUserpass = exports.CreateEcr = exports.CreateAws = exports.Reveal = exports.Edit = exports.SecretCmd = void 0; const _ = require("lodash"); // externalId: Joi.string() const options_1 = require("./options"); const generic_1 = require("./generic"); const resolver_1 = require("./resolver"); const query_1 = require("./query"); const io_1 = require("../util/io"); const command_1 = require("../cli/command"); const functions_1 = require("../util/functions"); const objects_1 = require("../util/objects"); const format_1 = require("../util/format"); class SecretCmd extends command_1.Command { constructor() { super(...arguments); this.command = 'secret'; this.describe = 'Manage secrets'; } builder(yargs) { const resolver = (0, resolver_1.kindResolver)('secret'); const schema = { props: [...query_1.defaultProps, 'type'], }; const opts = [options_1.withOrgOptions, options_1.withStandardOptions]; const commandName = 'secret'; const commandNamePlural = 'secrets'; const commandNameA = 'a secret'; return (yargs .demandCommand() .version(false) .help() // generic .command(new generic_1.Get(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Patch(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Delete(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Query(commandNamePlural, resolver, schema, ...opts).toYargs()) .command(new generic_1.Eventlog(commandName, resolver, ...opts).toYargs()) .command(new generic_1.ListPermissions(commandNameA, resolver, ...opts).toYargs()) .command(new generic_1.ViewAccessReport(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Tag(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Update(commandName, resolver, [ { path: 'description', }, { path: 'tags.<key>', }, ], ...opts).toYargs()) // specific .command(new Edit(resolver, ...opts).toYargs()) .command(new Reveal(resolver).toYargs()) .command(new Clone(resolver).toYargs()) // create .command(new CreateAws(resolver).toYargs()) .command(new CreateGcp(resolver).toYargs()) .command(new CreateAzureSDK(resolver).toYargs()) .command(new CreateAzureConnector(resolver).toYargs()) .command(new CreateUserpass(resolver).toYargs()) .command(new CreateOpaque(resolver).toYargs()) .command(new CreateDocker(resolver).toYargs()) .command(new CreateTls(resolver).toYargs()) .command(new CreateKeyPair(resolver).toYargs()) .command(new CreateDictionary(resolver).toYargs()) .command(new CreateEcr(resolver).toYargs()) .command(new CreateNATS(resolver).toYargs())); } async handle() { } } exports.SecretCmd = SecretCmd; class Edit extends command_1.Command { constructor(resolve, ...funcs) { super(); this.resolve = resolve; this.command = 'edit <ref>'; this.describe = 'Edit the referenced secret, as YAML, within an editor'; if (funcs.length == 0) { this.func = (0, functions_1.pipe)(generic_1.withSingleRef, options_1.withAllOptions, this.withReplaceOptions); } else { this.func = (0, functions_1.pipe)(this.withReplaceOptions, ...funcs); } } builder(yargs) { return this.func(yargs); } withReplaceOptions(yargs) { return yargs.options({ replace: { alias: 'r', description: 'Replace instead of patch/merge', type: 'boolean', default: 'false', }, }); } async handle(args) { var _a; const link = this.resolve.resourceLink(args.ref, this.session.context); let revealNotes = ''; let body; try { body = await this.client.get(link + '/-reveal'); } catch (e) { body = await this.client.get(link); revealNotes = 'You are not authorized to <reveal> the secret so you can only edit the metadata'; } let action = 'PATCH'; if (args.replace) { action = 'REPLACE'; } const header = `# You are about to ${action} ${link} # You are performing this operation as ${((_a = this.session.profile.authInfo) === null || _a === void 0 ? void 0 : _a.email) || '<system>'} # ${revealNotes} `; const editableYaml = header + (0, format_1.toSortedYamlString)(body); const editMod = require('../editor/editor'); const newContent = await editMod.edit(editableYaml, 'yaml'); if (newContent === undefined) { this.session.end('Resource was not modified. No changes have been submitted'); } const newPayload = (0, io_1.loadObject)(newContent, '<editor>'); if (_.isEqual(body, newPayload)) { this.session.end('Resource was not modified. No changes have been submitted'); } if (args.replace) { body = await this.client.put(link, newPayload); } else { body = await this.client.patch(link, newPayload); } this.session.outFormat(body); } } exports.Edit = Edit; class Reveal extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'reveal [ref]'; this.describe = 'Show the secret in plaintext'; } builder(yargs) { return (0, functions_1.pipe)(generic_1.withSingleRef, options_1.withOrgOptions, (yargs) => { return (0, options_1.withFormatOptions)(yargs, ['smart']); }, options_1.withRequestOptions, options_1.withDebugOptions)(yargs); } async handle(args) { let link = this.resolve.resourceLink(args.ref, this.session.context); link += '/-reveal'; const body = await this.client.get(link); if (args.output == 'smart') { this.outSmart(body); } else { this.session.outFormat(body); } } outSmart(res) { switch (true) { case res.type === 'opaque': let payload = res.data.payload; if (res.data.encoding == 'base64') { payload = Buffer.from(payload, 'base64').toString('utf-8'); } this.session.out(payload); break; case res.type === 'aws': case res.type === 'ecr': let arn = ''; if (res.data.roleArn) { arn = `AWS_ROLE_ARN=${res.data.roleArn}\n`; } this.session.out(` AWS_ACCESS_KEY_ID=${res.data.accessKey} AWS_SECRET_ACCESS_KEY=${res.data.secretKey} ${arn}`); break; case res.type === 'azure-connector': this.session.out(`${res.data.url}?code=${res.data.code} `); break; case res.type === 'azure-sdk': case res.type === 'gcp': case res.type === 'docker': this.session.outFormat(JSON.parse(res.data), { color: false }); break; case res.type === 'userpass': let pwd = res.data.password; if (res.data.encoding == 'base64') { pwd = Buffer.from(pwd, 'base64').toString('utf-8'); } this.session.out(` SECRET_USERNAME=${res.data.username} SECRET_PASSWORD=${pwd} `); break; // case res.type === 'docker': // this.session.out(JSON.stringify(JSON.parse(res.data), null, 2)); // break; case res.type === 'dictionary': let outputString = '\n'; for (let [key, value] of Object.entries(res.data)) { outputString += `${key}=${value}\n`; } this.session.out(outputString); break; default: this.session.outFormat(res); break; } } } exports.Reveal = Reveal; class Clone extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'clone <ref>'; this.describe = 'Create a clone of the referenced secret'; this.aliases = ['copy']; } builder(yargs) { return (0, functions_1.pipe)( // generic_1.withSingleRef, generic_1.withCloneOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const resourceLink = this.resolve.resourceLink(args.ref, this.session.context); const resource = await this.client.get(`${resourceLink}/-reveal`); resource.tags = { ...resource.tags, ...(0, generic_1.fromTagOptions)(args) }; if (args.description) { resource.description = args.description; } else { resource.description = (0, generic_1.guessDescription)(resource); } // override the name resource.name = args.name; const path = this.resolve.parentLink(this.session.context); const data = await this.client.create(path, resource); this.session.outFormat(data); } } class CreateAws extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-aws'; this.describe = 'Create a new AWS secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, 'access-key': { requiresArg: true, describe: 'AWS access key', demandOption: true, }, 'secret-key': { requiresArg: true, describe: 'AWS secret key', demandOption: true, }, 'role-arn': { requiresArg: true, describe: 'AWS role. Optional: Only if using "assumeRole"', }, 'external-id': { requiresArg: true, describe: 'AWS IAM Role External Id', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'aws', tags: (0, generic_1.fromTagOptions)(args), data: { accessKey: args.accessKey, secretKey: args.secretKey, roleArn: args.roleArn, }, }; if (args.externalId) { body.data.externalId = args.externalId; } const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateAws = CreateAws; class CreateEcr extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-ecr'; this.describe = 'Create a new ECR secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, 'access-key': { requiresArg: true, describe: 'AWS access key', demandOption: true, }, 'secret-key': { requiresArg: true, describe: 'AWS secret key', demandOption: true, }, 'role-arn': { requiresArg: true, describe: 'AWS role. Optional: Only if using "assumeRole"', }, repo: { requiresArg: true, demandOption: true, multiple: true, describe: 'ECR repository URI (e.g., AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPO_NAME)', }, 'external-id': { requiresArg: true, describe: 'AWS IAM Role External Id', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'ecr', tags: (0, generic_1.fromTagOptions)(args), data: { accessKey: args.accessKey, secretKey: args.secretKey, roleArn: args.roleArn, repos: _.uniq((0, objects_1.toArray)(args.repo)), }, }; if (args.externalId) { body.data.externalId = args.externalId; } const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateEcr = CreateEcr; class CreateUserpass extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-userpass'; this.describe = 'Create a new Username/Password secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, username: { demandOption: true, requiresArg: true, describe: 'Username', }, password: { demandOption: true, requiresArg: true, describe: 'Password', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'userpass', tags: (0, generic_1.fromTagOptions)(args), data: { username: args.username, password: args.password, }, }; const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateUserpass = CreateUserpass; class CreateGcp extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-gcp'; this.describe = 'Create a new GCP secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, file: { alias: 'f', requiresArg: true, demandOption: true, describe: 'Load the secret from a file. The file is usually exported from the GCP console', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'gcp', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; body.data = await (0, io_1.readTextFile)(args.file); const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateGcp = CreateGcp; class CreateAzureSDK extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-azure-sdk'; this.describe = 'Create a new Azure SDK secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, file: { alias: 'f', requiresArg: true, demandOption: true, describe: 'Load the secret from a file. The file is usually created using the command `az ad sp create-for-rbac`', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'azure-sdk', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; body.data = await (0, io_1.readTextFile)(args.file); const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateAzureSDK = CreateAzureSDK; class CreateAzureConnector extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-azure-connector'; this.describe = 'Create a new Azure Connector secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, url: { requiresArg: true, demandOption: true, describe: 'URL of the azure connector function', }, code: { requiresArg: true, demandOption: true, describe: 'Code of the azure connector function', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'azure-connector', data: { url: args.url, code: args.code, }, tags: (0, generic_1.fromTagOptions)(args), }; const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateAzureConnector = CreateAzureConnector; function withCreateOpaqueOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, file: { alias: 'f', requiresArg: true, demandOption: true, describe: 'Load the secret content from a file, use - for stdin', }, encoding: { describe: 'Set encoding. Available options: "base64", "plain"', default: 'base64', }, }); } class CreateOpaque extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-opaque'; this.describe = 'Create a new opaque secret'; } builder(yargs) { return (0, functions_1.pipe)( // withCreateOpaqueOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const path = this.resolve.homeLink(this.session.context); const secret = { name: args.name, description: args.description, type: 'opaque', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; // Handle encoding switch (args.encoding) { case 'plain': const plain = await (0, io_1.readTextFile)(args.file); secret.data = { payload: plain, encoding: 'plain', }; break; default: // Default encoding is base64 const buffer = await (0, io_1.readBinaryFile)(args.file); secret.data = { payload: buffer.toString('base64'), encoding: 'base64', }; break; } // Create opaque secret const newSecret = (await this.client.create(path, secret)); this.session.outFormat(newSecret); } } exports.CreateOpaque = CreateOpaque; class CreateDocker extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-docker'; this.describe = 'Create a new Docker secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, file: { alias: 'f', requiresArg: true, demandOption: true, describe: 'Load the docker config from a file (e.g., ~/.docker/config.json)', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'docker', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; const json = await (0, io_1.readTextFile)(args.file); body.data = json; const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateDocker = CreateDocker; class CreateTls extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-tls'; this.describe = 'Create a new TLS secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, key: { requiresArg: true, demandOption: true, describe: 'Path to the private key file in PEM format', }, cert: { requiresArg: true, demandOption: true, describe: 'Path to the certificate file in PEM format', }, chain: { requiresArg: true, demandOption: false, describe: 'Path to the certificate chain file in PEM format', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'tls', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; body.data = { key: await (0, io_1.readTextFile)(args.key), cert: await (0, io_1.readTextFile)(args.cert), }; if (args.chain) { body.data.chain = await (0, io_1.readTextFile)(args.chain); } const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateTls = CreateTls; class CreateKeyPair extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-keypair'; this.describe = 'Create a new KeyPair secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, secret: { requiresArg: true, demandOption: true, describe: 'Path to the secret key file', }, public: { requiresArg: true, demandOption: false, describe: 'Path to the public key file', }, passphrase: { requiresArg: true, demandOption: false, describe: 'Passpharse for the private key', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'keypair', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; body.data = { secretKey: await (0, io_1.readTextFile)(args.secret), publicKey: await (0, io_1.readTextFile)(args.public), }; if (args.passphrase) { body.data.passphrase = args.passphrase; } const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateKeyPair = CreateKeyPair; class CreateDictionary extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-dictionary'; this.aliases = ['create-dict']; this.describe = 'Create a new dictionary secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, entry: { describe: 'Add an entry to the dictionary. Use the syntax: `key=value`', requiresArg: true, multiple: true, demandOption: true, }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'dictionary', data: undefined, tags: (0, generic_1.fromTagOptions)(args), }; body.data = Object.fromEntries((0, objects_1.toArray)(args.entry).map((e) => { const i = e.indexOf('='); return [e.substring(0, i), e.substring(i + 1)]; })); const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateDictionary = CreateDictionary; class CreateNATS extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create-nats'; this.describe = 'Create a new nats account secret'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the secret', requiresArg: true, demandOption: true, }, description: { alias: 'desc', describe: 'Optional description, defaults to the name if not set', requiresArg: true, }, 'account-id': { describe: 'Account Id of the NATS account', requiresArg: true, demandOption: true, }, 'private-key': { describe: 'Private Key to access the NATS account', requiresArg: true, demandOption: true, }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, type: 'nats-account', data: { accountId: args.accountId, privateKey: args.privateKey, }, tags: (0, generic_1.fromTagOptions)(args), }; const path = this.resolve.homeLink(this.session.context); const data = await this.client.create(path, body); this.session.outFormat(data); } } exports.CreateNATS = CreateNATS; //# sourceMappingURL=secret.js.map