@bussolabs/closeyourit-cli 0.0.25 → 0.0.27

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.
Files changed (46) hide show
  1. package/README.md +22 -0
  2. package/dist/base.d.ts +10 -2
  3. package/dist/base.js +28 -10
  4. package/dist/commands/environments/create.d.ts +3 -0
  5. package/dist/commands/environments/create.js +11 -0
  6. package/dist/commands/environments/update.d.ts +3 -0
  7. package/dist/commands/environments/update.js +11 -0
  8. package/dist/commands/projects/set-environment-capabilities.d.ts +13 -0
  9. package/dist/commands/projects/set-environment-capabilities.js +39 -0
  10. package/dist/commands/secrets/assets/archive.d.ts +11 -0
  11. package/dist/commands/secrets/assets/archive.js +17 -0
  12. package/dist/commands/secrets/assets/delegate.d.ts +10 -0
  13. package/dist/commands/secrets/assets/delegate.js +17 -0
  14. package/dist/commands/secrets/assets/download.d.ts +14 -0
  15. package/dist/commands/secrets/assets/download.js +25 -0
  16. package/dist/commands/secrets/assets/list.d.ts +10 -0
  17. package/dist/commands/secrets/assets/list.js +18 -0
  18. package/dist/commands/secrets/assets/purge.d.ts +12 -0
  19. package/dist/commands/secrets/assets/purge.js +22 -0
  20. package/dist/commands/secrets/assets/rollback.d.ts +11 -0
  21. package/dist/commands/secrets/assets/rollback.js +17 -0
  22. package/dist/commands/secrets/assets/shared-list.d.ts +5 -0
  23. package/dist/commands/secrets/assets/shared-list.js +15 -0
  24. package/dist/commands/secrets/assets/shared-upload.d.ts +11 -0
  25. package/dist/commands/secrets/assets/shared-upload.js +24 -0
  26. package/dist/commands/secrets/assets/undelegate.d.ts +10 -0
  27. package/dist/commands/secrets/assets/undelegate.js +17 -0
  28. package/dist/commands/secrets/assets/upload.d.ts +12 -0
  29. package/dist/commands/secrets/assets/upload.js +25 -0
  30. package/dist/commands/secrets/assets/versions.d.ts +10 -0
  31. package/dist/commands/secrets/assets/versions.js +18 -0
  32. package/dist/commands/service-accounts/create.d.ts +15 -0
  33. package/dist/commands/service-accounts/create.js +46 -0
  34. package/dist/commands/service-accounts/delete.d.ts +12 -0
  35. package/dist/commands/service-accounts/delete.js +25 -0
  36. package/dist/commands/service-accounts/list.d.ts +9 -0
  37. package/dist/commands/service-accounts/list.js +25 -0
  38. package/dist/commands/service-accounts/tokens/create.d.ts +10 -0
  39. package/dist/commands/service-accounts/tokens/create.js +27 -0
  40. package/dist/commands/service-accounts/tokens/revoke.d.ts +13 -0
  41. package/dist/commands/service-accounts/tokens/revoke.js +26 -0
  42. package/dist/lib/api.js +6 -0
  43. package/dist/lib/config.js +10 -1
  44. package/oclif.manifest.json +4223 -3293
  45. package/opencli.json +142 -1
  46. package/package.json +2 -2
package/README.md CHANGED
@@ -24,6 +24,17 @@ closeyourit projects list
24
24
  URL (and opens it in your browser), then polls until you approve. The resulting token, account and
25
25
  organization are stored locally.
26
26
 
27
+ ### Headless / CI / agents
28
+
29
+ Set `CLOSEYOURIT_TOKEN` to a user token (`cyi_u_…`) to authenticate non-interactively, without the
30
+ device-flow login. It overrides the stored config token. Ideal for a **service account** token driving
31
+ an agent or CI job:
32
+
33
+ ```bash
34
+ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
35
+ closeyourit secrets bundle -p KEY -e development
36
+ ```
37
+
27
38
  ## Commands
