@flowcore/cli-plugin-iam 1.0.0 → 1.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.1](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.2.0...v1.2.1) (2024-10-22)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **configuration:** :bug: changed from prompt to enquirer import ([172ae77](https://github.com/flowcore-io/cli-plugin-iam/commit/172ae77e0a96f61786f334da1de8d2f388c10463))
9
+
10
+ ## [1.2.0](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.1.0...v1.2.0) (2024-10-22)
11
+
12
+
13
+ ### Features
14
+
15
+ * :sparkles: added delete and updated get for policies and roles ([22fe717](https://github.com/flowcore-io/cli-plugin-iam/commit/22fe71767c39f4a234583ae637d5204c7732900c))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **configuration:** :bug: switched from jsr to npm for obj-diff ([141d75e](https://github.com/flowcore-io/cli-plugin-iam/commit/141d75e1b9efb1c5c851dfbfc466e03c58c8fcfa))
21
+
22
+ ## [1.1.0](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.0.0...v1.1.0) (2024-10-21)
23
+
24
+
25
+ ### Features
26
+
27
+ * :sparkles: added functionality to create and delete iam policies ([0916612](https://github.com/flowcore-io/cli-plugin-iam/commit/09166128f3d1180d019b301eab5ead0af3055dbd))
28
+ * :sparkles: added policy and role bindings to the iam api ([a1815a0](https://github.com/flowcore-io/cli-plugin-iam/commit/a1815a093ad6743b26dd3cf7a4cfd0c32a8b4326))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * :fire: removed console log on create policy ([6289f72](https://github.com/flowcore-io/cli-plugin-iam/commit/6289f72ec7eff9b00fc6a15e928e448ca6403294))
34
+ * :rotating_light: fixed linting errors ([b388ac6](https://github.com/flowcore-io/cli-plugin-iam/commit/b388ac6532d7d5c5c6c7fc1d401218bfbaa75b33))
35
+
3
36
  ## 1.0.0 (2024-09-29)
4
37
 
5
38
 
package/README.md CHANGED
@@ -18,7 +18,7 @@ $ npm install -g @flowcore/cli-plugin-iam
18
18
  $ iam COMMAND
19
19
  running command...
20
20
  $ iam (--version)
21
- @flowcore/cli-plugin-iam/1.0.0 linux-x64 node-v20.17.0
21
+ @flowcore/cli-plugin-iam/1.2.1 linux-x64 node-v20.18.0
22
22
  $ iam --help [COMMAND]
23
23
  USAGE
24
24
  $ iam COMMAND
@@ -27,9 +27,57 @@ USAGE
27
27
  <!-- usagestop -->
28
28
  # Commands
29
29
  <!-- commands -->
30
+ * [`iam delete policy NAME`](#iam-delete-policy-name)
31
+ * [`iam delete role NAME`](#iam-delete-role-name)
30
32
  * [`iam get policy [NAME]`](#iam-get-policy-name)
31
33
  * [`iam get role [NAME]`](#iam-get-role-name)
32
34
 
35
+ ## `iam delete policy NAME`
36
+
37
+ Delete a policy
38
+
39
+ ```
40
+ USAGE
41
+ $ iam delete policy NAME -t <value> [--profile <value>] [-j] [-y]
42
+
43
+ ARGUMENTS
44
+ NAME name
45
+
46
+ FLAGS
47
+ -j, --json json output
48
+ -t, --tenant=<value> (required) tenant
49
+ -y, --yes yes to all
50
+ --profile=<value> Specify the configuration profile to use
51
+
52
+ DESCRIPTION
53
+ Delete a policy
54
+ ```
55
+
56
+ _See code: [src/commands/delete/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.2.1/src/commands/delete/policy.ts)_
57
+
58
+ ## `iam delete role NAME`
59
+
60
+ Delete a role
61
+
62
+ ```
63
+ USAGE
64
+ $ iam delete role NAME -t <value> [--profile <value>] [-j] [-y]
65
+
66
+ ARGUMENTS
67
+ NAME name
68
+
69
+ FLAGS
70
+ -j, --json json output
71
+ -t, --tenant=<value> (required) tenant
72
+ -y, --yes yes to all
73
+ --profile=<value> Specify the configuration profile to use
74
+
75
+ DESCRIPTION
76
+ Delete a role
77
+ ```
78
+
79
+ _See code: [src/commands/delete/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.2.1/src/commands/delete/role.ts)_
80
+
33
81
  ## `iam get policy [NAME]`
34
82
 
35
83
  Get a policy
@@ -51,7 +99,7 @@ DESCRIPTION
51
99
  Get a policy
52
100
  ```
53
101
 
54
- _See code: [src/commands/get/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.0.0/src/commands/get/policy.ts)_
102
+ _See code: [src/commands/get/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.2.1/src/commands/get/policy.ts)_
55
103
 
56
104
  ## `iam get role [NAME]`
57
105
 
@@ -74,5 +122,5 @@ DESCRIPTION
74
122
  Get a role
75
123
  ```
76
124
 
77
- _See code: [src/commands/get/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.0.0/src/commands/get/role.ts)_
125
+ _See code: [src/commands/get/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.2.1/src/commands/get/role.ts)_
78
126
  <!-- commandsstop -->
@@ -0,0 +1,17 @@
1
+ import { BaseCommand } from "@flowcore/cli-plugin-config";
2
+ export declare const DELETE_POLICY_ARGS: {
3
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ };
5
+ export default class DeletePolicy extends BaseCommand<typeof DeletePolicy> {
6
+ static args: {
7
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static description: string;
10
+ static examples: never[];
11
+ static flags: {
12
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ };
16
+ run(): Promise<void>;
17
+ }
@@ -0,0 +1,84 @@
1
+ import { BaseCommand, ValidateLogin } from "@flowcore/cli-plugin-config";
2
+ import { ClientFactory } from "@flowcore/cli-plugin-core";
3
+ import { Args, Flags, ux } from "@oclif/core";
4
+ import enquirer from "enquirer";
5
+ import { tryit } from "radash";
6
+ import { OrganizationService } from "../../services/organization.service.js";
7
+ import { Api as IamApi } from "../../utils/clients/iam/Api.js";
8
+ export const DELETE_POLICY_ARGS = {
9
+ NAME: Args.string({ description: "name", required: true }),
10
+ };
11
+ export default class DeletePolicy extends BaseCommand {
12
+ static args = DELETE_POLICY_ARGS;
13
+ static description = "Delete a policy";
14
+ static examples = [];
15
+ static flags = {
16
+ json: Flags.boolean({
17
+ char: "j",
18
+ description: "json output",
19
+ required: false,
20
+ }),
21
+ tenant: Flags.string({
22
+ char: "t",
23
+ description: "tenant",
24
+ required: true,
25
+ }),
26
+ yes: Flags.boolean({
27
+ char: "y",
28
+ description: "yes to all",
29
+ required: false,
30
+ }),
31
+ };
32
+ async run() {
33
+ const { args, flags } = await this.parse(DeletePolicy);
34
+ const graphqlClient = await ClientFactory.create(this.cliConfiguration, this.logger, flags.json);
35
+ const organizationService = new OrganizationService(graphqlClient);
36
+ const organizations = await organizationService.getMyOrganizations();
37
+ const iamClient = new IamApi();
38
+ const config = this.cliConfiguration.getConfig();
39
+ const login = new ValidateLogin(config.login.url);
40
+ await login.validate(config, this.cliConfiguration, !flags.json);
41
+ const { auth } = config;
42
+ if (!auth?.accessToken) {
43
+ this.logger.fatal("Not logged in, run 'flowcore login'");
44
+ }
45
+ const organization = organizations.me.organizations.find((org) => org.organization.org === flags.tenant);
46
+ if (!organization) {
47
+ this.logger.fatal(`Organization ${flags.tenant} not found, or you are not a member`);
48
+ }
49
+ const [policiesErr, policies] = await tryit(iamClient.getApiV1PolicyAssociationsOrganizationByOrganizationId)(organization.organization.id, {
50
+ headers: {
51
+ Authorization: `Bearer ${auth?.accessToken}`,
52
+ },
53
+ });
54
+ if (policiesErr) {
55
+ this.logger.fatal(`Failed to get policies: ${policiesErr.message}`);
56
+ }
57
+ const policy = policies.data.find((policy) => policy.name === args.NAME);
58
+ if (!policy) {
59
+ this.logger.fatal(`Policy ${args.NAME} not found in tenant: ${flags.tenant}`);
60
+ }
61
+ if (!flags.yes) {
62
+ const { confirm } = await enquirer.prompt([
63
+ {
64
+ message: `Are you sure you want to delete policy ${ux.colorize("cyan", policy.name)} in tenant: ${ux.colorize("cyan", flags.tenant)}?`,
65
+ name: "confirm",
66
+ type: "confirm",
67
+ },
68
+ ]);
69
+ if (!confirm) {
70
+ this.logger.info("Aborted");
71
+ return;
72
+ }
73
+ }
74
+ const [err] = await tryit(iamClient.deleteApiV1PoliciesById)(policy.id, {
75
+ headers: {
76
+ Authorization: `Bearer ${auth?.accessToken}`,
77
+ },
78
+ });
79
+ if (err) {
80
+ this.logger.fatal(`Failed to delete policy: ${err.message}`);
81
+ }
82
+ this.logger.info(`Policy ${policy.name} deleted`);
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ import { BaseCommand } from "@flowcore/cli-plugin-config";
2
+ export declare const DELETE_ROLE_ARGS: {
3
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ };
5
+ export default class DeleteRole extends BaseCommand<typeof DeleteRole> {
6
+ static args: {
7
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static description: string;
10
+ static examples: never[];
11
+ static flags: {
12
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ };
16
+ run(): Promise<void>;
17
+ }
@@ -0,0 +1,84 @@
1
+ import { BaseCommand, ValidateLogin } from "@flowcore/cli-plugin-config";
2
+ import { ClientFactory } from "@flowcore/cli-plugin-core";
3
+ import { Args, Flags, ux } from "@oclif/core";
4
+ import enquirer from "enquirer";
5
+ import { tryit } from "radash";
6
+ import { OrganizationService } from "../../services/organization.service.js";
7
+ import { Api as IamApi } from "../../utils/clients/iam/Api.js";
8
+ export const DELETE_ROLE_ARGS = {
9
+ NAME: Args.string({ description: "name", required: true }),
10
+ };
11
+ export default class DeleteRole extends BaseCommand {
12
+ static args = DELETE_ROLE_ARGS;
13
+ static description = "Delete a role";
14
+ static examples = [];
15
+ static flags = {
16
+ json: Flags.boolean({
17
+ char: "j",
18
+ description: "json output",
19
+ required: false,
20
+ }),
21
+ tenant: Flags.string({
22
+ char: "t",
23
+ description: "tenant",
24
+ required: true,
25
+ }),
26
+ yes: Flags.boolean({
27
+ char: "y",
28
+ description: "yes to all",
29
+ required: false,
30
+ }),
31
+ };
32
+ async run() {
33
+ const { args, flags } = await this.parse(DeleteRole);
34
+ const graphqlClient = await ClientFactory.create(this.cliConfiguration, this.logger, flags.json);
35
+ const organizationService = new OrganizationService(graphqlClient);
36
+ const organizations = await organizationService.getMyOrganizations();
37
+ const iamClient = new IamApi();
38
+ const config = this.cliConfiguration.getConfig();
39
+ const login = new ValidateLogin(config.login.url);
40
+ await login.validate(config, this.cliConfiguration, !flags.json);
41
+ const { auth } = config;
42
+ if (!auth?.accessToken) {
43
+ this.logger.fatal("Not logged in, run 'flowcore login'");
44
+ }
45
+ const organization = organizations.me.organizations.find((org) => org.organization.org === flags.tenant);
46
+ if (!organization) {
47
+ this.logger.fatal(`Organization ${flags.tenant} not found, or you are not a member`);
48
+ }
49
+ const [rolesErr, roles] = await tryit(iamClient.getApiV1RoleAssociationsOrganizationByOrganizationId)(organization.organization.id, {
50
+ headers: {
51
+ Authorization: `Bearer ${auth?.accessToken}`,
52
+ },
53
+ });
54
+ if (rolesErr) {
55
+ this.logger.fatal(`Failed to get roles: ${rolesErr.message}`);
56
+ }
57
+ const role = roles.data.find((role) => role.name === args.NAME);
58
+ if (!role) {
59
+ this.logger.fatal(`Role ${args.NAME} not found in tenant: ${flags.tenant}`);
60
+ }
61
+ if (!flags.yes) {
62
+ const { confirm } = await enquirer.prompt([
63
+ {
64
+ message: `Are you sure you want to delete role ${ux.colorize("cyan", role.name)} in tenant: ${ux.colorize("cyan", flags.tenant)}?`,
65
+ name: "confirm",
66
+ type: "confirm",
67
+ },
68
+ ]);
69
+ if (!confirm) {
70
+ this.logger.info("Aborted");
71
+ return;
72
+ }
73
+ }
74
+ const [err] = await tryit(iamClient.deleteApiV1RolesById)(role.id, {
75
+ headers: {
76
+ Authorization: `Bearer ${auth?.accessToken}`,
77
+ },
78
+ });
79
+ if (err) {
80
+ this.logger.fatal(`Failed to delete role: ${err.message}`);
81
+ }
82
+ this.logger.info(`Role ${role.name} deleted`);
83
+ }
84
+ }
@@ -37,9 +37,7 @@ export default class GetPolicy extends BaseCommand {
37
37
  const graphqlClient = await ClientFactory.create(this.cliConfiguration, this.logger, flags.json);
38
38
  const organizationService = new OrganizationService(graphqlClient);
39
39
  const organizations = await organizationService.getMyOrganizations();
40
- const iamClient = new IamApi({
41
- baseUrl: "https://iam.api.flowcore.io",
42
- });
40
+ const iamClient = new IamApi();
43
41
  const config = this.cliConfiguration.getConfig();
44
42
  const login = new ValidateLogin(config.login.url);
45
43
  await login.validate(config, this.cliConfiguration, !flags.json);
@@ -83,6 +81,7 @@ export default class GetPolicy extends BaseCommand {
83
81
  return {
84
82
  description: policy.description,
85
83
  documents: policy.policyDocuments,
84
+ flowcoreManaged: policy.flowcoreManaged,
86
85
  id: policy.id,
87
86
  name: policy.name,
88
87
  organization: organizationLink,
@@ -127,6 +126,47 @@ export default class GetPolicy extends BaseCommand {
127
126
  documentTable = documentTable.row(row);
128
127
  }
129
128
  documentTable.render();
129
+ this.logger.info("");
130
+ const [associationsErr, associations] = await tryit(iamClient.getApiV1PolicyAssociationsByPolicyId)(policy.id, {
131
+ headers: {
132
+ Authorization: `Bearer ${auth?.accessToken}`,
133
+ },
134
+ });
135
+ if (associationsErr) {
136
+ this.logger.fatal(`Failed to get associations: ${associationsErr.message}`);
137
+ }
138
+ const userAssociationHeaders = ["User ID"];
139
+ const keyAssociationHeaders = ["Key ID"];
140
+ const roleAssociationHeaders = ["Role ID"];
141
+ const userAssociationTable = this.ui
142
+ .table()
143
+ .head(userAssociationHeaders);
144
+ const keyAssociationTable = this.ui.table().head(keyAssociationHeaders);
145
+ const roleAssociationTable = this.ui.table().head(roleAssociationHeaders);
146
+ for (const association of associations.data.keys) {
147
+ keyAssociationTable.row([association.keyId]);
148
+ }
149
+ for (const association of associations.data.users) {
150
+ userAssociationTable.row([association.userId]);
151
+ }
152
+ for (const association of associations.data.roles) {
153
+ roleAssociationTable.row([association.roleId]);
154
+ }
155
+ this.logger.info("");
156
+ this.logger.info("Key Associations:");
157
+ associations.data.keys.length > 0 && !flags.json
158
+ ? keyAssociationTable.render()
159
+ : this.logger.info("No key associations");
160
+ this.logger.info("");
161
+ this.logger.info("User Associations:");
162
+ associations.data.users.length > 0 && !flags.json
163
+ ? userAssociationTable.render()
164
+ : this.logger.info("No user associations");
165
+ this.logger.info("");
166
+ this.logger.info("Role Associations:");
167
+ associations.data.roles.length > 0 && !flags.json
168
+ ? roleAssociationTable.render()
169
+ : this.logger.info("No role associations");
130
170
  }
131
171
  }
132
172
  else if (flags.json) {
@@ -1,7 +1,6 @@
1
1
  import { BaseCommand, ValidateLogin } from "@flowcore/cli-plugin-config";
2
2
  import { ClientFactory } from "@flowcore/cli-plugin-core";
3
3
  import { Args, Flags } from "@oclif/core";
4
- import _ from "lodash";
5
4
  import { tryit } from "radash";
6
5
  import { OrganizationService } from "../../services/organization.service.js";
7
6
  import { Api as IamApi } from "../../utils/clients/iam/Api.js";
@@ -47,55 +46,39 @@ export default class GetRole extends BaseCommand {
47
46
  if (!auth?.accessToken) {
48
47
  this.logger.fatal("Not logged in, run 'flowcore login'");
49
48
  }
50
- const [err, rolesResponse] = await tryit(iamClient.getApiV1Roles)({
51
- headers: {
52
- Authorization: `Bearer ${auth?.accessToken}`,
53
- },
54
- });
55
- if (err) {
56
- this.logger.fatal(`Failed to get roles: ${err.message}`);
57
- }
58
- const roles = rolesResponse.data
59
- .map((role) => {
60
- const organizationLink = organizations.me.organizations.find((organization) => organization.organization.id === role.organizationId);
61
- if (!organizationLink) {
62
- return;
63
- }
64
- return {
65
- description: role.description,
66
- id: role.id,
67
- name: role.name,
68
- organization: organizationLink,
69
- organizationId: role.organizationId,
70
- };
71
- })
72
- .filter((role) => role !== undefined)
73
- .filter((role) => {
74
- if (flags.tenant) {
75
- return role.organization.organization.org === flags.tenant;
76
- }
77
- return true;
78
- });
79
- if (args.NAME) {
80
- const role = roles.find((role) => role.name === args.NAME);
81
- if (!role) {
82
- this.logger.fatal(`Role ${args.NAME} not found`);
49
+ if (flags.tenant) {
50
+ const organization = organizations.me.organizations.find((organization) => flags.tenant ? organization.organization.org === flags.tenant : true);
51
+ if (!organization) {
52
+ this.logger.fatal(`Organization ${flags.tenant} not found, or not accessible`);
83
53
  }
84
- if (flags.json) {
85
- console.log(JSON.stringify(_.omit(role, "organization"), null, 2));
54
+ this.logger.info(`Roles for ${flags.tenant}:`);
55
+ const [err, roles] = await tryit(iamClient.getApiV1RoleAssociationsOrganizationByOrganizationId)(organization.organization.id, {
56
+ headers: {
57
+ Authorization: `Bearer ${auth?.accessToken}`,
58
+ },
59
+ });
60
+ if (err) {
61
+ this.logger.fatal(`Failed to get roles: ${err.message}`);
86
62
  }
87
- else {
88
- this.ui
89
- .sticker()
90
- .add(`Role ${this.ui.colors.green(role.name)}`)
91
- .add("")
92
- .add(`ID: ${this.ui.colors.green(role.id)}`)
93
- .add(`Description: ${this.ui.colors.green(role.description ?? "")}`)
94
- .add(`Organization: ${this.ui.colors.green(role.organization.organization.displayName === "" ? role.organization.organization.org : role.organization.organization.displayName)}`)
95
- .render();
63
+ if (args.NAME && flags.tenant) {
64
+ const role = roles.data.find((role) => role.name === args.NAME);
65
+ if (!role) {
66
+ this.logger.fatal(`Role ${args.NAME} not found`);
67
+ }
68
+ !flags.json &&
69
+ this.ui
70
+ .sticker()
71
+ .add(`Role ${this.ui.colors.green(role.name)}`)
72
+ .add("")
73
+ .add(`ID: ${this.ui.colors.green(role.id)}`)
74
+ .add(`Description: ${this.ui.colors.green(role.description ?? "")}`)
75
+ .add(`Organization: ${this.ui.colors.green(organization.organization.displayName === ""
76
+ ? organization.organization.org
77
+ : organization.organization.displayName)}`)
78
+ .render();
96
79
  this.logger.info("");
97
80
  this.logger.info("Policies:");
98
- const [err, policies] = await tryit(iamClient.getApiV1PolicyAssociationsOrganizationByOrganizationId)(role.organization.organization.id, {
81
+ const [err, policies] = await tryit(iamClient.getApiV1PolicyAssociationsRoleByRoleId)(role.id, {
99
82
  headers: {
100
83
  Authorization: `Bearer ${auth?.accessToken}`,
101
84
  },
@@ -123,35 +106,97 @@ export default class GetRole extends BaseCommand {
123
106
  ];
124
107
  policyTable = policyTable.row(row);
125
108
  }
126
- policyTable.render();
109
+ !flags.json && policyTable.render();
127
110
  this.logger.info("");
111
+ const [associationsErr, associations] = await tryit(iamClient.getApiV1RoleAssociationsByRoleId)(role.id, {
112
+ headers: {
113
+ Authorization: `Bearer ${auth?.accessToken}`,
114
+ },
115
+ });
116
+ if (associationsErr) {
117
+ this.logger.fatal(`Failed to get associations: ${associationsErr.message}`);
118
+ }
119
+ const userAssociationHeaders = ["User ID"];
120
+ const keyAssociationHeaders = ["Key ID"];
121
+ const userAssociationTable = this.ui
122
+ .table()
123
+ .head(userAssociationHeaders);
124
+ const keyAssociationTable = this.ui.table().head(keyAssociationHeaders);
125
+ for (const association of associations.data.keys) {
126
+ keyAssociationTable.row([association.keyId]);
127
+ }
128
+ for (const association of associations.data.users) {
129
+ userAssociationTable.row([association.userId]);
130
+ }
131
+ this.logger.info("");
132
+ this.logger.info("Key Associations:");
133
+ associations.data.keys.length > 0 && !flags.json
134
+ ? keyAssociationTable.render()
135
+ : this.logger.info("No key associations");
136
+ this.logger.info("");
137
+ this.logger.info("User Associations:");
138
+ associations.data.users.length > 0 && !flags.json
139
+ ? userAssociationTable.render()
140
+ : this.logger.info("No user associations");
141
+ if (flags.json) {
142
+ console.log(JSON.stringify({
143
+ associations: associations.data,
144
+ policies: policies.data,
145
+ role: roles.data,
146
+ }, null, 2));
147
+ }
128
148
  }
149
+ else if (!args.NAME && flags.tenant) {
150
+ const roleHeaders = ["Role ID", "Name", "Description"];
151
+ let roleTable = this.ui.table().head(roleHeaders);
152
+ for (const role of roles.data) {
153
+ const row = [role.id, role.name, role.description ?? ""];
154
+ roleTable = roleTable.row(row);
155
+ }
156
+ !flags.json && roleTable.render();
157
+ this.logger.info("");
158
+ if (flags.json) {
159
+ console.log(JSON.stringify({ role: roles.data }, null, 2));
160
+ }
161
+ }
162
+ return;
129
163
  }
130
- else if (flags.json) {
131
- console.log(JSON.stringify(roles.map((role) => _.omit(role, "organization")), null, 2));
164
+ const [err, userRoles] = await tryit(iamClient.getApiV1Roles)({
165
+ headers: {
166
+ Authorization: `Bearer ${auth?.accessToken}`,
167
+ },
168
+ });
169
+ if (err) {
170
+ this.logger.fatal(`Failed to get roles: ${err.message}`);
132
171
  }
133
- else {
134
- const headers = [
135
- "Role ID",
136
- "Name",
137
- "Description",
138
- "Organization Name",
139
- ...(flags.wide ? ["Organization ID"] : []),
140
- ];
141
- let listTable = this.ui.table().head(headers);
142
- for (const role of roles) {
143
- const row = [
144
- role.id,
145
- role.name,
146
- role.description ?? "",
147
- role.organization.organization.displayName === ""
148
- ? role.organization.organization.org
149
- : role.organization.organization.displayName,
150
- ...(flags.wide ? [role.organization.organization.id] : []),
151
- ];
152
- listTable = listTable.row(row);
172
+ console.log(userRoles.data);
173
+ const headers = [
174
+ "Role ID",
175
+ "Name",
176
+ "Description",
177
+ "Organization Name",
178
+ ...(flags.wide ? ["Organization ID"] : []),
179
+ ];
180
+ const listTable = this.ui.table().head(headers);
181
+ for (const role of userRoles.data) {
182
+ const organization = organizations.me.organizations.find((organization) => organization.organization.id === role.organizationId);
183
+ if (!organization) {
184
+ continue;
153
185
  }
154
- listTable.render();
186
+ const row = [
187
+ role.id,
188
+ role.name,
189
+ role.description ?? "",
190
+ organization.organization.displayName === ""
191
+ ? organization.organization.org
192
+ : organization.organization.displayName,
193
+ ...(flags.wide ? [organization.organization.id] : []),
194
+ ];
195
+ listTable.row(row);
196
+ }
197
+ !flags.json && listTable.render();
198
+ if (flags.json) {
199
+ console.log(JSON.stringify({ role: userRoles.data }, null, 2));
155
200
  }
156
201
  }
157
202
  }
@@ -0,0 +1,10 @@
1
+ import type { CliConfiguration, Logger } from "@flowcore/cli-plugin-config";
2
+ import type { Config } from "@oclif/core";
3
+ import { type ApiRegistryService } from "@flowcore/cli-plugin-core";
4
+ declare const hook: (options: {
5
+ apiRegistry: ApiRegistryService;
6
+ cliConfiguration: CliConfiguration;
7
+ config: Config;
8
+ logger: Logger;
9
+ }) => Promise<void>;
10
+ export default hook;
@@ -0,0 +1,9 @@
1
+ import { ClientFactory, } from "@flowcore/cli-plugin-core";
2
+ import { IAMApply } from "../resource-types/iam-api-version.js";
3
+ import { OrganizationService } from "../services/organization.service.js";
4
+ const hook = async (options) => {
5
+ const graphqlClient = await ClientFactory.create(options.cliConfiguration, options.logger, false);
6
+ const organizationService = new OrganizationService(graphqlClient);
7
+ options.apiRegistry.register(new IAMApply(organizationService, options.cliConfiguration, options.logger));
8
+ };
9
+ export default hook;
@@ -0,0 +1,24 @@
1
+ import type { ApiRegistryEntry, BaseResource } from "@flowcore/cli-plugin-core";
2
+ import { type CliConfiguration, type Logger } from "@flowcore/cli-plugin-config";
3
+ import type { OrganizationService } from "../services/organization.service.js";
4
+ export declare class IAMApply implements ApiRegistryEntry {
5
+ private readonly organizationService;
6
+ private readonly cliConfiguration;
7
+ private readonly logger;
8
+ name: string;
9
+ private iamClient;
10
+ private organizations;
11
+ private policyBindingService;
12
+ private policyService;
13
+ private roleBindingService;
14
+ private roleService;
15
+ constructor(organizationService: OrganizationService, cliConfiguration: CliConfiguration, logger: Logger);
16
+ apply(resource: BaseResource, skipConfirmation: boolean): Promise<boolean>;
17
+ calculateApplyOrder(resources: BaseResource[]): BaseResource[];
18
+ delete(resource: BaseResource): Promise<boolean>;
19
+ fetchOrganizationId(tenant: string): Promise<{
20
+ id: string;
21
+ tenant: string;
22
+ } | undefined>;
23
+ getToken(): Promise<string>;
24
+ }