@bussolabs/closeyourit-cli 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -81,6 +81,9 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
81
81
  | `errors resolve\|reopen\|mute\|unmute <id> --project <id\|key>` | Triage an error group. |
82
82
  | `tokens list --project <id\|key>` | List ingest tokens. |
83
83
  | `tokens create --project <id\|key> --name <name> --environment-id <id>` | Create a token (secret shown once). |
84
+ | `tokens provision --project <id\|key> --name <name> --environment-id <code\|id> --to-project <id\|key> --to-environment-id <code\|id> --secret-name <NAME>` | Generate and deliver a token without revealing its value. GitHub sync is enabled by default; use `--no-sync-github` for vault-only delivery. |
85
+ | `tokens provisions show <id> --project <id\|key>` | Show secret-free provisioning status. |
86
+ | `tokens provisions retry <id> --project <id\|key>` | Retry GitHub sync without regenerating or revealing the token. |
84
87
  | `tokens rotate <id> --project <id\|key>` | Rotate a token (new secret shown once). |
85
88
  | `tokens revoke <id> --project <id\|key>` | Revoke a token. |
86
89
  | `secrets assets list --project <id\|key>` | List encrypted secret-file metadata (never contents). |
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalDelete extends BaseCommand {
3
+ static args: {
4
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<unknown>;
9
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ class PersonalDelete extends base_1.BaseCommand {
6
+ static args = {
7
+ name: core_1.Args.string({ description: 'Secret name', required: true }),
8
+ };
9
+ static description = 'Delete a personal secret from the current organization';
10
+ static examples = ['<%= config.bin %> personal delete API_KEY'];
11
+ async run() {
12
+ const { args } = await this.parse(PersonalDelete);
13
+ const name = args.name.toUpperCase();
14
+ await this.api.delete(`/cli/v1/personal_secrets/${encodeURIComponent(name)}`);
15
+ if (!this.jsonEnabled()) {
16
+ this.log(`Personal secret ${name} deleted.`);
17
+ }
18
+ return { deleted: name };
19
+ }
20
+ }
21
+ exports.default = PersonalDelete;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalDownload extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ out: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const core_1 = require("@oclif/core");
5
+ const base_1 = require("../../base");
6
+ class PersonalDownload extends base_1.BaseCommand {
7
+ static description = 'Download all your personal secrets as .env or JSON (to a file or stdout). Values with newlines: use --format json. Prefer `cyi personal run` to avoid writing plaintext to disk.';
8
+ static examples = [
9
+ '<%= config.bin %> personal download --out .env',
10
+ '<%= config.bin %> personal download --format json',
11
+ ];
12
+ static flags = {
13
+ format: core_1.Flags.string({ default: 'env', description: 'Output format', options: ['env', 'json'] }),
14
+ out: core_1.Flags.string({ description: 'Write to this file instead of stdout' }),
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(PersonalDownload);
18
+ const res = await this.api.get('/cli/v1/personal_secrets/bundle');
19
+ const map = res.data ?? {};
20
+ const body = flags.format === 'json'
21
+ ? JSON.stringify(map, null, 2)
22
+ : Object.entries(map)
23
+ .map(([key, value]) => `${key}=${value}`)
24
+ .join('\n');
25
+ if (flags.out) {
26
+ await (0, promises_1.writeFile)(flags.out, `${body}\n`);
27
+ if (!this.jsonEnabled()) {
28
+ this.log(`Wrote ${Object.keys(map).length} personal secrets → ${flags.out}`);
29
+ this.warn('The file contains plaintext secrets. Prefer `cyi personal run` to inject them without touching disk.');
30
+ }
31
+ }
32
+ else if (!this.jsonEnabled()) {
33
+ this.log(body);
34
+ }
35
+ return { count: Object.keys(map).length, format: flags.format, out: flags.out ?? null };
36
+ }
37
+ }
38
+ exports.default = PersonalDownload;
@@ -0,0 +1,9 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalGet extends BaseCommand {
3
+ static args: {
4
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<unknown>;
9
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ class PersonalGet extends base_1.BaseCommand {
6
+ static args = {
7
+ name: core_1.Args.string({ description: 'Secret name', required: true }),
8
+ };
9
+ static description = 'Print the value of a single personal secret (pipeable).';
10
+ static examples = ['<%= config.bin %> personal get OPENAI_API_KEY'];
11
+ async run() {
12
+ const { args } = await this.parse(PersonalGet);
13
+ const res = await this.api.get('/cli/v1/personal_secrets/bundle');
14
+ const map = res.data ?? {};
15
+ const key = args.name.toUpperCase();
16
+ if (!(key in map)) {
17
+ this.error(`Personal secret not found: ${key}`, { exit: 1 });
18
+ }
19
+ if (!this.jsonEnabled()) {
20
+ this.log(map[key]);
21
+ }
22
+ return { name: key, value: map[key] };
23
+ }
24
+ }
25
+ exports.default = PersonalGet;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalImport extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'from-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const core_1 = require("@oclif/core");
5
+ const base_1 = require("../../base");
6
+ const stdin_1 = require("../../lib/stdin");
7
+ // Reuse the exact env/JSON parsers from the project-secrets twin so the two vaults never diverge.
8
+ const import_1 = require("../secrets/import");
9
+ class PersonalImport extends base_1.BaseCommand {
10
+ static description = 'Import many personal secrets at once (all-or-nothing) from a .env or JSON file';
11
+ static examples = [
12
+ '<%= config.bin %> personal import --from-file .env',
13
+ '<%= config.bin %> personal import --format json --from-file secrets.json',
14
+ 'doppler secrets download --no-file --format json | <%= config.bin %> personal import --format json',
15
+ ];
16
+ static flags = {
17
+ 'from-file': core_1.Flags.string({ description: 'Path to a .env or JSON file (default: read from stdin)' }),
18
+ format: core_1.Flags.string({ default: 'env', description: 'Input format', options: ['env', 'json'] }),
19
+ };
20
+ async run() {
21
+ const { flags } = await this.parse(PersonalImport);
22
+ let text;
23
+ if (flags['from-file']) {
24
+ text = await (0, promises_1.readFile)(flags['from-file'], 'utf8');
25
+ }
26
+ else {
27
+ if (process.stdin.isTTY) {
28
+ this.error('Provide --from-file or pipe the input via stdin (e.g. `doppler secrets download --format json | cyi personal import --format json`)', { exit: 1 });
29
+ }
30
+ text = await (0, stdin_1.readStream)();
31
+ }
32
+ const variables = flags.format === 'json' ? (0, import_1.parseJson)(text) : (0, import_1.parseEnv)(text);
33
+ if (variables.length === 0) {
34
+ this.error('No variables found in the input', { exit: 1 });
35
+ }
36
+ const res = await this.api.post('/cli/v1/personal_secrets/import', { variables });
37
+ if (!this.jsonEnabled()) {
38
+ this.log(`Imported ${res.data?.imported ?? variables.length} personal secrets.`);
39
+ }
40
+ return res;
41
+ }
42
+ }
43
+ exports.default = PersonalImport;
@@ -0,0 +1,6 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalList extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<unknown>;
6
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../base");
4
+ const output_1 = require("../../lib/output");
5
+ class PersonalList extends base_1.BaseCommand {
6
+ static description = 'List your personal secret names for the current organization. Never prints values.';
7
+ static examples = ['<%= config.bin %> personal list', '<%= config.bin %> personal list --json'];
8
+ async run() {
9
+ await this.parse(PersonalList);
10
+ const res = await this.api.get('/cli/v1/personal_secrets');
11
+ if (!this.jsonEnabled()) {
12
+ const rows = (res.data ?? []).map((secret) => [String(secret.name ?? ''), String(secret.description ?? '')]);
13
+ this.log((0, output_1.renderTable)(['NAME', 'DESCRIPTION'], rows));
14
+ }
15
+ return res;
16
+ }
17
+ }
18
+ exports.default = PersonalList;
@@ -0,0 +1,8 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalRun extends BaseCommand {
3
+ static strict: boolean;
4
+ static enableJsonFlag: boolean;
5
+ static description: string;
6
+ static examples: string[];
7
+ run(): Promise<unknown>;
8
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const base_1 = require("../../base");
4
+ const subprocess_1 = require("../../lib/subprocess");
5
+ class PersonalRun extends base_1.BaseCommand {
6
+ // Everything after `--` is the child command + its args (not parsed as flags).
7
+ static strict = false;
8
+ // The output belongs to the child process, not to us.
9
+ static enableJsonFlag = false;
10
+ static description = 'Run a command with your personal secrets injected as env vars (like `doppler run`). Secrets never touch disk.';
11
+ static examples = [
12
+ '<%= config.bin %> personal run -- bundle exec rails server',
13
+ '<%= config.bin %> personal run -- printenv OPENAI_API_KEY',
14
+ ];
15
+ async run() {
16
+ const { argv } = await this.parse(PersonalRun);
17
+ const parts = argv;
18
+ if (parts.length === 0) {
19
+ this.error('Provide a command to run after `--`, e.g. `cyi personal run -- printenv`', { exit: 1 });
20
+ }
21
+ const { data } = await this.api.get('/cli/v1/personal_secrets/bundle');
22
+ const [command, ...commandArgs] = parts;
23
+ const code = await (0, subprocess_1.runCommand)(command, commandArgs, { ...process.env, ...(data ?? {}) });
24
+ // Propagate the child's exit code (0 on success) so `cyi personal run … && next` behaves like the child.
25
+ this.exit(code);
26
+ }
27
+ }
28
+ exports.default = PersonalRun;
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class PersonalSet extends BaseCommand {
3
+ static args: {
4
+ assignment: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ value: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../base");
5
+ class PersonalSet extends base_1.BaseCommand {
6
+ static args = {
7
+ assignment: core_1.Args.string({ description: 'NAME=VALUE, or just NAME with --value', required: true }),
8
+ };
9
+ static description = 'Set (create or update) a personal secret for the current organization';
10
+ static examples = [
11
+ '<%= config.bin %> personal set OPENAI_API_KEY=sk-live-...',
12
+ '<%= config.bin %> personal set API_KEY --value s3cr3t --description "Stripe key"',
13
+ ];
14
+ static flags = {
15
+ value: core_1.Flags.string({ description: 'Secret value (use when the arg is just NAME)' }),
16
+ description: core_1.Flags.string({ description: 'Optional description' }),
17
+ };
18
+ async run() {
19
+ const { args, flags } = await this.parse(PersonalSet);
20
+ const eq = args.assignment.indexOf('=');
21
+ const name = eq === -1 ? args.assignment : args.assignment.slice(0, eq);
22
+ const value = eq === -1 ? flags.value : args.assignment.slice(eq + 1);
23
+ if (value === undefined) {
24
+ this.error('Provide a value: use NAME=VALUE or pass --value', { exit: 1 });
25
+ }
26
+ const res = await this.api.post('/cli/v1/personal_secrets', {
27
+ name,
28
+ value,
29
+ description: flags.description,
30
+ });
31
+ if (!this.jsonEnabled()) {
32
+ this.log(`Personal secret ${String(name).toUpperCase()} saved.`);
33
+ }
34
+ return res;
35
+ }
36
+ }
37
+ exports.default = PersonalSet;
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class TokensProvision extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ 'environment-id': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ scope: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'to-project': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ 'to-environment-id': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ 'secret-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ 'idempotency-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ 'sync-github': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ 'confirm-production': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ };
17
+ run(): Promise<unknown>;
18
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const node_crypto_1 = require("node:crypto");
5
+ const base_1 = require("../../base");
6
+ const token_provision_1 = require("../../lib/token-provision");
7
+ class TokensProvision extends base_1.BaseCommand {
8
+ static description = 'Generate an ingest token and deliver it without revealing the secret';
9
+ static examples = [
10
+ '<%= config.bin %> tokens provision -p CYRA --name "Self monitoring" --environment-id staging --to-project CYRA --to-environment-id staging --secret-name CLOSEYOURIT_TOKEN',
11
+ ];
12
+ static flags = {
13
+ ...base_1.projectFlag,
14
+ name: core_1.Flags.string({ description: 'Human-readable token name', required: true }),
15
+ 'environment-id': core_1.Flags.string({ description: 'Source environment code or id', required: true }),
16
+ scope: core_1.Flags.string({ description: 'Token scope (repeatable)', multiple: true, options: ['ingest', 'read'] }),
17
+ 'to-project': core_1.Flags.string({ description: 'Destination project id or key', required: true }),
18
+ 'to-environment-id': core_1.Flags.string({ description: 'Destination environment code or id', required: true }),
19
+ 'secret-name': core_1.Flags.string({ description: 'Destination vault variable name', required: true }),
20
+ 'idempotency-key': core_1.Flags.string({ description: 'Stable key for safe request retries' }),
21
+ 'sync-github': core_1.Flags.boolean({ description: 'Synchronize the destination vault to GitHub', default: true, allowNo: true }),
22
+ 'confirm-production': core_1.Flags.boolean({ description: 'Required when source or destination is production' }),
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(TokensProvision);
26
+ const [projectId, destinationProjectId] = await Promise.all([
27
+ this.resolveProjectId(flags.project),
28
+ this.resolveProjectId(flags['to-project']),
29
+ ]);
30
+ const response = await this.api.post(`/cli/v1/projects/${projectId}/tokens/provisions`, {
31
+ name: flags.name,
32
+ environment_id: flags['environment-id'],
33
+ scopes: flags.scope?.length ? flags.scope : ['ingest'],
34
+ idempotency_key: flags['idempotency-key'] ?? (0, node_crypto_1.randomUUID)(),
35
+ sync_github: flags['sync-github'],
36
+ confirm_production: flags['confirm-production'] ?? false,
37
+ destination: {
38
+ project_id: destinationProjectId,
39
+ environment_id: flags['to-environment-id'],
40
+ secret_name: flags['secret-name'],
41
+ },
42
+ });
43
+ const safe = (0, token_provision_1.safeTokenProvisionEnvelope)(response);
44
+ if (!this.jsonEnabled()) {
45
+ const data = safe.data;
46
+ this.log('Token generated and delivered without revealing its value.');
47
+ this.log(` provision: ${data.provision?.id ?? '-'}`);
48
+ this.log(` token: ${data.token?.id ?? '-'}`);
49
+ this.log(` prefix: ${data.token?.token_prefix ?? '-'}`);
50
+ this.log(` status: ${data.provision?.status ?? '-'}`);
51
+ }
52
+ return safe;
53
+ }
54
+ }
55
+ exports.default = TokensProvision;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class TokensProvisionsRetry extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../../base");
5
+ const token_provision_1 = require("../../../lib/token-provision");
6
+ class TokensProvisionsRetry extends base_1.BaseCommand {
7
+ static description = 'Retry GitHub synchronization without regenerating or revealing the token';
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Provision id', required: true }),
10
+ };
11
+ static flags = { ...base_1.projectFlag };
12
+ async run() {
13
+ const { args, flags } = await this.parse(TokensProvisionsRetry);
14
+ const projectId = await this.resolveProjectId(flags.project);
15
+ const response = await this.api.post(`/cli/v1/projects/${projectId}/tokens/provisions/${args.id}/retry`);
16
+ const safe = (0, token_provision_1.safeTokenProvisionEnvelope)(response);
17
+ if (!this.jsonEnabled()) {
18
+ const provision = safe.data;
19
+ this.log(`Provision ${provision.id ?? args.id} queued again.`);
20
+ this.log(` status: ${provision.status ?? '-'}`);
21
+ }
22
+ return safe;
23
+ }
24
+ }
25
+ exports.default = TokensProvisionsRetry;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class TokensProvisionsShow extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const base_1 = require("../../../base");
5
+ const token_provision_1 = require("../../../lib/token-provision");
6
+ class TokensProvisionsShow extends base_1.BaseCommand {
7
+ static description = 'Show secret-free token provision status';
8
+ static args = {
9
+ id: core_1.Args.string({ description: 'Provision id', required: true }),
10
+ };
11
+ static flags = { ...base_1.projectFlag };
12
+ async run() {
13
+ const { args, flags } = await this.parse(TokensProvisionsShow);
14
+ const projectId = await this.resolveProjectId(flags.project);
15
+ const response = await this.api.get(`/cli/v1/projects/${projectId}/tokens/provisions/${args.id}`);
16
+ const safe = (0, token_provision_1.safeTokenProvisionEnvelope)(response);
17
+ if (!this.jsonEnabled()) {
18
+ const data = safe.data;
19
+ this.log(`Provision ${data.provision?.id ?? args.id}`);
20
+ this.log(` status: ${data.provision?.status ?? '-'}`);
21
+ this.log(` destination: ${data.provision?.destination_project_id ?? '-'} / ${data.provision?.destination_environment_id ?? '-'}`);
22
+ this.log(` secret name: ${data.provision?.secret_name ?? '-'}`);
23
+ if (data.provision?.error_code)
24
+ this.log(` error: ${data.provision.error_code}`);
25
+ }
26
+ return safe;
27
+ }
28
+ }
29
+ exports.default = TokensProvisionsShow;
@@ -0,0 +1,8 @@
1
+ import type { Envelope } from './api';
2
+ type UnknownRecord = Record<string, unknown>;
3
+ /**
4
+ * Rebuild the backend response from an allow-list. Even if a future backend regression adds a
5
+ * plaintext field, blind commands cannot return it through oclif's JSON formatter.
6
+ */
7
+ export declare function safeTokenProvisionEnvelope(response: Envelope<unknown>): Envelope<UnknownRecord>;
8
+ export {};
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.safeTokenProvisionEnvelope = safeTokenProvisionEnvelope;
4
+ const tokenKeys = [
5
+ 'id',
6
+ 'name',
7
+ 'environment_id',
8
+ 'token_prefix',
9
+ 'public_key',
10
+ 'scopes',
11
+ 'last_used_at',
12
+ 'revoked_at',
13
+ 'created_at',
14
+ ];
15
+ const provisionKeys = [
16
+ 'id',
17
+ 'status',
18
+ 'secret_name',
19
+ 'sync_github',
20
+ 'error_code',
21
+ 'error_message',
22
+ 'synced_at',
23
+ 'created_at',
24
+ 'updated_at',
25
+ 'source_project_id',
26
+ 'source_environment_id',
27
+ 'destination_project_id',
28
+ 'destination_environment_id',
29
+ ];
30
+ function record(value) {
31
+ return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
32
+ }
33
+ function pick(source, keys) {
34
+ const safe = {};
35
+ for (const key of keys) {
36
+ if (source[key] !== undefined)
37
+ safe[key] = source[key];
38
+ }
39
+ return safe;
40
+ }
41
+ /**
42
+ * Rebuild the backend response from an allow-list. Even if a future backend regression adds a
43
+ * plaintext field, blind commands cannot return it through oclif's JSON formatter.
44
+ */
45
+ function safeTokenProvisionEnvelope(response) {
46
+ const data = record(response.data);
47
+ const safeData = data.provision === undefined
48
+ ? pick(data, provisionKeys)
49
+ : {
50
+ token: pick(record(data.token), tokenKeys),
51
+ provision: pick(record(data.provision), provisionKeys),
52
+ };
53
+ return response.meta ? { data: safeData, meta: response.meta } : { data: safeData };
54
+ }