opal-security 3.1.1-beta.7cc0a74 → 3.1.1-beta.7e1cc21
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/README.md +114 -18
- package/lib/commands/login.js +6 -2
- package/lib/commands/request/create.d.ts +1 -2
- package/lib/commands/request/create.js +18 -13
- package/lib/commands/request/get.d.ts +0 -1
- package/lib/commands/request/get.js +1 -4
- package/lib/commands/request/list.d.ts +0 -1
- package/lib/commands/request/list.js +0 -3
- package/lib/commands/whoami.d.ts +8 -0
- package/lib/commands/whoami.js +34 -0
- package/lib/lib/apollo.js +3 -4
- package/lib/lib/credentials/index.d.ts +2 -1
- package/lib/lib/credentials/index.js +2 -1
- package/lib/lib/requests.d.ts +5 -3
- package/lib/lib/requests.js +76 -69
- package/lib/utils/displays.d.ts +1 -1
- package/lib/utils/displays.js +2 -1
- package/oclif.manifest.json +62 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ $ npm install -g opal-security
|
|
|
22
22
|
$ opal COMMAND
|
|
23
23
|
running command...
|
|
24
24
|
$ opal (--version)
|
|
25
|
-
opal-security/3.1.1-beta.
|
|
25
|
+
opal-security/3.1.1-beta.7e1cc21 linux-x64 node-v20.19.2
|
|
26
26
|
$ opal --help [COMMAND]
|
|
27
27
|
USAGE
|
|
28
28
|
$ opal COMMAND
|
|
@@ -44,6 +44,9 @@ USAGE
|
|
|
44
44
|
* [`opal login`](#opal-login)
|
|
45
45
|
* [`opal logout`](#opal-logout)
|
|
46
46
|
* [`opal postgres-instances start`](#opal-postgres-instances-start)
|
|
47
|
+
* [`opal request create`](#opal-request-create)
|
|
48
|
+
* [`opal request get`](#opal-request-get)
|
|
49
|
+
* [`opal request list`](#opal-request-list)
|
|
47
50
|
* [`opal resources get`](#opal-resources-get)
|
|
48
51
|
* [`opal set-auth-provider`](#opal-set-auth-provider)
|
|
49
52
|
* [`opal set-custom-header`](#opal-set-custom-header)
|
|
@@ -53,6 +56,7 @@ USAGE
|
|
|
53
56
|
* [`opal ssh copyTo`](#opal-ssh-copyto)
|
|
54
57
|
* [`opal ssh start`](#opal-ssh-start)
|
|
55
58
|
* [`opal version`](#opal-version)
|
|
59
|
+
* [`opal whoami`](#opal-whoami)
|
|
56
60
|
|
|
57
61
|
## `opal autocomplete [SHELL]`
|
|
58
62
|
|
|
@@ -101,7 +105,7 @@ EXAMPLES
|
|
|
101
105
|
$ opal aws:identity
|
|
102
106
|
```
|
|
103
107
|
|
|
104
|
-
_See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
108
|
+
_See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/aws/identity.ts)_
|
|
105
109
|
|
|
106
110
|
## `opal clear-auth-provider`
|
|
107
111
|
|
|
@@ -121,7 +125,7 @@ EXAMPLES
|
|
|
121
125
|
$ opal clear-auth-provider
|
|
122
126
|
```
|
|
123
127
|
|
|
124
|
-
_See code: [src/commands/clear-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
128
|
+
_See code: [src/commands/clear-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/clear-auth-provider.ts)_
|
|
125
129
|
|
|
126
130
|
## `opal curl-example`
|
|
127
131
|
|
|
@@ -138,7 +142,7 @@ DESCRIPTION
|
|
|
138
142
|
Prints out an example cURL command containing the parameters the CLI uses to query the Opal server.
|
|
139
143
|
```
|
|
140
144
|
|
|
141
|
-
_See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
145
|
+
_See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/curl-example.ts)_
|
|
142
146
|
|
|
143
147
|
## `opal groups get`
|
|
144
148
|
|
|
@@ -159,7 +163,7 @@ EXAMPLES
|
|
|
159
163
|
$ opal groups:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
|
|
160
164
|
```
|
|
161
165
|
|
|
162
|
-
_See code: [src/commands/groups/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
166
|
+
_See code: [src/commands/groups/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/groups/get.ts)_
|
|
163
167
|
|
|
164
168
|
## `opal help [COMMANDS]`
|
|
165
169
|
|
|
@@ -209,7 +213,7 @@ EXAMPLES
|
|
|
209
213
|
$ opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName "custom-profile"
|
|
210
214
|
```
|
|
211
215
|
|
|
212
|
-
_See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
216
|
+
_See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/iam-roles/start.ts)_
|
|
213
217
|
|
|
214
218
|
## `opal kube-roles start`
|
|
215
219
|
|
|
@@ -240,7 +244,7 @@ EXAMPLES
|
|
|
240
244
|
$ opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId "arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role"
|
|
241
245
|
```
|
|
242
246
|
|
|
243
|
-
_See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
247
|
+
_See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/kube-roles/start.ts)_
|
|
244
248
|
|
|
245
249
|
## `opal login`
|
|
246
250
|
|
|
@@ -261,7 +265,7 @@ EXAMPLES
|
|
|
261
265
|
$ opal login
|
|
262
266
|
```
|
|
263
267
|
|
|
264
|
-
_See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
268
|
+
_See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/login.ts)_
|
|
265
269
|
|
|
266
270
|
## `opal logout`
|
|
267
271
|
|
|
@@ -281,7 +285,7 @@ EXAMPLES
|
|
|
281
285
|
$ opal logout
|
|
282
286
|
```
|
|
283
287
|
|
|
284
|
-
_See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
288
|
+
_See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/logout.ts)_
|
|
285
289
|
|
|
286
290
|
## `opal postgres-instances start`
|
|
287
291
|
|
|
@@ -318,7 +322,82 @@ EXAMPLES
|
|
|
318
322
|
$ opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view
|
|
319
323
|
```
|
|
320
324
|
|
|
321
|
-
_See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
325
|
+
_See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/postgres-instances/start.ts)_
|
|
326
|
+
|
|
327
|
+
## `opal request create`
|
|
328
|
+
|
|
329
|
+
Creates an Opal access request via an interactive form
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
USAGE
|
|
333
|
+
$ opal request create [-h] [-a <value>...] [-r <value>] [-d <value>]
|
|
334
|
+
|
|
335
|
+
FLAGS
|
|
336
|
+
-a, --assets=<value>... The ids of the assets (resource, group) to request access to. Append a role ID using a colon
|
|
337
|
+
if needed, e.g. `--assets 123:456`.
|
|
338
|
+
If not provided, an interactive selection flow will be available to select assets to request.
|
|
339
|
+
-d, --duration=<value> The duration of access for the request in minutes. If not provided, you will be prompted.
|
|
340
|
+
-h, --help Show CLI help.
|
|
341
|
+
-r, --reason=<value> The reason for the request, contained in quotes. If not provided, you will be prompted.
|
|
342
|
+
|
|
343
|
+
DESCRIPTION
|
|
344
|
+
Creates an Opal access request via an interactive form
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
_See code: [src/commands/request/create.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/request/create.ts)_
|
|
348
|
+
|
|
349
|
+
## `opal request get`
|
|
350
|
+
|
|
351
|
+
Lists access requests
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
USAGE
|
|
355
|
+
$ opal request get [-h] [-i <value>] [-v]
|
|
356
|
+
|
|
357
|
+
FLAGS
|
|
358
|
+
-h, --help Show CLI help.
|
|
359
|
+
-i, --id=<value> The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]
|
|
360
|
+
-v, --verbose Enable verbose output, prints full response in JSON format. Defaults to false.
|
|
361
|
+
|
|
362
|
+
DESCRIPTION
|
|
363
|
+
Lists access requests
|
|
364
|
+
|
|
365
|
+
EXAMPLES
|
|
366
|
+
$ opal request get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
|
|
367
|
+
|
|
368
|
+
$ opal request get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4 --verbose
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
_See code: [src/commands/request/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/request/get.ts)_
|
|
372
|
+
|
|
373
|
+
## `opal request list`
|
|
374
|
+
|
|
375
|
+
Lists your n recent outgoing access requests
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
USAGE
|
|
379
|
+
$ opal request list [-h] [-n <value>] [-p] [-v]
|
|
380
|
+
|
|
381
|
+
FLAGS
|
|
382
|
+
-h, --help Show CLI help.
|
|
383
|
+
-n, --n=<value> [default: 10] Defines number of requests to be returned. 1 <= n <= 100.
|
|
384
|
+
-p, --pending Show only pending requests. Defaults to false.
|
|
385
|
+
-v, --verbose Enable verbose output, prints full response in JSON format. Defaults to false.
|
|
386
|
+
|
|
387
|
+
DESCRIPTION
|
|
388
|
+
Lists your n recent outgoing access requests
|
|
389
|
+
|
|
390
|
+
EXAMPLES
|
|
391
|
+
$ opal request list --n 5
|
|
392
|
+
|
|
393
|
+
$ opal request list --n 5 --pending
|
|
394
|
+
|
|
395
|
+
$ opal request list --n 5 --verbose
|
|
396
|
+
|
|
397
|
+
$ opal request list --n 5 --pending --verbose
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
_See code: [src/commands/request/list.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/request/list.ts)_
|
|
322
401
|
|
|
323
402
|
## `opal resources get`
|
|
324
403
|
|
|
@@ -339,7 +418,7 @@ EXAMPLES
|
|
|
339
418
|
$ opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
|
|
340
419
|
```
|
|
341
420
|
|
|
342
|
-
_See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
421
|
+
_See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/resources/get.ts)_
|
|
343
422
|
|
|
344
423
|
## `opal set-auth-provider`
|
|
345
424
|
|
|
@@ -365,7 +444,7 @@ EXAMPLES
|
|
|
365
444
|
$ opal set-auth-provider --clientID 1234asdf --issuerUrl https://auth.example.com
|
|
366
445
|
```
|
|
367
446
|
|
|
368
|
-
_See code: [src/commands/set-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
447
|
+
_See code: [src/commands/set-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/set-auth-provider.ts)_
|
|
369
448
|
|
|
370
449
|
## `opal set-custom-header`
|
|
371
450
|
|
|
@@ -386,7 +465,7 @@ EXAMPLES
|
|
|
386
465
|
$ opal set-custom-header --header 'cf-access-token: $TOKEN'
|
|
387
466
|
```
|
|
388
467
|
|
|
389
|
-
_See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
468
|
+
_See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/set-custom-header.ts)_
|
|
390
469
|
|
|
391
470
|
## `opal set-token`
|
|
392
471
|
|
|
@@ -406,7 +485,7 @@ EXAMPLES
|
|
|
406
485
|
$ opal set-token
|
|
407
486
|
```
|
|
408
487
|
|
|
409
|
-
_See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
488
|
+
_See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/set-token.ts)_
|
|
410
489
|
|
|
411
490
|
## `opal set-url [URL]`
|
|
412
491
|
|
|
@@ -430,7 +509,7 @@ EXAMPLES
|
|
|
430
509
|
$ opal set-url
|
|
431
510
|
```
|
|
432
511
|
|
|
433
|
-
_See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
512
|
+
_See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/set-url.ts)_
|
|
434
513
|
|
|
435
514
|
## `opal ssh copyFrom`
|
|
436
515
|
|
|
@@ -461,7 +540,7 @@ EXAMPLES
|
|
|
461
540
|
$ opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
462
541
|
```
|
|
463
542
|
|
|
464
|
-
_See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
543
|
+
_See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/ssh/copyFrom.ts)_
|
|
465
544
|
|
|
466
545
|
## `opal ssh copyTo`
|
|
467
546
|
|
|
@@ -492,7 +571,7 @@ EXAMPLES
|
|
|
492
571
|
$ opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
493
572
|
```
|
|
494
573
|
|
|
495
|
-
_See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
574
|
+
_See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/ssh/copyTo.ts)_
|
|
496
575
|
|
|
497
576
|
## `opal ssh start`
|
|
498
577
|
|
|
@@ -519,7 +598,7 @@ EXAMPLES
|
|
|
519
598
|
$ opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
520
599
|
```
|
|
521
600
|
|
|
522
|
-
_See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
601
|
+
_See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/ssh/start.ts)_
|
|
523
602
|
|
|
524
603
|
## `opal version`
|
|
525
604
|
|
|
@@ -540,4 +619,21 @@ FLAG DESCRIPTIONS
|
|
|
540
619
|
```
|
|
541
620
|
|
|
542
621
|
_See code: [@oclif/plugin-version](https://github.com/oclif/plugin-version/blob/v2.2.27/src/commands/version.ts)_
|
|
622
|
+
|
|
623
|
+
## `opal whoami`
|
|
624
|
+
|
|
625
|
+
Describes current url set, organization name, and logged in user if applicabled.
|
|
626
|
+
|
|
627
|
+
```
|
|
628
|
+
USAGE
|
|
629
|
+
$ opal whoami [-h]
|
|
630
|
+
|
|
631
|
+
FLAGS
|
|
632
|
+
-h, --help Show CLI help.
|
|
633
|
+
|
|
634
|
+
DESCRIPTION
|
|
635
|
+
Describes current url set, organization name, and logged in user if applicabled.
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
_See code: [src/commands/whoami.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.7e1cc21/src/commands/whoami.ts)_
|
|
543
639
|
<!-- commandsstop -->
|
package/lib/commands/login.js
CHANGED
|
@@ -88,12 +88,14 @@ class Login extends core_1.Command {
|
|
|
88
88
|
const configData = (0, config_1.getOrCreateConfigData)(configDir);
|
|
89
89
|
let email = flags.email;
|
|
90
90
|
let organizationId;
|
|
91
|
+
let organizationName;
|
|
91
92
|
let clientIDCandidate;
|
|
92
93
|
const existingCreds = await (0, credentials_1.getOpalCredentials)(this, false);
|
|
93
94
|
// Only use the previous email + organizationID if email isn't explicitly specified.
|
|
94
95
|
if (!email) {
|
|
95
96
|
email = existingCreds.email;
|
|
96
97
|
organizationId = existingCreds.organizationID;
|
|
98
|
+
organizationName = existingCreds.organizationName;
|
|
97
99
|
clientIDCandidate = existingCreds.clientIDCandidate;
|
|
98
100
|
}
|
|
99
101
|
await (0, credentials_1.removeOpalCredentials)(this);
|
|
@@ -149,6 +151,7 @@ class Login extends core_1.Command {
|
|
|
149
151
|
if (signInOrganizations && signInOrganizations.length > 0) {
|
|
150
152
|
if (signInOrganizations.length === 1) {
|
|
151
153
|
organizationId = signInOrganizations[0].organizationId;
|
|
154
|
+
organizationName = signInOrganizations[0].organizationName;
|
|
152
155
|
clientIDCandidate = signInOrganizations[0].cliClientId;
|
|
153
156
|
}
|
|
154
157
|
else {
|
|
@@ -164,6 +167,7 @@ class Login extends core_1.Command {
|
|
|
164
167
|
},
|
|
165
168
|
]);
|
|
166
169
|
organizationId = responses.signInOrganization.organizationId;
|
|
170
|
+
organizationName = responses.signInOrganization.organizationName;
|
|
167
171
|
clientIDCandidate = responses.signInOrganization.cliClientId;
|
|
168
172
|
}
|
|
169
173
|
}
|
|
@@ -238,10 +242,10 @@ class Login extends core_1.Command {
|
|
|
238
242
|
if (tokenExchangeError) {
|
|
239
243
|
this.log("WARN: Failed to exchange access token for session in Opal. Falling back to using access token for authenticating requests\n");
|
|
240
244
|
// TODO: consider adding a warn line recommending upgrading Opal to version XYZ, once accompanying PR is pushed to prod
|
|
241
|
-
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || "", credentials_1.SecretType.ApiToken);
|
|
245
|
+
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || "", credentials_1.SecretType.ApiToken, organizationName);
|
|
242
246
|
}
|
|
243
247
|
else {
|
|
244
|
-
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, apollo_1.cookieStr, credentials_1.SecretType.Cookie);
|
|
248
|
+
await (0, credentials_1.setOpalCredentials)(this, email, organizationId !== null && organizationId !== void 0 ? organizationId : "", clientIDCandidate, apollo_1.cookieStr, credentials_1.SecretType.Cookie, organizationName);
|
|
245
249
|
}
|
|
246
250
|
// "Representative" authenticated call to check the log-in worked as expected.
|
|
247
251
|
const { resp: authCheckResp, error: authCheckErr } = await (0, handler_1.runQueryDeprecated)({
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Command } from "@oclif/core";
|
|
2
2
|
export default class RequestCreate extends Command {
|
|
3
|
-
static hidden: boolean;
|
|
4
3
|
static description: string;
|
|
5
4
|
static flags: {
|
|
6
5
|
help: import("@oclif/core/lib/interfaces").BooleanFlag<void>;
|
|
7
|
-
|
|
6
|
+
assets: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
7
|
reason: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
8
|
duration: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
9
|
};
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const apollo_1 = require("../../lib/apollo");
|
|
5
|
+
const cmd_1 = require("../../lib/cmd");
|
|
5
6
|
const flags_1 = require("../../lib/flags");
|
|
6
7
|
const requests_1 = require("../../lib/requests");
|
|
7
8
|
const displays_1 = require("../../utils/displays");
|
|
8
|
-
const utils_1 = require("../../utils/utils");
|
|
9
9
|
class RequestCreate extends core_1.Command {
|
|
10
10
|
async run() {
|
|
11
|
+
(0, cmd_1.setMostRecentCommand)(this);
|
|
11
12
|
await (0, apollo_1.initClient)(this, true);
|
|
12
13
|
const client = await (0, apollo_1.getClient)(this, true);
|
|
13
|
-
(0, utils_1.restrictToDev)(); //TODO: Remove after development is complete
|
|
14
14
|
const { flags } = await this.parse(RequestCreate);
|
|
15
15
|
const metadata = (0, requests_1.initEmptyRequestMetadata)();
|
|
16
|
-
if (flags.
|
|
16
|
+
if (flags.assets) {
|
|
17
17
|
// if IDs are provided, bypass the interactive selection process
|
|
18
|
-
(0, requests_1.bypassRequestSelection)(this, client, flags.
|
|
18
|
+
await (0, requests_1.bypassRequestSelection)(this, client, flags.assets, metadata);
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
21
|
(0, displays_1.headerMessage)(this);
|
|
@@ -36,7 +36,9 @@ class RequestCreate extends core_1.Command {
|
|
|
36
36
|
if (flags.reason) {
|
|
37
37
|
metadata.reason = flags.reason;
|
|
38
38
|
}
|
|
39
|
-
else
|
|
39
|
+
else if (!(metadata.requestDefaults.reasonOptional &&
|
|
40
|
+
flags.assets &&
|
|
41
|
+
flags.duration)) {
|
|
40
42
|
await (0, requests_1.promptForReason)(metadata);
|
|
41
43
|
}
|
|
42
44
|
// Step 5: Prompt for expiration
|
|
@@ -47,21 +49,24 @@ class RequestCreate extends core_1.Command {
|
|
|
47
49
|
await (0, requests_1.promptForExpiration)(metadata);
|
|
48
50
|
}
|
|
49
51
|
// Step 6: Display final summary of request
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
let canSubmit = true;
|
|
53
|
+
if (!(flags.assets &&
|
|
54
|
+
flags.duration &&
|
|
55
|
+
(metadata.requestDefaults.reasonOptional || flags.reason))) {
|
|
56
|
+
canSubmit = await (0, requests_1.promptRequestSubmission)(this, metadata);
|
|
52
57
|
}
|
|
53
|
-
// Step 7: Prompt for final
|
|
54
|
-
|
|
58
|
+
// Step 7: Prompt for final submission
|
|
59
|
+
if (canSubmit)
|
|
60
|
+
await (0, requests_1.submitFinalRequest)(this, client, metadata);
|
|
55
61
|
}
|
|
56
62
|
}
|
|
57
|
-
RequestCreate.hidden = true;
|
|
58
63
|
RequestCreate.description = "Creates an Opal access request via an interactive form";
|
|
59
64
|
RequestCreate.flags = {
|
|
60
65
|
help: flags_1.SHARED_FLAGS.help,
|
|
61
|
-
|
|
62
|
-
char: "
|
|
66
|
+
assets: core_1.Flags.string({
|
|
67
|
+
char: "a",
|
|
63
68
|
multiple: true,
|
|
64
|
-
description: "The
|
|
69
|
+
description: "The ids of the assets (resource, group) to request access to. Append a role ID using a colon if needed, e.g. `--assets 123:456`.\
|
|
65
70
|
\n If not provided, an interactive selection flow will be available to select assets to request.",
|
|
66
71
|
}),
|
|
67
72
|
reason: core_1.Flags.string({
|
|
@@ -8,7 +8,6 @@ const cmd_1 = require("../../lib/cmd");
|
|
|
8
8
|
const config_1 = require("../../lib/config");
|
|
9
9
|
const flags_1 = require("../../lib/flags");
|
|
10
10
|
const displays_1 = require("../../utils/displays");
|
|
11
|
-
const utils_1 = require("../../utils/utils");
|
|
12
11
|
const GET_REQUEST = (0, graphql_1.graphql)(`
|
|
13
12
|
query GetRequest(
|
|
14
13
|
$id: RequestId!
|
|
@@ -58,14 +57,13 @@ const GET_REQUEST = (0, graphql_1.graphql)(`
|
|
|
58
57
|
`);
|
|
59
58
|
class GetRequest extends core_1.Command {
|
|
60
59
|
async run() {
|
|
61
|
-
(0, utils_1.restrictToDev)(); //TODO: Remove after development is complete
|
|
62
60
|
(0, cmd_1.setMostRecentCommand)(this);
|
|
63
61
|
const configData = (0, config_1.getOrCreateConfigData)(this.config.configDir);
|
|
64
62
|
const client = await (0, apollo_1.getClient)(this, true);
|
|
65
63
|
// Verify id tag was provided
|
|
66
64
|
const { flags } = await this.parse(GetRequest);
|
|
67
65
|
if (!flags.id) {
|
|
68
|
-
this.log("Error: Please provide a
|
|
66
|
+
this.log("Error: Please provide a request ID using the --id flag.");
|
|
69
67
|
this.log("ex. opal request get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4");
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
@@ -96,7 +94,6 @@ class GetRequest extends core_1.Command {
|
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
|
-
GetRequest.hidden = true;
|
|
100
97
|
GetRequest.description = "Lists access requests";
|
|
101
98
|
GetRequest.flags = {
|
|
102
99
|
help: flags_1.SHARED_FLAGS.help,
|
|
@@ -6,7 +6,6 @@ const apollo_1 = require("../../lib/apollo");
|
|
|
6
6
|
const cmd_1 = require("../../lib/cmd");
|
|
7
7
|
const flags_1 = require("../../lib/flags");
|
|
8
8
|
const displays_1 = require("../../utils/displays");
|
|
9
|
-
const utils_1 = require("../../utils/utils");
|
|
10
9
|
// Add date filters, search query,
|
|
11
10
|
const GET_REQUESTS = (0, graphql_1.graphql)(`
|
|
12
11
|
query GetRequests($pageSize: Int, $showPendingOnly: Boolean!) {
|
|
@@ -59,7 +58,6 @@ const GET_REQUESTS = (0, graphql_1.graphql)(`
|
|
|
59
58
|
}`);
|
|
60
59
|
class ListRequests extends core_1.Command {
|
|
61
60
|
async run() {
|
|
62
|
-
(0, utils_1.restrictToDev)(); //TODO: Remove after development is complete
|
|
63
61
|
(0, cmd_1.setMostRecentCommand)(this);
|
|
64
62
|
const client = await (0, apollo_1.getClient)(this, true);
|
|
65
63
|
let pageSize = 10;
|
|
@@ -88,7 +86,6 @@ class ListRequests extends core_1.Command {
|
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
}
|
|
91
|
-
ListRequests.hidden = true;
|
|
92
89
|
ListRequests.description = "Lists your n recent outgoing access requests";
|
|
93
90
|
ListRequests.examples = [
|
|
94
91
|
"opal request list --n 5",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const credentials_1 = require("../lib/credentials");
|
|
6
|
+
const flags_1 = require("../lib/flags");
|
|
7
|
+
class WhoAmI extends core_1.Command {
|
|
8
|
+
async run() {
|
|
9
|
+
const opalCreds = await (0, credentials_1.getOpalCredentials)(this, false);
|
|
10
|
+
const organizationName = opalCreds === null || opalCreds === void 0 ? void 0 : opalCreds.organizationName;
|
|
11
|
+
const email = opalCreds === null || opalCreds === void 0 ? void 0 : opalCreds.email;
|
|
12
|
+
const configData = (0, config_1.getOrCreateConfigData)(this.config.configDir);
|
|
13
|
+
const url = configData[config_1.urlKey];
|
|
14
|
+
if (email) {
|
|
15
|
+
this.log(`User: ${email}`);
|
|
16
|
+
}
|
|
17
|
+
if (organizationName) {
|
|
18
|
+
if (organizationName === "unset-org-id") {
|
|
19
|
+
this.log("Authenticated with Opal API Token.");
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this.log(`Organization: ${organizationName}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (url) {
|
|
26
|
+
this.log(`Server: ${url}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
WhoAmI.description = "Describes current url set, organization name, and logged in user if applicabled.";
|
|
31
|
+
WhoAmI.flags = {
|
|
32
|
+
help: flags_1.SHARED_FLAGS.help,
|
|
33
|
+
};
|
|
34
|
+
exports.default = WhoAmI;
|
package/lib/lib/apollo.js
CHANGED
|
@@ -155,7 +155,7 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
155
155
|
return response;
|
|
156
156
|
});
|
|
157
157
|
});
|
|
158
|
-
const errorLink = (0, error_1.onError)(({ networkError, operation }) => {
|
|
158
|
+
const errorLink = (0, error_1.onError)(({ networkError, operation, forward }) => {
|
|
159
159
|
var _a;
|
|
160
160
|
// There's a few GQL operations where we don't want to use this error handler:
|
|
161
161
|
const customErrorOperations = [
|
|
@@ -186,7 +186,7 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
186
186
|
case 401: {
|
|
187
187
|
command.log("Your session is invalid or expired. Authenticating now...\n");
|
|
188
188
|
const loginCommand = new login_1.default([], command.config);
|
|
189
|
-
loginCommand.run().then(() => {
|
|
189
|
+
return (0, core_1.fromPromise)(loginCommand.run().then(() => {
|
|
190
190
|
if (cmd_1.mostRecentCommandTime && cmd_1.mostRecentCommand) {
|
|
191
191
|
const lastCommandReexecutionDuration = moment.duration(2, "minutes");
|
|
192
192
|
const lastCommandReexecutionDurationHasElapsed = cmd_1.mostRecentCommandTime.add(lastCommandReexecutionDuration) >
|
|
@@ -195,8 +195,7 @@ const initClient = async (command, fetchAccessToken = true) => {
|
|
|
195
195
|
cmd_1.mostRecentCommand.run();
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
-
});
|
|
199
|
-
break;
|
|
198
|
+
})).flatMap(() => forward(operation));
|
|
200
199
|
}
|
|
201
200
|
default:
|
|
202
201
|
return (0, exports.handleError)(command, `Received status code ${networkError.statusCode} from server${errorMessage ? ` with message "${errorMessage}"` : ""}`);
|
|
@@ -5,12 +5,13 @@ interface OpalCredentials {
|
|
|
5
5
|
clientIDCandidate?: string;
|
|
6
6
|
secret?: string;
|
|
7
7
|
secretType?: SecretType;
|
|
8
|
+
organizationName?: string;
|
|
8
9
|
}
|
|
9
10
|
export declare enum SecretType {
|
|
10
11
|
Cookie = "COOKIE",
|
|
11
12
|
ApiToken = "API_TOKEN"
|
|
12
13
|
}
|
|
13
|
-
export declare const setOpalCredentials: (command: Command, email: string | undefined, organizationID: string, clientIDCandidate: string | undefined | null, secret: string, secretType: SecretType) => Promise<void>;
|
|
14
|
+
export declare const setOpalCredentials: (command: Command, email: string | undefined, organizationID: string, clientIDCandidate: string | undefined | null, secret: string, secretType: SecretType, organizationName?: string) => Promise<void>;
|
|
14
15
|
export declare const getOpalCredentials: (command: Command, includeAuthSecret?: boolean) => Promise<OpalCredentials>;
|
|
15
16
|
export declare const removeOpalCredentials: (command: Command) => Promise<void>;
|
|
16
17
|
export {};
|
|
@@ -9,13 +9,14 @@ var SecretType;
|
|
|
9
9
|
SecretType["Cookie"] = "COOKIE";
|
|
10
10
|
SecretType["ApiToken"] = "API_TOKEN";
|
|
11
11
|
})(SecretType || (exports.SecretType = SecretType = {}));
|
|
12
|
-
const setOpalCredentials = async (command, email, organizationID, clientIDCandidate, secret, secretType) => {
|
|
12
|
+
const setOpalCredentials = async (command, email, organizationID, clientIDCandidate, secret, secretType, organizationName) => {
|
|
13
13
|
const givenEmail = email || "email-unset";
|
|
14
14
|
const configData = (0, config_1.getOrCreateConfigData)(command.config.configDir);
|
|
15
15
|
configData.creds = {
|
|
16
16
|
clientIDCandidate,
|
|
17
17
|
email,
|
|
18
18
|
organizationID,
|
|
19
|
+
organizationName,
|
|
19
20
|
secretType,
|
|
20
21
|
};
|
|
21
22
|
(0, config_1.writeConfigData)(command.config.configDir, configData);
|
package/lib/lib/requests.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { NormalizedCacheObject } from "@apollo/client/core";
|
|
2
2
|
import type { ApolloClient } from "@apollo/client/core/ApolloClient";
|
|
3
3
|
import type { Command } from "@oclif/core/lib/command";
|
|
4
|
+
import { type AppType, type ConnectionType, EntityType } from "../graphql/graphql";
|
|
4
5
|
type AppNode = {
|
|
5
6
|
appId: string;
|
|
6
7
|
appName: string;
|
|
7
|
-
appType?:
|
|
8
|
+
appType?: AppType | ConnectionType;
|
|
8
9
|
assets: Record<string, AssetNode>;
|
|
9
10
|
};
|
|
10
11
|
type AssetNode = {
|
|
11
12
|
assetId: string;
|
|
12
13
|
assetName: string;
|
|
13
|
-
type:
|
|
14
|
+
type: EntityType;
|
|
14
15
|
roles?: Record<string, RoleNode>;
|
|
15
16
|
};
|
|
16
17
|
type RoleNode = {
|
|
@@ -18,6 +19,7 @@ type RoleNode = {
|
|
|
18
19
|
roleName: string;
|
|
19
20
|
};
|
|
20
21
|
export type RequestMap = Record<string, AppNode>;
|
|
22
|
+
export declare const DISPLAY_LABELS: Partial<Record<EntityType, string>>;
|
|
21
23
|
type DurationOption = {
|
|
22
24
|
durationInMinutes: number;
|
|
23
25
|
label: string;
|
|
@@ -44,7 +46,7 @@ export declare function doneSelectingAssets(): Promise<boolean>;
|
|
|
44
46
|
export declare function setRequestDefaults(cmd: Command, client: ApolloClient<NormalizedCacheObject>, metadata: RequestMetadata): Promise<void>;
|
|
45
47
|
export declare function promptForReason(metadata: RequestMetadata): Promise<void>;
|
|
46
48
|
export declare function promptForExpiration(metadata: RequestMetadata): Promise<void>;
|
|
47
|
-
export declare function
|
|
49
|
+
export declare function promptRequestSubmission(cmd: Command, metadata: RequestMetadata): Promise<boolean>;
|
|
48
50
|
export declare function submitFinalRequest(cmd: Command, client: ApolloClient<NormalizedCacheObject>, metadata: RequestMetadata): Promise<void>;
|
|
49
51
|
export declare function bypassRequestSelection(cmd: Command, client: ApolloClient<NormalizedCacheObject>, flagValue: string[], metadata: RequestMetadata): Promise<void>;
|
|
50
52
|
export declare function bypassDuration(cmd: Command, duration: number, metadata: RequestMetadata): void;
|
package/lib/lib/requests.js
CHANGED
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DISPLAY_LABELS = void 0;
|
|
3
4
|
exports.initEmptyRequestMetadata = initEmptyRequestMetadata;
|
|
4
5
|
exports.selectRequestableItems = selectRequestableItems;
|
|
5
6
|
exports.doneSelectingAssets = doneSelectingAssets;
|
|
6
7
|
exports.setRequestDefaults = setRequestDefaults;
|
|
7
8
|
exports.promptForReason = promptForReason;
|
|
8
9
|
exports.promptForExpiration = promptForExpiration;
|
|
9
|
-
exports.
|
|
10
|
+
exports.promptRequestSubmission = promptRequestSubmission;
|
|
10
11
|
exports.submitFinalRequest = submitFinalRequest;
|
|
11
12
|
exports.bypassRequestSelection = bypassRequestSelection;
|
|
12
13
|
exports.bypassDuration = bypassDuration;
|
|
13
14
|
const chalk_1 = require("chalk");
|
|
14
|
-
const inquirer = require("inquirer");
|
|
15
15
|
const graphql_1 = require("../graphql");
|
|
16
16
|
const graphql_2 = require("../graphql/graphql");
|
|
17
17
|
const displays_1 = require("../utils/displays");
|
|
18
18
|
const config_1 = require("./config");
|
|
19
19
|
const { AutoComplete, Select, prompt, Form } = require("enquirer");
|
|
20
|
+
function entityTypeFromString(str) {
|
|
21
|
+
const capStr = str === null || str === void 0 ? void 0 : str.toLocaleUpperCase();
|
|
22
|
+
if (capStr === "RESOURCE") {
|
|
23
|
+
return graphql_2.EntityType.Resource;
|
|
24
|
+
}
|
|
25
|
+
if (capStr === "GROUP") {
|
|
26
|
+
return graphql_2.EntityType.Group;
|
|
27
|
+
}
|
|
28
|
+
// if type unknown, default to resource
|
|
29
|
+
return graphql_2.EntityType.Resource;
|
|
30
|
+
}
|
|
31
|
+
exports.DISPLAY_LABELS = {
|
|
32
|
+
[graphql_2.EntityType.Resource]: "Resource",
|
|
33
|
+
[graphql_2.EntityType.Group]: "Group",
|
|
34
|
+
};
|
|
20
35
|
function initEmptyRequestMetadata() {
|
|
21
36
|
// Initialize with empty defaults
|
|
22
37
|
const requestDefaults = {
|
|
@@ -169,7 +184,7 @@ async function queryRequestableAssets(cmd, client, appId, input) {
|
|
|
169
184
|
value: {
|
|
170
185
|
name: name || "",
|
|
171
186
|
id: id || "",
|
|
172
|
-
type: ((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)
|
|
187
|
+
type: entityTypeFromString(((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)),
|
|
173
188
|
},
|
|
174
189
|
};
|
|
175
190
|
});
|
|
@@ -228,7 +243,7 @@ async function queryAssetRoles(cmd, client, assetType, assetId) {
|
|
|
228
243
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
229
244
|
try {
|
|
230
245
|
switch (assetType) {
|
|
231
|
-
case
|
|
246
|
+
case graphql_2.EntityType.Resource: {
|
|
232
247
|
const resp = await client.query({
|
|
233
248
|
query: RESOURCE_ROLES_QUERY,
|
|
234
249
|
variables: {
|
|
@@ -257,7 +272,7 @@ async function queryAssetRoles(cmd, client, assetType, assetId) {
|
|
|
257
272
|
}
|
|
258
273
|
return;
|
|
259
274
|
}
|
|
260
|
-
case
|
|
275
|
+
case graphql_2.EntityType.Group: {
|
|
261
276
|
const resp = await client.query({
|
|
262
277
|
query: GROUP_ROLES_QUERY,
|
|
263
278
|
variables: {
|
|
@@ -613,11 +628,14 @@ async function queryAssociatedItems(cmd, client, id, input) {
|
|
|
613
628
|
}
|
|
614
629
|
}
|
|
615
630
|
// Helper functions
|
|
631
|
+
const selectInstructions = chalk_1.default.dim("[↑↓] Navigate · [Enter] Select · Type to filter");
|
|
632
|
+
const multiSelectInstructions = chalk_1.default.dim("[↑↓] Navigate · [Space] Select · [Enter] Confirm · Type to filter");
|
|
616
633
|
async function selectRequestableItems(cmd, client, requestMap) {
|
|
617
634
|
const initial = (await queryRequestableApps(cmd, client, "")) || [];
|
|
618
635
|
const appPrompt = new AutoComplete({
|
|
619
636
|
name: "App",
|
|
620
|
-
message: "Select an app
|
|
637
|
+
message: "Select an app",
|
|
638
|
+
hint: selectInstructions,
|
|
621
639
|
limit: 15,
|
|
622
640
|
choices: initial,
|
|
623
641
|
async suggest(input) {
|
|
@@ -645,6 +663,7 @@ async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
|
|
|
645
663
|
const rolePrompt = new AutoComplete({
|
|
646
664
|
name: "Roles",
|
|
647
665
|
message: `Select a role for ${app.name}:`,
|
|
666
|
+
hint: multiSelectInstructions,
|
|
648
667
|
limit: 15,
|
|
649
668
|
multiple: true,
|
|
650
669
|
async choices(input) {
|
|
@@ -655,7 +674,7 @@ async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
|
|
|
655
674
|
},
|
|
656
675
|
validate: (answer) => {
|
|
657
676
|
if (answer.length !== 1) {
|
|
658
|
-
return "
|
|
677
|
+
return "Only one role is allowed to be requested for on Okta or Azure apps.";
|
|
659
678
|
}
|
|
660
679
|
return true;
|
|
661
680
|
},
|
|
@@ -667,7 +686,7 @@ async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
|
|
|
667
686
|
entry.assets[role.id] = {
|
|
668
687
|
assetId: role.id,
|
|
669
688
|
assetName: role.name,
|
|
670
|
-
type: role.type
|
|
689
|
+
type: entityTypeFromString(role.type),
|
|
671
690
|
roles: {},
|
|
672
691
|
};
|
|
673
692
|
}
|
|
@@ -683,7 +702,7 @@ function appRolesFromEdge(edge) {
|
|
|
683
702
|
value: {
|
|
684
703
|
id: edge.node.id + accessLevel.accessLevelRemoteId,
|
|
685
704
|
name: accessLevel.accessLevelName,
|
|
686
|
-
type: graphql_2.EntityType.Resource,
|
|
705
|
+
type: exports.DISPLAY_LABELS[graphql_2.EntityType.Resource],
|
|
687
706
|
toString: () => accessLevel.accessLevelName,
|
|
688
707
|
},
|
|
689
708
|
}));
|
|
@@ -694,7 +713,7 @@ function appRolesFromEdge(edge) {
|
|
|
694
713
|
value: {
|
|
695
714
|
id: edge.node.id,
|
|
696
715
|
name: (_b = edge.alias) !== null && _b !== void 0 ? _b : edge.node.name,
|
|
697
|
-
type: graphql_2.EntityType.Resource,
|
|
716
|
+
type: exports.DISPLAY_LABELS[graphql_2.EntityType.Resource],
|
|
698
717
|
toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
|
|
699
718
|
},
|
|
700
719
|
},
|
|
@@ -703,11 +722,11 @@ function appRolesFromEdge(edge) {
|
|
|
703
722
|
case "Group":
|
|
704
723
|
return [
|
|
705
724
|
{
|
|
706
|
-
message: (_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name
|
|
725
|
+
message: `${(_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name} ${graphql_2.EntityType.Group}`,
|
|
707
726
|
value: {
|
|
708
727
|
id: edge.node.id,
|
|
709
728
|
name: (_d = edge.alias) !== null && _d !== void 0 ? _d : edge.node.name,
|
|
710
|
-
type: graphql_2.EntityType.Group,
|
|
729
|
+
type: exports.DISPLAY_LABELS[graphql_2.EntityType.Group],
|
|
711
730
|
toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
|
|
712
731
|
},
|
|
713
732
|
},
|
|
@@ -719,6 +738,7 @@ async function chooseAssets(cmd, client, appId, requestMap) {
|
|
|
719
738
|
const assetPrompt = new AutoComplete({
|
|
720
739
|
name: "Assets",
|
|
721
740
|
message: "Select one or more assets:",
|
|
741
|
+
hint: multiSelectInstructions,
|
|
722
742
|
limit: 15,
|
|
723
743
|
multiple: true,
|
|
724
744
|
async choices(input) {
|
|
@@ -768,6 +788,7 @@ async function chooseRoles(cmd, client, appId, assetId, requestMap) {
|
|
|
768
788
|
const rolePrompt = new AutoComplete({
|
|
769
789
|
name: "Roles",
|
|
770
790
|
message: `Select one or more roles for ${assetEntry.assetName}:`,
|
|
791
|
+
hint: multiSelectInstructions,
|
|
771
792
|
limit: 15,
|
|
772
793
|
multiple: true,
|
|
773
794
|
choices: assetRoles,
|
|
@@ -858,7 +879,7 @@ async function promptForReason(metadata) {
|
|
|
858
879
|
const { reason } = await prompt([
|
|
859
880
|
{
|
|
860
881
|
name: "reason",
|
|
861
|
-
message: "
|
|
882
|
+
message: "Why do you need access?",
|
|
862
883
|
type: "input",
|
|
863
884
|
validate: (answer) => {
|
|
864
885
|
if (!metadata.requestDefaults.reasonOptional && answer.length < 1) {
|
|
@@ -897,6 +918,7 @@ async function promptForExpiration(metadata) {
|
|
|
897
918
|
const expirationSelect = new AutoComplete({
|
|
898
919
|
name: "expiration",
|
|
899
920
|
message: "When should access expire?",
|
|
921
|
+
hint: "Type to filter",
|
|
900
922
|
type: "list",
|
|
901
923
|
choices: durations,
|
|
902
924
|
pageSize: 15,
|
|
@@ -980,30 +1002,17 @@ async function setCustomDuration(metadata) {
|
|
|
980
1002
|
label: durationLabel,
|
|
981
1003
|
};
|
|
982
1004
|
}
|
|
983
|
-
async function
|
|
1005
|
+
async function promptRequestSubmission(cmd, metadata) {
|
|
984
1006
|
(0, displays_1.displayFinalRequestSummary)(cmd, metadata);
|
|
985
1007
|
const submitMessage = "✅ Yes, submit request";
|
|
986
1008
|
const cancelMessage = "❌ No, cancel request";
|
|
987
|
-
const
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
]);
|
|
995
|
-
switch (submit) {
|
|
996
|
-
case submitMessage: {
|
|
997
|
-
return;
|
|
998
|
-
}
|
|
999
|
-
case cancelMessage: {
|
|
1000
|
-
cmd.log("🚫 Access Request has been cancelled.");
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
default: {
|
|
1004
|
-
cmd.error("Unknown error occurred.");
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1009
|
+
const prompt = new Select({
|
|
1010
|
+
name: "submitOrCancel",
|
|
1011
|
+
message: "Is this all you want to request?",
|
|
1012
|
+
choices: [submitMessage, cancelMessage],
|
|
1013
|
+
});
|
|
1014
|
+
const submitOrCancel = await prompt.run();
|
|
1015
|
+
return submitOrCancel === submitMessage;
|
|
1007
1016
|
}
|
|
1008
1017
|
async function submitFinalRequest(cmd, client, metadata) {
|
|
1009
1018
|
var _a, _b, _c, _d;
|
|
@@ -1015,11 +1024,11 @@ async function submitFinalRequest(cmd, client, metadata) {
|
|
|
1015
1024
|
// Both extract the requestedResources and requestedGroups,
|
|
1016
1025
|
// use different formats.
|
|
1017
1026
|
for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
1018
|
-
if (assetNode.roles
|
|
1027
|
+
if (assetNode.roles) {
|
|
1019
1028
|
const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
|
|
1020
1029
|
return roleId;
|
|
1021
1030
|
});
|
|
1022
|
-
const roleIds = mappedRoles.length ? mappedRoles : [""];
|
|
1031
|
+
const roleIds = mappedRoles.length > 0 ? mappedRoles : [""];
|
|
1023
1032
|
for (const roleId of roleIds) {
|
|
1024
1033
|
switch (assetNode.type) {
|
|
1025
1034
|
case graphql_2.EntityType.Resource: {
|
|
@@ -1064,68 +1073,66 @@ async function submitFinalRequest(cmd, client, metadata) {
|
|
|
1064
1073
|
async function bypassRequestSelection(cmd, client, flagValue, metadata) {
|
|
1065
1074
|
var _a, _b;
|
|
1066
1075
|
try {
|
|
1067
|
-
|
|
1076
|
+
// Query Catalog Item endpoint to identify what the id belongs to (resource or group)
|
|
1077
|
+
for (const val of flagValue) {
|
|
1078
|
+
const delimiterIndex = val.indexOf(":");
|
|
1079
|
+
const assetId = val.substring(0, delimiterIndex);
|
|
1080
|
+
const roleName = val.substring(delimiterIndex + 1);
|
|
1068
1081
|
const resp = await client.query({
|
|
1069
1082
|
query: CATALOG_ITEM,
|
|
1070
1083
|
variables: {
|
|
1071
|
-
uuid:
|
|
1084
|
+
uuid: assetId || "",
|
|
1072
1085
|
},
|
|
1073
1086
|
fetchPolicy: "network-only", // to avoid caching
|
|
1074
1087
|
});
|
|
1075
1088
|
switch (resp.data.catalogItem.__typename) {
|
|
1089
|
+
case "Group":
|
|
1076
1090
|
case "Resource": {
|
|
1077
|
-
const
|
|
1078
|
-
const
|
|
1091
|
+
const item = resp.data.catalogItem;
|
|
1092
|
+
const assetName = item.__typename === "Resource" ? item.displayName : item.name;
|
|
1093
|
+
const requestableRoles = (item.accessLevels || [])
|
|
1079
1094
|
// TODO: Support okta azure apps ?.filter((role) => role.accessLevelName !== "") // This assumes length == 1
|
|
1080
1095
|
.map((role) => ({
|
|
1081
1096
|
id: role.accessLevelRemoteId,
|
|
1082
1097
|
name: role.accessLevelName,
|
|
1083
1098
|
}));
|
|
1084
|
-
|
|
1085
|
-
!(roles.length === 1 && roles[0].name === "")) {
|
|
1086
|
-
cmd.log(`Roles not implemented yet for resource ${resourceName}. Skipping roles selection.`); //TODO: Implement roles support
|
|
1087
|
-
continue;
|
|
1088
|
-
}
|
|
1089
|
-
const appId = ((_a = resp.data.catalogItem.connection) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
1099
|
+
const appId = ((_a = item.connection) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
1090
1100
|
if (!(appId in metadata.requestMap)) {
|
|
1091
1101
|
metadata.requestMap[appId] = {
|
|
1092
|
-
appName: ((_b =
|
|
1102
|
+
appName: ((_b = item.connection) === null || _b === void 0 ? void 0 : _b.displayName) || "",
|
|
1093
1103
|
appId: appId,
|
|
1094
1104
|
assets: {},
|
|
1095
1105
|
};
|
|
1096
1106
|
}
|
|
1097
|
-
const assetEntry = metadata.requestMap[appId].assets[
|
|
1107
|
+
const assetEntry = metadata.requestMap[appId].assets[assetId];
|
|
1098
1108
|
if (!assetEntry) {
|
|
1099
|
-
metadata.requestMap[appId].assets[
|
|
1100
|
-
assetId:
|
|
1101
|
-
assetName:
|
|
1102
|
-
type:
|
|
1109
|
+
metadata.requestMap[appId].assets[assetId] = {
|
|
1110
|
+
assetId: assetId,
|
|
1111
|
+
assetName: assetName,
|
|
1112
|
+
type: entityTypeFromString(item.__typename),
|
|
1103
1113
|
roles: {},
|
|
1104
1114
|
};
|
|
1105
1115
|
}
|
|
1106
|
-
if (
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1116
|
+
if (requestableRoles.length > 0 &&
|
|
1117
|
+
!(requestableRoles.length === 1 && requestableRoles[0].name === "")) {
|
|
1118
|
+
const selectedRole = requestableRoles.find((role) => role.name === roleName);
|
|
1119
|
+
if (selectedRole !== undefined) {
|
|
1120
|
+
if (!metadata.requestMap[appId].assets[assetId].roles) {
|
|
1121
|
+
metadata.requestMap[appId].assets[assetId].roles = {};
|
|
1122
|
+
}
|
|
1123
|
+
metadata.requestMap[appId].assets[assetId].roles[selectedRole.id] = {
|
|
1124
|
+
roleId: selectedRole.id,
|
|
1125
|
+
roleName: selectedRole.name,
|
|
1114
1126
|
};
|
|
1115
1127
|
}
|
|
1128
|
+
else {
|
|
1129
|
+
cmd.error(`Access level specified does not match one of ${assetName}'s defined access levels: ${requestableRoles.map((role) => `"${role.name}"`)}`);
|
|
1130
|
+
}
|
|
1116
1131
|
}
|
|
1117
1132
|
break;
|
|
1118
1133
|
}
|
|
1119
|
-
case "Group": {
|
|
1120
|
-
//TODO
|
|
1121
|
-
break;
|
|
1122
|
-
}
|
|
1123
|
-
case "Connection": {
|
|
1124
|
-
//TODO
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1127
1134
|
default:
|
|
1128
|
-
cmd.error("
|
|
1135
|
+
cmd.error("Invalid asset id was passed in using the --id flag.");
|
|
1129
1136
|
}
|
|
1130
1137
|
}
|
|
1131
1138
|
}
|
package/lib/utils/displays.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ApolloQueryResult } from "@apollo/client";
|
|
2
2
|
import type { Command } from "@oclif/core/lib/command";
|
|
3
3
|
import type { GetRequestQuery, GetRequestsQuery } from "../graphql/graphql";
|
|
4
|
-
import type
|
|
4
|
+
import { type RequestMap, type RequestMetadata } from "../lib/requests";
|
|
5
5
|
export declare function headerMessage(cmd: Command): void;
|
|
6
6
|
export declare function treeifyRequestMap(cmd: Command, requestMap: RequestMap): void;
|
|
7
7
|
export declare function displayFinalRequestSummary(cmd: Command, metadata: RequestMetadata): void;
|
package/lib/utils/displays.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.getStyledStatus = getStyledStatus;
|
|
|
7
7
|
exports.displayRequestDetails = displayRequestDetails;
|
|
8
8
|
exports.displayRequestListTable = displayRequestListTable;
|
|
9
9
|
const chalk_1 = require("chalk");
|
|
10
|
+
const requests_1 = require("../lib/requests");
|
|
10
11
|
const Table = require("cli-table3");
|
|
11
12
|
const treeify = require("object-treeify").default;
|
|
12
13
|
function headerMessage(cmd) {
|
|
@@ -30,7 +31,7 @@ function treeifyRequestMap(cmd, requestMap) {
|
|
|
30
31
|
for (const [_assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
31
32
|
// If okta/azure asset with no role, change asset name
|
|
32
33
|
const assetName = assetNode.assetName || "No Role (Direct access)";
|
|
33
|
-
const assetKey = `${assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
|
|
34
|
+
const assetKey = `${assetName} ${chalk_1.default.dim(`[${requests_1.DISPLAY_LABELS[assetNode.type]}]`)}`;
|
|
34
35
|
if (assetNode.roles !== undefined) {
|
|
35
36
|
assetsTree[assetKey] = {};
|
|
36
37
|
for (const [_roleId, roleNode] of Object.entries(assetNode.roles)) {
|
package/oclif.manifest.json
CHANGED
|
@@ -316,6 +316,34 @@
|
|
|
316
316
|
"set-url.js"
|
|
317
317
|
]
|
|
318
318
|
},
|
|
319
|
+
"whoami": {
|
|
320
|
+
"aliases": [],
|
|
321
|
+
"args": {},
|
|
322
|
+
"description": "Describes current url set, organization name, and logged in user if applicabled.",
|
|
323
|
+
"flags": {
|
|
324
|
+
"help": {
|
|
325
|
+
"char": "h",
|
|
326
|
+
"description": "Show CLI help.",
|
|
327
|
+
"name": "help",
|
|
328
|
+
"allowNo": false,
|
|
329
|
+
"type": "boolean"
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
"hasDynamicHelp": false,
|
|
333
|
+
"hiddenAliases": [],
|
|
334
|
+
"id": "whoami",
|
|
335
|
+
"pluginAlias": "opal-security",
|
|
336
|
+
"pluginName": "opal-security",
|
|
337
|
+
"pluginType": "core",
|
|
338
|
+
"strict": true,
|
|
339
|
+
"enableJsonFlag": false,
|
|
340
|
+
"isESM": false,
|
|
341
|
+
"relativePath": [
|
|
342
|
+
"lib",
|
|
343
|
+
"commands",
|
|
344
|
+
"whoami.js"
|
|
345
|
+
]
|
|
346
|
+
},
|
|
319
347
|
"aws:identity": {
|
|
320
348
|
"aliases": [],
|
|
321
349
|
"args": {},
|
|
@@ -388,14 +416,14 @@
|
|
|
388
416
|
"get.js"
|
|
389
417
|
]
|
|
390
418
|
},
|
|
391
|
-
"
|
|
419
|
+
"kube-roles:start": {
|
|
392
420
|
"aliases": [],
|
|
393
421
|
"args": {},
|
|
394
|
-
"description": "Starts a session to assume
|
|
422
|
+
"description": "Starts a session to assume a Kubernetes cluster IAM role.",
|
|
395
423
|
"examples": [
|
|
396
|
-
"opal
|
|
397
|
-
"opal
|
|
398
|
-
"opal
|
|
424
|
+
"opal kube-roles:start",
|
|
425
|
+
"opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398",
|
|
426
|
+
"opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role\""
|
|
399
427
|
],
|
|
400
428
|
"flags": {
|
|
401
429
|
"help": {
|
|
@@ -413,6 +441,14 @@
|
|
|
413
441
|
"multiple": false,
|
|
414
442
|
"type": "option"
|
|
415
443
|
},
|
|
444
|
+
"accessLevelRemoteId": {
|
|
445
|
+
"char": "a",
|
|
446
|
+
"description": "The remote ID of the access level with which to access the resource.",
|
|
447
|
+
"name": "accessLevelRemoteId",
|
|
448
|
+
"hasDynamicHelp": false,
|
|
449
|
+
"multiple": false,
|
|
450
|
+
"type": "option"
|
|
451
|
+
},
|
|
416
452
|
"sessionId": {
|
|
417
453
|
"char": "s",
|
|
418
454
|
"description": "The Opal ID of the session to connect to. Uses an existing session that was created via the web flow.",
|
|
@@ -427,18 +463,11 @@
|
|
|
427
463
|
"name": "refresh",
|
|
428
464
|
"allowNo": false,
|
|
429
465
|
"type": "boolean"
|
|
430
|
-
},
|
|
431
|
-
"profileName": {
|
|
432
|
-
"description": "Uses a custom AWS profile name for the IAM role. Default value is the role's name.",
|
|
433
|
-
"name": "profileName",
|
|
434
|
-
"hasDynamicHelp": false,
|
|
435
|
-
"multiple": false,
|
|
436
|
-
"type": "option"
|
|
437
466
|
}
|
|
438
467
|
},
|
|
439
468
|
"hasDynamicHelp": false,
|
|
440
469
|
"hiddenAliases": [],
|
|
441
|
-
"id": "
|
|
470
|
+
"id": "kube-roles:start",
|
|
442
471
|
"pluginAlias": "opal-security",
|
|
443
472
|
"pluginName": "opal-security",
|
|
444
473
|
"pluginType": "core",
|
|
@@ -448,18 +477,18 @@
|
|
|
448
477
|
"relativePath": [
|
|
449
478
|
"lib",
|
|
450
479
|
"commands",
|
|
451
|
-
"
|
|
480
|
+
"kube-roles",
|
|
452
481
|
"start.js"
|
|
453
482
|
]
|
|
454
483
|
},
|
|
455
|
-
"
|
|
484
|
+
"iam-roles:start": {
|
|
456
485
|
"aliases": [],
|
|
457
486
|
"args": {},
|
|
458
|
-
"description": "Starts a session to assume
|
|
487
|
+
"description": "Starts a session to assume an IAM role.",
|
|
459
488
|
"examples": [
|
|
460
|
-
"opal
|
|
461
|
-
"opal
|
|
462
|
-
"opal
|
|
489
|
+
"opal iam-roles:start",
|
|
490
|
+
"opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398",
|
|
491
|
+
"opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName \"custom-profile\""
|
|
463
492
|
],
|
|
464
493
|
"flags": {
|
|
465
494
|
"help": {
|
|
@@ -477,14 +506,6 @@
|
|
|
477
506
|
"multiple": false,
|
|
478
507
|
"type": "option"
|
|
479
508
|
},
|
|
480
|
-
"accessLevelRemoteId": {
|
|
481
|
-
"char": "a",
|
|
482
|
-
"description": "The remote ID of the access level with which to access the resource.",
|
|
483
|
-
"name": "accessLevelRemoteId",
|
|
484
|
-
"hasDynamicHelp": false,
|
|
485
|
-
"multiple": false,
|
|
486
|
-
"type": "option"
|
|
487
|
-
},
|
|
488
509
|
"sessionId": {
|
|
489
510
|
"char": "s",
|
|
490
511
|
"description": "The Opal ID of the session to connect to. Uses an existing session that was created via the web flow.",
|
|
@@ -499,11 +520,18 @@
|
|
|
499
520
|
"name": "refresh",
|
|
500
521
|
"allowNo": false,
|
|
501
522
|
"type": "boolean"
|
|
523
|
+
},
|
|
524
|
+
"profileName": {
|
|
525
|
+
"description": "Uses a custom AWS profile name for the IAM role. Default value is the role's name.",
|
|
526
|
+
"name": "profileName",
|
|
527
|
+
"hasDynamicHelp": false,
|
|
528
|
+
"multiple": false,
|
|
529
|
+
"type": "option"
|
|
502
530
|
}
|
|
503
531
|
},
|
|
504
532
|
"hasDynamicHelp": false,
|
|
505
533
|
"hiddenAliases": [],
|
|
506
|
-
"id": "
|
|
534
|
+
"id": "iam-roles:start",
|
|
507
535
|
"pluginAlias": "opal-security",
|
|
508
536
|
"pluginName": "opal-security",
|
|
509
537
|
"pluginType": "core",
|
|
@@ -513,7 +541,7 @@
|
|
|
513
541
|
"relativePath": [
|
|
514
542
|
"lib",
|
|
515
543
|
"commands",
|
|
516
|
-
"
|
|
544
|
+
"iam-roles",
|
|
517
545
|
"start.js"
|
|
518
546
|
]
|
|
519
547
|
},
|
|
@@ -606,10 +634,10 @@
|
|
|
606
634
|
"allowNo": false,
|
|
607
635
|
"type": "boolean"
|
|
608
636
|
},
|
|
609
|
-
"
|
|
610
|
-
"char": "
|
|
611
|
-
"description": "The
|
|
612
|
-
"name": "
|
|
637
|
+
"assets": {
|
|
638
|
+
"char": "a",
|
|
639
|
+
"description": "The ids of the assets (resource, group) to request access to. Append a role ID using a colon if needed, e.g. `--assets 123:456`. \n If not provided, an interactive selection flow will be available to select assets to request.",
|
|
640
|
+
"name": "assets",
|
|
613
641
|
"hasDynamicHelp": false,
|
|
614
642
|
"multiple": true,
|
|
615
643
|
"type": "option"
|
|
@@ -632,7 +660,6 @@
|
|
|
632
660
|
}
|
|
633
661
|
},
|
|
634
662
|
"hasDynamicHelp": false,
|
|
635
|
-
"hidden": true,
|
|
636
663
|
"hiddenAliases": [],
|
|
637
664
|
"id": "request:create",
|
|
638
665
|
"pluginAlias": "opal-security",
|
|
@@ -681,7 +708,6 @@
|
|
|
681
708
|
}
|
|
682
709
|
},
|
|
683
710
|
"hasDynamicHelp": false,
|
|
684
|
-
"hidden": true,
|
|
685
711
|
"hiddenAliases": [],
|
|
686
712
|
"id": "request:get",
|
|
687
713
|
"pluginAlias": "opal-security",
|
|
@@ -740,7 +766,6 @@
|
|
|
740
766
|
}
|
|
741
767
|
},
|
|
742
768
|
"hasDynamicHelp": false,
|
|
743
|
-
"hidden": true,
|
|
744
769
|
"hiddenAliases": [],
|
|
745
770
|
"id": "request:list",
|
|
746
771
|
"pluginAlias": "opal-security",
|
|
@@ -1003,5 +1028,5 @@
|
|
|
1003
1028
|
]
|
|
1004
1029
|
}
|
|
1005
1030
|
},
|
|
1006
|
-
"version": "3.1.1-beta.
|
|
1031
|
+
"version": "3.1.1-beta.7e1cc21"
|
|
1007
1032
|
}
|
package/package.json
CHANGED