28
39
 
29
40
  | Command | Description |
@@ -70,6 +81,11 @@ organization are stored locally.
70
81
  | `tokens create --project <id\|key> --name <name> --environment-id <id>` | Create a token (secret shown once). |
71
82
  | `tokens rotate <id> --project <id\|key>` | Rotate a token (new secret shown once). |
72
83
  | `tokens revoke <id> --project <id\|key>` | Revoke a token. |
84
+ | `secrets assets list --project <id\|key>` | List encrypted secret-file metadata (never contents). |
85
+ | `secrets assets upload --project <id\|key> --name <name> --file <path> [--environment]` | Encrypt and upload `.p8`, `.p12`, keystore or service-account JSON. |
86
+ | `secrets assets download <id> --project <id\|key> --output <path> [--version] [--force]` | Decrypt to an explicit `0600` file; refuses overwrite by default. |
87
+ | `secrets assets versions\|rollback\|archive\|purge …` | Manage immutable versions, restore, archive or owner-only permanent purge. |
88
+ | `secrets assets shared-list\|shared-upload\|delegate\|undelegate …` | Manage one organization-level ciphertext and delegate it to authorized projects. |
73
89
  | `tickets list --project <id\|key> [--page]` | List tickets. |
74
90
  | `tickets show <id> --project <id\|key>` | Show one ticket. |
75
91
  | `tickets create --project <id\|key> --title <t> [--kind] [--step-*] [--description] [--status-id] [--priority-id]` | Create a ticket. |
@@ -120,6 +136,11 @@ organization are stored locally.
120
136
  | `agents tokens list [--page]` | List the org automator tokens (cyi_a_). |
121
137
  | `agents tokens create <name>` | Create an org automator token (secret shown only once). |
122
138
  | `agents tokens revoke <id> --confirm` | Revoke an org automator token. |
139
+ | `service-accounts list [--page]` | List the service accounts (AI members, CLI-only) in your org. |
140
+ | `service-accounts create --name [--handle] [--project <id\|key>…] [--group <id\|name>…] [--role <id\|name>…] [--grant-secrets] [--secret-environment <code>…]` | Create a service account (optionally granting read+write secrets, limited to environment codes). |
141
+ | `service-accounts delete <id> --confirm` | Delete a service account (revokes tokens + removes access; secrets audit kept). |
142
+ | `service-accounts tokens create <account-id> <name>` | Mint a CLI token (cyi_u_) for a service account (secret shown only once). |
143
+ | `service-accounts tokens revoke <account-id> <token-id> --confirm` | Revoke a service account token. |
123
144
  | `monitors create --project <id\|key> --url <url> [--environment] [--http-method] [--interval-seconds] [--expected-status] [--timeout-seconds] [--expected-body-keyword] [--ssl-expiry-warn-days] [--group-id]` | Create an uptime monitor (one per environment). |
124
145
  | `monitors update <id> --project <id\|key> [--url] [--http-method] [--interval-seconds] [--expected-status] [--timeout-seconds] [--expected-body-keyword] [--ssl-expiry-warn-days] [--group-id]` | Update an uptime monitor. |
125
146
  | `monitors publish\|unpublish <id> --project <id\|key>` | Publish / unpublish the monitor's public status page. |
@@ -189,6 +210,7 @@ to clear it locally; revoke the token on the server at `/account/cli/tokens`.
189
210
 
190
211
  | Variable | Purpose | Default |
191
212
  | --- | --- | --- |
213
+ | `CLOSEYOURIT_TOKEN` | User token (`cyi_u_…`) for headless/CI/agent use; overrides the stored config token. | — |
192
214
  | `CLOSEYOURIT_API_URL` | Default backend base URL (overridden by a persisted `--api-url`). | `https://www.closeyour.it` |
193
215
  | `CLOSEYOURIT_CONFIG_DIR` | Directory holding `config.json`. | `~/.config/closeyourit` |
194
216
 
