@flowcore/cli-plugin-iam 1.3.1 → 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 +25 -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 +5 -2
- package/dist/commands/get/role.js +1 -0
- package/dist/utils/clients/iam/Api.d.ts +757 -189
- package/dist/utils/clients/iam/Api.js +717 -189
- package/dist/utils/clients/iam/Health.d.ts +1 -0
- package/dist/utils/clients/iam/Health.js +1 -0
- package/dist/utils/clients/iam/Transformers.d.ts +92 -28
- package/dist/utils/clients/iam/Transformers.js +92 -28
- package/dist/utils/clients/iam/http-client.d.ts +2 -2
- package/dist/utils/clients/iam/http-client.js +18 -6
- package/oclif.manifest.json +49 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
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
|
+
|
|
16
|
+
## [1.4.0](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.3.1...v1.4.0) (2024-11-08)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* :sparkles: added frn to role and policy display ([9cb9140](https://github.com/flowcore-io/cli-plugin-iam/commit/9cb9140242aaecdedc669cde48c1611ed53610ac))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
* :rotating_light: fixed linting errors ([7e5249e](https://github.com/flowcore-io/cli-plugin-iam/commit/7e5249e90c075b60a71c996184bb7a7fc9465bf6))
|
|
27
|
+
|
|
3
28
|
## [1.3.1](https://github.com/flowcore-io/cli-plugin-iam/compare/v1.3.0...v1.3.1) (2024-10-23)
|
|
4
29
|
|
|
5
30
|
|
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
|
+
}
|
|
@@ -104,6 +104,7 @@ export default class GetPolicy extends BaseCommand {
|
|
|
104
104
|
.sticker()
|
|
105
105
|
.add(`Policy ${this.ui.colors.green(policy.name)}`)
|
|
106
106
|
.add("")
|
|
107
|
+
.add(`Frn: ${this.ui.colors.green(`frn::${policy.organization.organization.org}:policy/${policy.id}`)}`)
|
|
107
108
|
.add(`ID: ${this.ui.colors.green(policy.id)}`)
|
|
108
109
|
.add(`Description: ${this.ui.colors.green(policy.description ?? "")}`)
|
|
109
110
|
.add(`Organization: ${this.ui.colors.green(policy.organization.organization.displayName === "" ? policy.organization.organization.org : policy.organization.organization.displayName)}`)
|
|
@@ -121,7 +122,7 @@ export default class GetPolicy extends BaseCommand {
|
|
|
121
122
|
const row = [
|
|
122
123
|
document.statementId,
|
|
123
124
|
document.resource,
|
|
124
|
-
document.action,
|
|
125
|
+
String(document.action),
|
|
125
126
|
];
|
|
126
127
|
documentTable = documentTable.row(row);
|
|
127
128
|
}
|
|
@@ -142,7 +143,9 @@ export default class GetPolicy extends BaseCommand {
|
|
|
142
143
|
.table()
|
|
143
144
|
.head(userAssociationHeaders);
|
|
144
145
|
const keyAssociationTable = this.ui.table().head(keyAssociationHeaders);
|
|
145
|
-
const roleAssociationTable = this.ui
|
|
146
|
+
const roleAssociationTable = this.ui
|
|
147
|
+
.table()
|
|
148
|
+
.head(roleAssociationHeaders);
|
|
146
149
|
for (const association of associations.data.keys) {
|
|
147
150
|
keyAssociationTable.row([association.keyId]);
|
|
148
151
|
}
|
|
@@ -70,6 +70,7 @@ export default class GetRole extends BaseCommand {
|
|
|
70
70
|
.sticker()
|
|
71
71
|
.add(`Role ${this.ui.colors.green(role.name)}`)
|
|
72
72
|
.add("")
|
|
73
|
+
.add(`Frn: ${this.ui.colors.green(`frn::${organization.organization.org}:role/${role.id}`)}`)
|
|
73
74
|
.add(`ID: ${this.ui.colors.green(role.id)}`)
|
|
74
75
|
.add(`Description: ${this.ui.colors.green(role.description ?? "")}`)
|
|
75
76
|
.add(`Organization: ${this.ui.colors.green(organization.organization.displayName === ""
|