@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 +13 -0
- package/README.md +32 -5
- package/dist/commands/edit/policy.d.ts +16 -0
- package/dist/commands/edit/policy.js +118 -0
- package/dist/commands/get/policy.js +4 -2
- package/oclif.manifest.json +49 -1
- package/package.json +1 -1
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
}
|
package/oclif.manifest.json
CHANGED
|
@@ -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.
|
|
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.
|
|
94
|
+
"version": "1.5.0",
|
|
95
95
|
"bugs": "https://github.com/flowcore-io/cli-plugin-iam/issues",
|
|
96
96
|
"keywords": [
|
|
97
97
|
"oclif"
|