package/dist/base.d.ts CHANGED
@@ -19,7 +19,11 @@ export declare abstract class BaseCommand extends Command {
19
19
  protected cfg: CliConfig;
20
20
  protected api: CliApi;
21
21
  init(): Promise<void>;
22
- /** Resolve a project reference (UUID passes through; otherwise matched by key). */
22
+ /**
23
+ * Resolve a project reference (UUID passes through; otherwise matched by key, case-insensitive).
24
+ * Walks every page of `/cli/v1/projects`: a key can live past the first page, so a single-page
25
+ * lookup would 404 keys like legalbloom LBRA/LBWB while their UUID (and first-page keys) worked (CYCL-1).
26
+ */
23
27
  protected resolveProjectId(value: string): Promise<string>;
24
28
  /** Resolve a role reference (UUID passes through; otherwise matched by name, case-insensitive). */
25
29
  protected resolveRoleId(value: string): Promise<string>;
@@ -33,6 +37,10 @@ export declare abstract class BaseCommand extends Command {
33
37
  protected resolveAll(values: string[], resolve: (value: string) => Promise<string>): Promise<string[]>;
34
38
  /** Resolve an `{id, name}` reference by name (UUID passes through). */
35
39
  private resolveByName;
36
- /** Print `code: message` for API errors, then exit non-zero. */
40
+ /**
41
+ * Surface API errors, then exit non-zero. In `--json` mode `logToStderr` is a no-op, so emit the
42
+ * structured `{ error: { code, message } }` envelope on stdout instead — otherwise the failure is
43
+ * swallowed (empty stdout, exit looks like a silent success) for machine consumers (CYCL-1).
44
+ */
37
45
  protected catch(error: Interfaces.CommandError): Promise<unknown>;
38
46
  }
package/dist/base.js CHANGED
@@ -27,17 +27,26 @@ class BaseCommand extends core_1.Command {
27
27
  this.cfg = (0, config_1.loadConfig)();
28
28
  this.api = new api_1.CliApi(this.cfg);
29
29
  }
30
- /** Resolve a project reference (UUID passes through; otherwise matched by key). */
30
+ /**
31
+ * Resolve a project reference (UUID passes through; otherwise matched by key, case-insensitive).
32
+ * Walks every page of `/cli/v1/projects`: a key can live past the first page, so a single-page
33
+ * lookup would 404 keys like legalbloom LBRA/LBWB while their UUID (and first-page keys) worked (CYCL-1).
34
+ */
31
35
  async resolveProjectId(value) {
32
36
  if (exports.UUID_RE.test(value))
33
37
  return value;
34
- const res = await this.api.get('/cli/v1/projects');
35
- const projects = res.data ?? [];
36
- const match = projects.find((project) => (project.key ?? '').toLowerCase() === value.toLowerCase());
37
- if (!match) {
38
- throw new api_1.ApiRequestError(404, error_codes_1.ErrorCodes.Project.notFound, `Project not found: ${value}`);
39
- }
40
- return match.id;
38
+ let page = 1;
39
+ let totalPages = 1;
40
+ do {
41
+ // eslint-disable-next-line no-await-in-loop
42
+ const res = await this.api.get(`/cli/v1/projects?page=${page}&per=100`);
43
+ const match = (res.data ?? []).find((project) => (project.key ?? '').toLowerCase() === value.toLowerCase());
44
+ if (match)
45
+ return match.id;
46
+ totalPages = Number(res.meta?.total_pages ?? 1);
47
+ page += 1;
48
+ } while (page <= totalPages);
49
+ throw new api_1.ApiRequestError(404, error_codes_1.ErrorCodes.Project.notFound, `Project not found: ${value}`);
41
50
  }
42
51
  /** Resolve a role reference (UUID passes through; otherwise matched by name, case-insensitive). */
43
52
  resolveRoleId(value) {
@@ -77,10 +86,19 @@ class BaseCommand extends core_1.Command {
77
86
  }
78
87
  return match.id;
79
88
  }
80
- /** Print `code: message` for API errors, then exit non-zero. */
89
+ /**
90
+ * Surface API errors, then exit non-zero. In `--json` mode `logToStderr` is a no-op, so emit the
91
+ * structured `{ error: { code, message } }` envelope on stdout instead — otherwise the failure is
92
+ * swallowed (empty stdout, exit looks like a silent success) for machine consumers (CYCL-1).
93
+ */
81
94
  async catch(error) {
82
95
  if (error instanceof api_1.ApiRequestError) {
83
- this.logToStderr(`${error.code}: ${error.message}`);
96
+ if (this.jsonEnabled()) {
97
+ this.logJson({ error: { code: error.code, message: error.message } });
98
+ }
99
+ else {
100
+ this.logToStderr(`${error.code}: ${error.message}`);
101
+ }
84
102
  return this.exit(1);
85
103
  }
86
104
  return super.catch(error);
@@ -10,6 +10,9 @@ export default class EnvironmentsCreate extends BaseCommand {
10
10
  color: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
11
  position: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
12
  active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ servers: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ uptime: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ secrets: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
16
  };
14
17
  run(): Promise<unknown>;
15
18
  }
@@ -11,6 +11,7 @@ class EnvironmentsCreate extends base_1.BaseCommand {
11
11
  static examples = [
12
12
  '<%= config.bin %> environments create production --label Production',
13
13
  '<%= config.bin %> environments create staging --label Staging --color amber',
14
+ '<%= config.bin %> environments create staging --label Staging --no-uptime',
14
15
  ];
15
16
  static flags = {
16
17
  label: core_1.Flags.string({ description: 'Human-readable label', required: true }),
@@ -18,6 +19,10 @@ class EnvironmentsCreate extends base_1.BaseCommand {
18
19
  color: core_1.Flags.string({ description: 'Color label', default: 'emerald' }),
19
20
  position: core_1.Flags.integer({ description: 'Sort position' }),
20
21
  active: core_1.Flags.boolean({ description: 'Whether the environment is active', allowNo: true }),
22
+ // Default capabilities projects can enable on this environment (each project can override).
23
+ servers: core_1.Flags.boolean({ description: 'Servers capability default', allowNo: true }),
24
+ uptime: core_1.Flags.boolean({ description: 'Uptime capability default', allowNo: true }),
25
+ secrets: core_1.Flags.boolean({ description: 'Secrets capability default', allowNo: true }),
21
26
  };
22
27
  async run() {
23
28
  const { args, flags } = await this.parse(EnvironmentsCreate);
@@ -26,6 +31,12 @@ class EnvironmentsCreate extends base_1.BaseCommand {
26
31
  body.position = flags.position;
27
32
  if (flags.active !== undefined)
28
33
  body.active = flags.active;
34
+ if (flags.servers !== undefined)
35
+ body.servers_enabled = flags.servers;
36
+ if (flags.uptime !== undefined)
37
+ body.uptime_enabled = flags.uptime;
38
+ if (flags.secrets !== undefined)
39
+ body.secrets_enabled = flags.secrets;
29
40
  const res = await this.api.post('/cli/v1/environments', body);
30
41
  if (!this.jsonEnabled()) {
31
42
  this.log('Environment created:');
@@ -11,6 +11,9 @@ export default class EnvironmentsUpdate extends BaseCommand {
11
11
  color: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
12
  position: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
13
  active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ servers: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ uptime: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ secrets: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
17
  };
15
18
  run(): Promise<unknown>;
16
19
  }
@@ -12,6 +12,7 @@ class EnvironmentsUpdate extends base_1.BaseCommand {
12
12
  '<%= config.bin %> environments update staging --label "Staging env"',
13
13
  '<%= config.bin %> environments update production --color indigo',
14
14
  '<%= config.bin %> environments update staging --no-active',
15
+ '<%= config.bin %> environments update staging --no-uptime --servers',
15
16
  ];
16
17
  static flags = {
17
18
  code: core_1.Flags.string({ description: 'New code (lowercase)' }),
@@ -19,6 +20,10 @@ class EnvironmentsUpdate extends base_1.BaseCommand {
19
20
  color: core_1.Flags.string({ description: 'Color label' }),
20
21
  position: core_1.Flags.integer({ description: 'Sort position' }),
21
22
  active: core_1.Flags.boolean({ description: 'Whether the environment is active', allowNo: true }),
23
+ // Default capabilities projects can enable on this environment (each project can override).
24
+ servers: core_1.Flags.boolean({ description: 'Servers capability default', allowNo: true }),
25
+ uptime: core_1.Flags.boolean({ description: 'Uptime capability default', allowNo: true }),
26
+ secrets: core_1.Flags.boolean({ description: 'Secrets capability default', allowNo: true }),
22
27
  };
23
28
  async run() {
24
29
  const { args, flags } = await this.parse(EnvironmentsUpdate);
@@ -33,6 +38,12 @@ class EnvironmentsUpdate extends base_1.BaseCommand {
33
38
  body.position = flags.position;
34
39
  if (flags.active !== undefined)
35
40
  body.active = flags.active;
41
+ if (flags.servers !== undefined)
42
+ body.servers_enabled = flags.servers;
43
+ if (flags.uptime !== undefined)
44
+ body.uptime_enabled = flags.uptime;
45
+ if (flags.secrets !== undefined)
46
+ body.secrets_enabled = flags.secrets;
36
47
  // Identifier (id or code) goes straight in the path — the backend resolves id-or-code.
37
48
  const res = await this.api.put(`/cli/v1/environments/${encodeURIComponent(args.environment)}`, body);
38
49
  if (!this.jsonEnabled()) {
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../base';
2
+ export default class ProjectsSetEnvironmentCapabilities extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ servers: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ uptime: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ secrets: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ environment: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<unknown>;
13
+ }
@@ -0,0 +1,39 @@
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 output_1 = require("../../lib/output");
6
+ class ProjectsSetEnvironmentCapabilities extends base_1.BaseCommand {
7
+ static description = 'Override the servers/uptime/secrets capabilities of a project environment (inherit = follow the environment default)';
8
+ static examples = [
9
+ '<%= config.bin %> projects set-environment-capabilities -p LBRA -e production --uptime off',
10
+ '<%= config.bin %> projects set-environment-capabilities -p legalbloom-rails -e staging --uptime off --secrets inherit',
11
+ ];
12
+ static flags = {
13
+ ...base_1.projectFlag,
14
+ ...base_1.environmentFlag,
15
+ // inherit = clear the override (follow the environment default); on/off = force it for this project.
16
+ servers: core_1.Flags.string({ description: 'Servers capability', options: ['inherit', 'on', 'off'] }),
17
+ uptime: core_1.Flags.string({ description: 'Uptime capability', options: ['inherit', 'on', 'off'] }),
18
+ secrets: core_1.Flags.string({ description: 'Secrets capability', options: ['inherit', 'on', 'off'] }),
19
+ };
20
+ async run() {
21
+ const { flags } = await this.parse(ProjectsSetEnvironmentCapabilities);
22
+ const projectId = await this.resolveProjectId(flags.project);
23
+ // Only the provided capabilities are sent — the others keep their current override.
24
+ const body = {};
25
+ if (flags.servers !== undefined)
26
+ body.servers = flags.servers;
27
+ if (flags.uptime !== undefined)
28
+ body.uptime = flags.uptime;
29
+ if (flags.secrets !== undefined)
30
+ body.secrets = flags.secrets;
31
+ const res = await this.api.put(`/cli/v1/projects/${projectId}/environments/${encodeURIComponent(flags.environment)}/capabilities`, body);
32
+ if (!this.jsonEnabled()) {
33
+ this.log('Capabilities updated:');
34
+ this.log((0, output_1.renderRecord)(res.data ?? {}));
35
+ }
36
+ return res;
37
+ }
38
+ }
39
+ exports.default = ProjectsSetEnvironmentCapabilities;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsArchive extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ confirm: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,17 @@
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 SecretsAssetsArchive extends base_1.BaseCommand {
6
+ static args = { id: core_1.Args.string({ required: true }) };
7
+ static flags = { ...base_1.projectFlag, confirm: core_1.Flags.boolean({ required: true }) };
8
+ async run() {
9
+ const { args, flags } = await this.parse(SecretsAssetsArchive);
10
+ const projectId = await this.resolveProjectId(flags.project);
11
+ await this.api.delete(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets/${encodeURIComponent(args.id)}`);
12
+ if (!this.jsonEnabled())
13
+ this.log(`Archived secret asset ${args.id}`);
14
+ return { archived: true, id: args.id };
15
+ }
16
+ }
17
+ exports.default = SecretsAssetsArchive;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsDelegate extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,17 @@
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 SecretsAssetsDelegate extends base_1.BaseCommand {
6
+ static args = { id: core_1.Args.string({ required: true }) };
7
+ static flags = { project: core_1.Flags.string({ char: 'p', required: true }) };
8
+ async run() {
9
+ const { args, flags } = await this.parse(SecretsAssetsDelegate);
10
+ const projectId = await this.resolveProjectId(flags.project);
11
+ const res = await this.api.post(`/cli/v1/shared_secret_assets/${encodeURIComponent(args.id)}/delegate`, { project_id: projectId });
12
+ if (!this.jsonEnabled())
13
+ this.log(`Delegated shared asset to ${flags.project}`);
14
+ return res;
15
+ }
16
+ }
17
+ exports.default = SecretsAssetsDelegate;
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsDownload extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static flags: {
8
+ output: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ version: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
+ };
13
+ run(): Promise<unknown>;
14
+ }
@@ -0,0 +1,25 @@
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 SecretsAssetsDownload extends base_1.BaseCommand {
7
+ static args = { id: core_1.Args.string({ required: true }) };
8
+ static description = 'Download and decrypt a secret file to an explicit path with mode 0600';
9
+ static flags = { ...base_1.projectFlag, output: core_1.Flags.string({ char: 'o', required: true }), version: core_1.Flags.integer(), force: core_1.Flags.boolean({ default: false }) };
10
+ async run() {
11
+ const { args, flags } = await this.parse(SecretsAssetsDownload);
12
+ const projectId = await this.resolveProjectId(flags.project);
13
+ const query = flags.version ? `?version=${flags.version}` : '';
14
+ const { data, filename } = await this.api.download(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets/${encodeURIComponent(args.id)}/download${query}`);
15
+ await (0, promises_1.writeFile)(flags.output, data, { flag: flags.force ? 'w' : 'wx', mode: 0o600 }).catch((error) => {
16
+ if (error.code === 'EEXIST')
17
+ this.error(`Refusing to overwrite ${flags.output}; pass --force`, { exit: 2 });
18
+ throw error;
19
+ });
20
+ if (!this.jsonEnabled())
21
+ this.log(`Saved ${data.byteLength} encrypted-vault bytes → ${flags.output}`);
22
+ return { bytes: data.byteLength, filename, path: flags.output, mode: '0600' };
23
+ }
24
+ }
25
+ exports.default = SecretsAssetsDownload;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsList extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ page: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ per: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,18 @@
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 output_1 = require("../../../lib/output");
6
+ class SecretsAssetsList extends base_1.BaseCommand {
7
+ static description = 'List encrypted secret files visible to a project (metadata only)';
8
+ static flags = { ...base_1.projectFlag, page: core_1.Flags.integer({ default: 1 }), per: core_1.Flags.integer({ default: 50 }) };
9
+ async run() {
10
+ const { flags } = await this.parse(SecretsAssetsList);
11
+ const projectId = await this.resolveProjectId(flags.project);
12
+ const res = await this.api.get(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets?page=${flags.page}&per=${flags.per}`);
13
+ if (!this.jsonEnabled())
14
+ this.log((0, output_1.renderTable)(['ID', 'NAME', 'TYPE', 'ENV', 'VERSION', 'BYTES'], (res.data ?? []).map((a) => [a.id, a.name, a.asset_type, a.environment?.code ?? 'all', a.current_version?.number ?? '', a.current_version?.byte_size ?? ''])));
15
+ return res;
16
+ }
17
+ }
18
+ exports.default = SecretsAssetsList;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsPurge extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static flags: {
8
+ 'confirm-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,22 @@
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 SecretsAssetsPurge extends base_1.BaseCommand {
6
+ static args = { id: core_1.Args.string({ required: true }) };
7
+ static description = 'Permanently delete an archived secret asset and all versions (owner only)';
8
+ static flags = { ...base_1.projectFlag, 'confirm-name': core_1.Flags.string({ description: 'Exact asset name confirmation', required: true }) };
9
+ async run() {
10
+ const { args, flags } = await this.parse(SecretsAssetsPurge);
11
+ const projectId = await this.resolveProjectId(flags.project);
12
+ const list = await this.api.get(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets?per=100`);
13
+ const asset = (list.data ?? []).find((row) => row.id === args.id);
14
+ if (!asset || asset.name !== flags['confirm-name'])
15
+ this.error('Confirmation name does not match the asset', { exit: 2 });
16
+ await this.api.delete(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets/${encodeURIComponent(args.id)}/purge`);
17
+ if (!this.jsonEnabled())
18
+ this.log(`Permanently purged ${asset.name}`);
19
+ return { purged: true, id: args.id };
20
+ }
21
+ }
22
+ exports.default = SecretsAssetsPurge;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsRollback extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ version: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,17 @@
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 SecretsAssetsRollback extends base_1.BaseCommand {
6
+ static args = { id: core_1.Args.string({ required: true }) };
7
+ static flags = { ...base_1.projectFlag, version: core_1.Flags.integer({ required: true }) };
8
+ async run() {
9
+ const { args, flags } = await this.parse(SecretsAssetsRollback);
10
+ const projectId = await this.resolveProjectId(flags.project);
11
+ const res = await this.api.post(`/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets/${encodeURIComponent(args.id)}/rollback`, { version: flags.version });
12
+ if (!this.jsonEnabled())
13
+ this.log(`Restored version ${flags.version} as a new encrypted version`);
14
+ return res;
15
+ }
16
+ }
17
+ exports.default = SecretsAssetsRollback;
@@ -0,0 +1,5 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsSharedList extends BaseCommand {
3
+ static description: string;
4
+ run(): Promise<unknown>;
5
+ }
@@ -0,0 +1,15 @@
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 SecretsAssetsSharedList extends base_1.BaseCommand {
6
+ static description = 'List organization-level encrypted secret files and delegated projects';
7
+ async run() {
8
+ await this.parse(SecretsAssetsSharedList);
9
+ const res = await this.api.get('/cli/v1/shared_secret_assets?per=100');
10
+ if (!this.jsonEnabled())
11
+ this.log((0, output_1.renderTable)(['ID', 'NAME', 'TYPE', 'ENV'], (res.data ?? []).map((a) => [a.id, a.name, a.asset_type, a.environment?.code ?? 'all'])));
12
+ return res;
13
+ }
14
+ }
15
+ exports.default = SecretsAssetsSharedList;
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsSharedUpload extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ file: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ environment: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<unknown>;
11
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const node_path_1 = require("node:path");
5
+ const core_1 = require("@oclif/core");
6
+ const base_1 = require("../../../base");
7
+ class SecretsAssetsSharedUpload extends base_1.BaseCommand {
8
+ static description = 'Encrypt and upload one organization-level secret file';
9
+ static flags = { file: core_1.Flags.string({ required: true }), name: core_1.Flags.string({ required: true }), environment: core_1.Flags.string(), description: core_1.Flags.string() };
10
+ async run() {
11
+ const { flags } = await this.parse(SecretsAssetsSharedUpload);
12
+ const info = await (0, promises_1.stat)(flags.file).catch(() => undefined);
13
+ if (!info?.isFile())
14
+ this.error(`File not found or unreadable: ${flags.file}`, { exit: 2 });
15
+ if (info.size > 10 * 1024 * 1024)
16
+ this.error('Secret file exceeds 10 MiB', { exit: 2 });
17
+ const data = await (0, promises_1.readFile)(flags.file);
18
+ const res = await this.api.upload('POST', '/cli/v1/shared_secret_assets', [{ field: 'file', filename: (0, node_path_1.basename)(flags.file), data: new Blob([data]) }], { body: { name: flags.name, environment: flags.environment, description: flags.description } });
19
+ if (!this.jsonEnabled())
20
+ this.log(`Encrypted and uploaded shared asset ${flags.name}`);
21
+ return res;
22
+ }
23
+ }
24
+ exports.default = SecretsAssetsSharedUpload;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsUndelegate extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }
@@ -0,0 +1,17 @@
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 SecretsAssetsUndelegate extends base_1.BaseCommand {
6
+ static args = { id: core_1.Args.string({ required: true }) };
7
+ static flags = { project: core_1.Flags.string({ char: 'p', required: true }) };
8
+ async run() {
9
+ const { args, flags } = await this.parse(SecretsAssetsUndelegate);
10
+ const projectId = await this.resolveProjectId(flags.project);
11
+ await this.api.delete(`/cli/v1/shared_secret_assets/${encodeURIComponent(args.id)}/undelegate?project_id=${encodeURIComponent(projectId)}`);
12
+ if (!this.jsonEnabled())
13
+ this.log(`Removed shared-asset delegation from ${flags.project}`);
14
+ return { undelegated: true, project_id: projectId };
15
+ }
16
+ }
17
+ exports.default = SecretsAssetsUndelegate;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsUpload extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ file: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
6
+ name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ environment: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<unknown>;
12
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promises_1 = require("node:fs/promises");
4
+ const node_path_1 = require("node:path");
5
+ const core_1 = require("@oclif/core");
6
+ const base_1 = require("../../../base");
7
+ class SecretsAssetsUpload extends base_1.BaseCommand {
8
+ static description = 'Encrypt and upload a mobile CI secret file (never prints its contents)';
9
+ static flags = { ...base_1.projectFlag, file: core_1.Flags.string({ required: true }), name: core_1.Flags.string({ required: true }), environment: core_1.Flags.string(), description: core_1.Flags.string() };
10
+ async run() {
11
+ const { flags } = await this.parse(SecretsAssetsUpload);
12
+ const info = await (0, promises_1.stat)(flags.file).catch(() => undefined);
13
+ if (!info?.isFile())
14
+ this.error(`File not found or unreadable: ${flags.file}`, { exit: 2 });
15
+ if (info.size > 10 * 1024 * 1024)
16
+ this.error('Secret file exceeds 10 MiB', { exit: 2 });
17
+ const projectId = await this.resolveProjectId(flags.project);
18
+ const data = await (0, promises_1.readFile)(flags.file);
19
+ const res = await this.api.upload('POST', `/cli/v1/projects/${encodeURIComponent(projectId)}/secret_assets`, [{ field: 'file', filename: (0, node_path_1.basename)(flags.file), data: new Blob([data]) }], { body: { name: flags.name, environment: flags.environment, description: flags.description } });
20
+ if (!this.jsonEnabled())
21
+ this.log(`Encrypted and uploaded ${flags.name}`);
22
+ return res;
23
+ }
24
+ }
25
+ exports.default = SecretsAssetsUpload;
@@ -0,0 +1,10 @@
1
+ import { BaseCommand } from '../../../base';
2
+ export default class SecretsAssetsVersions extends BaseCommand {
3
+ static args: {
4
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ project: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<unknown>;
10
+ }