@flowcore/cli-plugin-iam 1.4.0 → 1.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.5.0](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.4.0...v1.5.0) (2025-02-16)
4
+
5
+
6
+ ### Features
7
+
8
+ * add edit policy command to modify policy details interactively ([061e036](https://github.com/flowcore-io/cli-plugin-iam/commit/061e036e07fb076017543b8ed232f9077d615a72))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * :rotating_light: fixed linting errors ([ff60a54](https://github.com/flowcore-io/cli-plugin-iam/commit/ff60a54131d35bfbc7f8b0ca3985e6a6528be8ae))
14
+ * update GitHub Actions runners to use blacksmith infrastructure ([826d577](https://github.com/flowcore-io/cli-plugin-iam/commit/826d577d8145442b1e35b7268a6f7a5482047509))
15
+
3
16
  ## [1.4.0](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.3.1...v1.4.0) (2024-11-08)
4
17
 
5
18
 
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.4.0 linux-x64 node-v22.10.0
21
+ @flowcore/cli-plugin-iam/1.5.0 linux-x64 node-v20.16.0
22
22
  $ iam --help [COMMAND]
23
23
  USAGE
24
24
  $ iam COMMAND
@@ -29,6 +29,7 @@ USAGE
29
29
  <!-- commands -->
30
30
  * [`iam delete policy NAME`](#iam-delete-policy-name)
31
31
  * [`iam delete role NAME`](#iam-delete-role-name)
32
+ * [`iam edit policy NAME`](#iam-edit-policy-name)
32
33
  * [`iam get policy [NAME]`](#iam-get-policy-name)
33
34
  * [`iam get role [NAME]`](#iam-get-role-name)
34
35
 
@@ -53,7 +54,7 @@ DESCRIPTION
53
54
  Delete a policy
54
55
  ```
55
56
 
56
- _See code: [src/commands/delete/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.4.0/src/commands/delete/policy.ts)_
57
+ _See code: [src/commands/delete/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.5.0/src/commands/delete/policy.ts)_
57
58
 
58
59
  ## `iam delete role NAME`
59
60
 
@@ -76,7 +77,33 @@ DESCRIPTION
76
77
  Delete a role
77
78
  ```
78
79
 
79
- _See code: [src/commands/delete/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.4.0/src/commands/delete/role.ts)_
80
+ _See code: [src/commands/delete/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.5.0/src/commands/delete/role.ts)_
81
+
82
+ ## `iam edit policy NAME`
83
+
84
+ Edit a policy in your preferred editor
85
+
86
+ ```
87
+ USAGE
88
+ $ iam edit policy NAME -t <value> [--profile <value>]
89
+
90
+ ARGUMENTS
91
+ NAME name
92
+
93
+ FLAGS
94
+ -t, --tenant=<value> (required) tenant
95
+ --profile=<value> Specify the configuration profile to use
96
+
97
+ DESCRIPTION
98
+ Edit a policy in your preferred editor
99
+
100
+ EXAMPLES
101
+ $ flowcore iam edit policy my-policy -t my-tenant
102
+
103
+ $ FC_EDITOR=code flowcore iam edit policy my-policy -t my-tenant
104
+ ```
105
+
106
+ _See code: [src/commands/edit/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.5.0/src/commands/edit/policy.ts)_
80
107
 
81
108
  ## `iam get policy [NAME]`
82
109
 
@@ -99,7 +126,7 @@ DESCRIPTION
99
126
  Get a policy
100
127
  ```
101
128
 
102
- _See code: [src/commands/get/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.4.0/src/commands/get/policy.ts)_
129
+ _See code: [src/commands/get/policy.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.5.0/src/commands/get/policy.ts)_
103
130
 
104
131
  ## `iam get role [NAME]`
105
132
 
@@ -122,5 +149,5 @@ DESCRIPTION
122
149
  Get a role
123
150
  ```
124
151
 
125
- _See code: [src/commands/get/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.4.0/src/commands/get/role.ts)_
152
+ _See code: [src/commands/get/role.ts](https://github.com/flowcore-io/cli-plugin-iam/blob/v1.5.0/src/commands/get/role.ts)_
126
153
  <!-- commandsstop -->
@@ -0,0 +1,16 @@
1
+ import { BaseCommand } from "@flowcore/cli-plugin-config";
2
+ export declare const EDIT_POLICY_ARGS: {
3
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ };
5
+ export default class EditPolicy extends BaseCommand<typeof EditPolicy> {
6
+ static args: {
7
+ NAME: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<void>;
15
+ private spawnEditor;
16
+ }
@@ -0,0 +1,118 @@
1
+ import { BaseCommand, ValidateLogin } from "@flowcore/cli-plugin-config";
2
+ import { ClientFactory } from "@flowcore/cli-plugin-core";
3
+ import { Args, Flags } from "@oclif/core";
4
+ import { spawn } from "node:child_process";
5
+ import { unlink, writeFile } from "node:fs/promises";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { tryit } from "radash";
9
+ import { v4 as uuidv4 } from "uuid";
10
+ import { OrganizationService } from "../../services/organization.service.js";
11
+ import { Api as IamApi } from "../../utils/clients/iam/Api.js";
12
+ export const EDIT_POLICY_ARGS = {
13
+ NAME: Args.string({ description: "name", required: true }),
14
+ };
15
+ export default class EditPolicy extends BaseCommand {
16
+ static args = EDIT_POLICY_ARGS;
17
+ static description = "Edit a policy in your preferred editor";
18
+ static examples = [
19
+ "$ flowcore iam edit policy my-policy -t my-tenant",
20
+ "$ FC_EDITOR=code flowcore iam edit policy my-policy -t my-tenant",
21
+ ];
22
+ static flags = {
23
+ tenant: Flags.string({
24
+ char: "t",
25
+ description: "tenant",
26
+ required: true,
27
+ }),
28
+ };
29
+ async run() {
30
+ const { args, flags } = await this.parse(EditPolicy);
31
+ const graphqlClient = await ClientFactory.create(this.cliConfiguration, this.logger);
32
+ const organizationService = new OrganizationService(graphqlClient);
33
+ const organizations = await organizationService.getMyOrganizations();
34
+ const iamClient = new IamApi();
35
+ const config = this.cliConfiguration.getConfig();
36
+ const login = new ValidateLogin(config.login.url);
37
+ await login.validate(config, this.cliConfiguration, true);
38
+ const { auth } = config;
39
+ if (!auth?.accessToken) {
40
+ this.logger.fatal("Not logged in, run 'flowcore login'");
41
+ }
42
+ const organization = organizations.me.organizations.find((org) => org.organization.org === flags.tenant);
43
+ if (!organization) {
44
+ this.logger.fatal(`Organization ${flags.tenant} not found, or you are not a member`);
45
+ }
46
+ const [policiesErr, policies] = await tryit(iamClient.getApiV1PolicyAssociationsOrganizationByOrganizationId)(organization.organization.id, {
47
+ headers: {
48
+ Authorization: `Bearer ${auth?.accessToken}`,
49
+ },
50
+ });
51
+ if (policiesErr) {
52
+ this.logger.fatal(`Failed to get policies: ${policiesErr.message}`);
53
+ }
54
+ const policy = policies.data.find((policy) => policy.name === args.NAME);
55
+ if (!policy) {
56
+ this.logger.fatal(`Policy ${args.NAME} not found in tenant: ${flags.tenant}`);
57
+ }
58
+ // Create a temporary file with the policy content
59
+ const tmpFile = join(tmpdir(), `policy-${uuidv4()}.json`);
60
+ const policyContent = JSON.stringify({
61
+ description: policy.description,
62
+ documents: policy.policyDocuments,
63
+ name: policy.name,
64
+ version: policy.version,
65
+ }, null, 2);
66
+ try {
67
+ await writeFile(tmpFile, policyContent, "utf8");
68
+ await this.spawnEditor(tmpFile);
69
+ // Read and parse the edited content
70
+ const editedContent = await import(tmpFile, {
71
+ assert: { type: "json" },
72
+ });
73
+ // Update the policy
74
+ const [updateErr] = await tryit(iamClient.patchApiV1PoliciesById)(policy.id, {
75
+ description: editedContent.default.description,
76
+ name: editedContent.default.name,
77
+ organizationId: organization.organization.id,
78
+ policyDocuments: editedContent.default.documents,
79
+ version: editedContent.default.version,
80
+ }, {
81
+ headers: {
82
+ Authorization: `Bearer ${auth?.accessToken}`,
83
+ },
84
+ });
85
+ if (updateErr) {
86
+ this.logger.fatal(`Failed to update policy: ${updateErr.message}`);
87
+ }
88
+ this.logger.info(`Policy ${policy.name} updated successfully`);
89
+ }
90
+ catch (error) {
91
+ this.logger.fatal(`Error editing policy: ${error}`);
92
+ }
93
+ finally {
94
+ await unlink(tmpFile).catch(() => {
95
+ // Ignore error if file doesn't exist
96
+ });
97
+ }
98
+ }
99
+ async spawnEditor(filePath) {
100
+ return new Promise((resolve, reject) => {
101
+ const editor = process.env.FC_EDITOR || process.env.EDITOR || "vim";
102
+ const child = spawn(editor, [filePath], {
103
+ stdio: "inherit",
104
+ });
105
+ child.on("exit", (code) => {
106
+ if (code === 0) {
107
+ resolve();
108
+ }
109
+ else {
110
+ reject(new Error(`Editor process exited with code ${code}`));
111
+ }
112
+ });
113
+ child.on("error", (err) => {
114
+ reject(err);
115
+ });
116
+ });
117
+ }
118
+ }
@@ -122,7 +122,7 @@ export default class GetPolicy extends BaseCommand {
122
122
  const row = [
123
123
  document.statementId,
124
124
  document.resource,
125
- document.action,
125
+ String(document.action),
126
126
  ];
127
127
  documentTable = documentTable.row(row);
128
128
  }
@@ -143,7 +143,9 @@ export default class GetPolicy extends BaseCommand {
143
143
  .table()
144
144
  .head(userAssociationHeaders);
145
145
  const keyAssociationTable = this.ui.table().head(keyAssociationHeaders);
146
- const roleAssociationTable = this.ui.table().head(roleAssociationHeaders);
146
+ const roleAssociationTable = this.ui
147
+ .table()
148
+ .head(roleAssociationHeaders);
147
149
  for (const association of associations.data.keys) {
148
150
  keyAssociationTable.row([association.keyId]);
149
151
  }
@@ -243,7 +243,55 @@
243
243
  "get",
244
244
  "role.js"
245
245
  ]
246
+ },
247
+ "edit:policy": {
248
+ "aliases": [],
249
+ "args": {
250
+ "NAME": {
251
+ "description": "name",
252
+ "name": "NAME",
253
+ "required": true
254
+ }
255
+ },
256
+ "description": "Edit a policy in your preferred editor",
257
+ "examples": [
258
+ "$ flowcore iam edit policy my-policy -t my-tenant",
259
+ "$ FC_EDITOR=code flowcore iam edit policy my-policy -t my-tenant"
260
+ ],
261
+ "flags": {
262
+ "profile": {
263
+ "description": "Specify the configuration profile to use",
264
+ "name": "profile",
265
+ "hasDynamicHelp": false,
266
+ "multiple": false,
267
+ "type": "option"
268
+ },
269
+ "tenant": {
270
+ "char": "t",
271
+ "description": "tenant",
272
+ "name": "tenant",
273
+ "required": true,
274
+ "hasDynamicHelp": false,
275
+ "multiple": false,
276
+ "type": "option"
277
+ }
278
+ },
279
+ "hasDynamicHelp": false,
280
+ "hiddenAliases": [],
281
+ "id": "edit:policy",
282
+ "pluginAlias": "@flowcore/cli-plugin-iam",
283
+ "pluginName": "@flowcore/cli-plugin-iam",
284
+ "pluginType": "core",
285
+ "strict": true,
286
+ "enableJsonFlag": false,
287
+ "isESM": true,
288
+ "relativePath": [
289
+ "dist",
290
+ "commands",
291
+ "edit",
292
+ "policy.js"
293
+ ]
246
294
  }
247
295
  },
248
- "version": "1.4.0"
296
+ "version": "1.5.0"
249
297
  }
package/package.json CHANGED
@@ -91,7 +91,7 @@
91
91
  "version": "oclif readme && git add README.md",
92
92
  "update-schema": "rover graph introspect https://graph.api.flowcore.io/graphql -o schema.gql"
93
93
  },
94
- "version": "1.4.0",
94
+ "version": "1.5.0",
95
95
  "bugs": "https://github.com/flowcore-io/cli-plugin-iam/issues",
96
96
  "keywords": [
97
97
  "oclif"