opal-security 3.1.1-beta.7648ca2 → 3.1.1-beta.8a533e4
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 +18 -18
- package/lib/commands/request/create.js +1 -1
- package/lib/commands/request/list.js +2 -2
- package/lib/lib/requests.js +78 -50
- package/lib/utils/displays.d.ts +2 -2
- package/lib/utils/displays.js +43 -50
- package/oclif.manifest.json +1 -1
- package/package.json +2 -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.8a533e4 linux-x64 node-v20.19.2
|
|
26
26
|
$ opal --help [COMMAND]
|
|
27
27
|
USAGE
|
|
28
28
|
$ opal COMMAND
|
|
@@ -101,7 +101,7 @@ EXAMPLES
|
|
|
101
101
|
$ opal aws:identity
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
_See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
104
|
+
_See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/aws/identity.ts)_
|
|
105
105
|
|
|
106
106
|
## `opal clear-auth-provider`
|
|
107
107
|
|
|
@@ -121,7 +121,7 @@ EXAMPLES
|
|
|
121
121
|
$ opal clear-auth-provider
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
_See code: [src/commands/clear-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
124
|
+
_See code: [src/commands/clear-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/clear-auth-provider.ts)_
|
|
125
125
|
|
|
126
126
|
## `opal curl-example`
|
|
127
127
|
|
|
@@ -138,7 +138,7 @@ DESCRIPTION
|
|
|
138
138
|
Prints out an example cURL command containing the parameters the CLI uses to query the Opal server.
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
_See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
141
|
+
_See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/curl-example.ts)_
|
|
142
142
|
|
|
143
143
|
## `opal groups get`
|
|
144
144
|
|
|
@@ -159,7 +159,7 @@ EXAMPLES
|
|
|
159
159
|
$ opal groups:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
|
|
160
160
|
```
|
|
161
161
|
|
|
162
|
-
_See code: [src/commands/groups/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
162
|
+
_See code: [src/commands/groups/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/groups/get.ts)_
|
|
163
163
|
|
|
164
164
|
## `opal help [COMMANDS]`
|
|
165
165
|
|
|
@@ -209,7 +209,7 @@ EXAMPLES
|
|
|
209
209
|
$ opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName "custom-profile"
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
_See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
212
|
+
_See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/iam-roles/start.ts)_
|
|
213
213
|
|
|
214
214
|
## `opal kube-roles start`
|
|
215
215
|
|
|
@@ -240,7 +240,7 @@ EXAMPLES
|
|
|
240
240
|
$ opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId "arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role"
|
|
241
241
|
```
|
|
242
242
|
|
|
243
|
-
_See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
243
|
+
_See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/kube-roles/start.ts)_
|
|
244
244
|
|
|
245
245
|
## `opal login`
|
|
246
246
|
|
|
@@ -261,7 +261,7 @@ EXAMPLES
|
|
|
261
261
|
$ opal login
|
|
262
262
|
```
|
|
263
263
|
|
|
264
|
-
_See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
264
|
+
_See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/login.ts)_
|
|
265
265
|
|
|
266
266
|
## `opal logout`
|
|
267
267
|
|
|
@@ -281,7 +281,7 @@ EXAMPLES
|
|
|
281
281
|
$ opal logout
|
|
282
282
|
```
|
|
283
283
|
|
|
284
|
-
_See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
284
|
+
_See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/logout.ts)_
|
|
285
285
|
|
|
286
286
|
## `opal postgres-instances start`
|
|
287
287
|
|
|
@@ -318,7 +318,7 @@ EXAMPLES
|
|
|
318
318
|
$ opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view
|
|
319
319
|
```
|
|
320
320
|
|
|
321
|
-
_See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
321
|
+
_See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/postgres-instances/start.ts)_
|
|
322
322
|
|
|
323
323
|
## `opal resources get`
|
|
324
324
|
|
|
@@ -339,7 +339,7 @@ EXAMPLES
|
|
|
339
339
|
$ opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
|
|
340
340
|
```
|
|
341
341
|
|
|
342
|
-
_See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
342
|
+
_See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/resources/get.ts)_
|
|
343
343
|
|
|
344
344
|
## `opal set-auth-provider`
|
|
345
345
|
|
|
@@ -365,7 +365,7 @@ EXAMPLES
|
|
|
365
365
|
$ opal set-auth-provider --clientID 1234asdf --issuerUrl https://auth.example.com
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
-
_See code: [src/commands/set-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
368
|
+
_See code: [src/commands/set-auth-provider.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/set-auth-provider.ts)_
|
|
369
369
|
|
|
370
370
|
## `opal set-custom-header`
|
|
371
371
|
|
|
@@ -386,7 +386,7 @@ EXAMPLES
|
|
|
386
386
|
$ opal set-custom-header --header 'cf-access-token: $TOKEN'
|
|
387
387
|
```
|
|
388
388
|
|
|
389
|
-
_See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
389
|
+
_See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/set-custom-header.ts)_
|
|
390
390
|
|
|
391
391
|
## `opal set-token`
|
|
392
392
|
|
|
@@ -406,7 +406,7 @@ EXAMPLES
|
|
|
406
406
|
$ opal set-token
|
|
407
407
|
```
|
|
408
408
|
|
|
409
|
-
_See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
409
|
+
_See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/set-token.ts)_
|
|
410
410
|
|
|
411
411
|
## `opal set-url [URL]`
|
|
412
412
|
|
|
@@ -430,7 +430,7 @@ EXAMPLES
|
|
|
430
430
|
$ opal set-url
|
|
431
431
|
```
|
|
432
432
|
|
|
433
|
-
_See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
433
|
+
_See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/set-url.ts)_
|
|
434
434
|
|
|
435
435
|
## `opal ssh copyFrom`
|
|
436
436
|
|
|
@@ -461,7 +461,7 @@ EXAMPLES
|
|
|
461
461
|
$ opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
462
462
|
```
|
|
463
463
|
|
|
464
|
-
_See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
464
|
+
_See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/ssh/copyFrom.ts)_
|
|
465
465
|
|
|
466
466
|
## `opal ssh copyTo`
|
|
467
467
|
|
|
@@ -492,7 +492,7 @@ EXAMPLES
|
|
|
492
492
|
$ opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
493
493
|
```
|
|
494
494
|
|
|
495
|
-
_See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
495
|
+
_See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/ssh/copyTo.ts)_
|
|
496
496
|
|
|
497
497
|
## `opal ssh start`
|
|
498
498
|
|
|
@@ -519,7 +519,7 @@ EXAMPLES
|
|
|
519
519
|
$ opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398
|
|
520
520
|
```
|
|
521
521
|
|
|
522
|
-
_See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.
|
|
522
|
+
_See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v3.1.1-beta.8a533e4/src/commands/ssh/start.ts)_
|
|
523
523
|
|
|
524
524
|
## `opal version`
|
|
525
525
|
|
|
@@ -18,7 +18,7 @@ class RequestCreate extends core_1.Command {
|
|
|
18
18
|
await (0, requests_1.selectRequestableItems)(this, client, metadata.requestMap);
|
|
19
19
|
// Step 2: Display the selected items in a tree format
|
|
20
20
|
(0, displays_1.headerMessage)(this);
|
|
21
|
-
|
|
21
|
+
(0, displays_1.treeifyRequestMap)(this, metadata.requestMap);
|
|
22
22
|
// Step 3: Prompt to add more items, repeat 1-3 if needed
|
|
23
23
|
shouldProceed = await (0, requests_1.doneSelectingAssets)();
|
|
24
24
|
}
|
|
@@ -66,7 +66,7 @@ class ListRequests extends core_1.Command {
|
|
|
66
66
|
let showPendingOnly = false;
|
|
67
67
|
const { flags } = await this.parse(ListRequests);
|
|
68
68
|
if (flags.n) {
|
|
69
|
-
pageSize = flags.
|
|
69
|
+
pageSize = flags.n;
|
|
70
70
|
}
|
|
71
71
|
if (flags.showPendingOnly) {
|
|
72
72
|
showPendingOnly = flags.showPendingOnly;
|
|
@@ -84,7 +84,7 @@ class ListRequests extends core_1.Command {
|
|
|
84
84
|
(0, apollo_1.printResponse)(this, resp);
|
|
85
85
|
}
|
|
86
86
|
else {
|
|
87
|
-
(0, displays_1.
|
|
87
|
+
(0, displays_1.displayRequestListTable)(this, resp);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
package/lib/lib/requests.js
CHANGED
|
@@ -89,13 +89,12 @@ async function queryRequestableApps(cmd, client, input) {
|
|
|
89
89
|
default:
|
|
90
90
|
type = edge.node.__typename;
|
|
91
91
|
}
|
|
92
|
-
const label = `${edge.node.displayName} (${type})`;
|
|
93
92
|
return {
|
|
94
|
-
message:
|
|
93
|
+
message: `${edge.node.displayName} [${type}]`,
|
|
95
94
|
value: {
|
|
96
95
|
id: edge.node.id,
|
|
97
|
-
name:
|
|
98
|
-
toString: () =>
|
|
96
|
+
name: edge.node.displayName,
|
|
97
|
+
toString: () => edge.node.displayName,
|
|
99
98
|
},
|
|
100
99
|
};
|
|
101
100
|
});
|
|
@@ -162,11 +161,10 @@ async function queryRequestableAssets(cmd, client, appId, input) {
|
|
|
162
161
|
const name = ((_a = item.resource) === null || _a === void 0 ? void 0 : _a.name) || ((_b = item.group) === null || _b === void 0 ? void 0 : _b.name);
|
|
163
162
|
const id = ((_c = item.resource) === null || _c === void 0 ? void 0 : _c.id) || ((_d = item.group) === null || _d === void 0 ? void 0 : _d.id);
|
|
164
163
|
const type = ((_e = item.resource) === null || _e === void 0 ? void 0 : _e.__typename) || ((_f = item.group) === null || _f === void 0 ? void 0 : _f.__typename);
|
|
165
|
-
const label = `${name} (${type})`;
|
|
166
164
|
return {
|
|
167
|
-
message:
|
|
165
|
+
message: `${name} [${type}]`,
|
|
168
166
|
value: {
|
|
169
|
-
name:
|
|
167
|
+
name: name || "",
|
|
170
168
|
id: id || "",
|
|
171
169
|
type: ((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename) || "",
|
|
172
170
|
},
|
|
@@ -428,57 +426,56 @@ async function createRequest(cmd, client, requestedResources, requestedGroups, r
|
|
|
428
426
|
durationInMinutes: durationInMinutes,
|
|
429
427
|
},
|
|
430
428
|
});
|
|
431
|
-
let x;
|
|
432
429
|
switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.createRequest.__typename) {
|
|
433
430
|
case "CreateRequestResult":
|
|
434
431
|
return (_b = resp.data) === null || _b === void 0 ? void 0 : _b.createRequest.request;
|
|
435
432
|
case "RequestDurationTooLargeError":
|
|
436
|
-
|
|
433
|
+
cmd.log((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
|
|
437
434
|
break;
|
|
438
435
|
case "RequestRequiresUserAuthTokenForConnectionError":
|
|
439
|
-
|
|
436
|
+
cmd.log((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
|
|
440
437
|
break;
|
|
441
438
|
case "NoReviewersSetForOwnerError":
|
|
442
|
-
|
|
439
|
+
cmd.log((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
|
|
443
440
|
break;
|
|
444
441
|
case "NoReviewersSetForResourceError":
|
|
445
|
-
|
|
442
|
+
cmd.log((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
|
|
446
443
|
break;
|
|
447
444
|
case "NoReviewersSetForGroupError":
|
|
448
|
-
|
|
445
|
+
cmd.log((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
|
|
449
446
|
break;
|
|
450
447
|
case "NoManagerSetForRequestingUserError":
|
|
451
|
-
|
|
448
|
+
cmd.log((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
|
|
452
449
|
break;
|
|
453
450
|
case "MfaInvalidError":
|
|
454
|
-
|
|
451
|
+
cmd.log((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
|
|
455
452
|
break;
|
|
456
453
|
case "BulkRequestTooLargeError":
|
|
457
|
-
|
|
454
|
+
cmd.log((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
|
|
458
455
|
break;
|
|
459
456
|
case "ItemCannotBeRequestedError":
|
|
460
|
-
|
|
457
|
+
cmd.log((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
|
|
461
458
|
break;
|
|
462
459
|
case "UserCannotRequestAccessForTargetGroupError":
|
|
463
|
-
|
|
460
|
+
cmd.log((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
|
|
464
461
|
break;
|
|
465
462
|
case "GroupNestingNotAllowedError":
|
|
466
|
-
|
|
463
|
+
cmd.log((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
|
|
467
464
|
break;
|
|
468
465
|
case "TargetUserHasNestedAccessError":
|
|
469
|
-
|
|
466
|
+
cmd.log((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
|
|
470
467
|
break;
|
|
471
468
|
case "RequestReasonMissingError":
|
|
472
|
-
|
|
469
|
+
cmd.log((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
|
|
473
470
|
break;
|
|
474
471
|
case "RequestFieldValueMissingError":
|
|
475
|
-
|
|
472
|
+
cmd.log((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
|
|
476
473
|
break;
|
|
477
474
|
case "LinkedGroupNotRequestableError":
|
|
478
|
-
|
|
475
|
+
cmd.log((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
|
|
479
476
|
break;
|
|
480
477
|
case "RequestReasonBelowMinLengthError":
|
|
481
|
-
|
|
478
|
+
cmd.log((_t = resp.data) === null || _t === void 0 ? void 0 : _t.createRequest.message);
|
|
482
479
|
break;
|
|
483
480
|
}
|
|
484
481
|
}
|
|
@@ -665,10 +662,16 @@ async function promptForReason(metadata) {
|
|
|
665
662
|
async function promptForExpiration(metadata) {
|
|
666
663
|
var _a, _b;
|
|
667
664
|
const durations = ((_b = (_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.durationOptions) === null || _b === void 0 ? void 0 : _b.map((option) => {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
:
|
|
665
|
+
var _a;
|
|
666
|
+
let label = option.label;
|
|
667
|
+
if (option.durationInMinutes ===
|
|
668
|
+
((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes)) {
|
|
669
|
+
label = `${label} (MAX)`;
|
|
670
|
+
}
|
|
671
|
+
if (option.durationInMinutes ===
|
|
672
|
+
metadata.requestDefaults.recommendedDurationInMinutes) {
|
|
673
|
+
label = `${label} (RECOMMENDED)`;
|
|
674
|
+
}
|
|
672
675
|
return {
|
|
673
676
|
message: label,
|
|
674
677
|
value: {
|
|
@@ -690,7 +693,7 @@ async function promptForExpiration(metadata) {
|
|
|
690
693
|
let selected = await expirationSelect.run();
|
|
691
694
|
switch (selected.label) {
|
|
692
695
|
case "Custom": {
|
|
693
|
-
selected = await setCustomDuration();
|
|
696
|
+
selected = await setCustomDuration(metadata);
|
|
694
697
|
break;
|
|
695
698
|
}
|
|
696
699
|
case "Permanent": {
|
|
@@ -701,7 +704,36 @@ async function promptForExpiration(metadata) {
|
|
|
701
704
|
metadata.durationInMinutes = selected.durationInMinutes;
|
|
702
705
|
metadata.durationLabel = selected.label;
|
|
703
706
|
}
|
|
704
|
-
|
|
707
|
+
function getDurationNumbers(duration) {
|
|
708
|
+
const d = +duration.days || 0;
|
|
709
|
+
const h = +duration.hours || 0;
|
|
710
|
+
const m = +duration.minutes || 0;
|
|
711
|
+
return { d, h, m };
|
|
712
|
+
}
|
|
713
|
+
function getDurationInMinutes(duration) {
|
|
714
|
+
const { d, h, m } = getDurationNumbers(duration);
|
|
715
|
+
const minutesInDay = 1440; // 24 hours * 60 minutes
|
|
716
|
+
const minutesInHour = 60;
|
|
717
|
+
return d * minutesInDay + h * minutesInHour + m;
|
|
718
|
+
}
|
|
719
|
+
function getDHMFromMinutes(minutes) {
|
|
720
|
+
const label = [];
|
|
721
|
+
const d = Math.floor(minutes / 1440);
|
|
722
|
+
if (d > 0) {
|
|
723
|
+
label.push(`${d}d`);
|
|
724
|
+
}
|
|
725
|
+
const remainingMinutes = minutes % 1440;
|
|
726
|
+
const h = Math.floor(remainingMinutes / 60);
|
|
727
|
+
if (h > 0) {
|
|
728
|
+
label.push(`${h}h`);
|
|
729
|
+
}
|
|
730
|
+
const m = remainingMinutes % 60;
|
|
731
|
+
if (m > 0) {
|
|
732
|
+
label.push(`${m}m`);
|
|
733
|
+
}
|
|
734
|
+
return label.join(" ");
|
|
735
|
+
}
|
|
736
|
+
async function setCustomDuration(metadata) {
|
|
705
737
|
const durationForm = new Form({
|
|
706
738
|
name: "user",
|
|
707
739
|
message: "Please set a custom access duration:",
|
|
@@ -711,31 +743,27 @@ async function setCustomDuration() {
|
|
|
711
743
|
{ name: "minutes", message: "Minutes", initial: "0" },
|
|
712
744
|
],
|
|
713
745
|
validate: (answer) => {
|
|
714
|
-
|
|
715
|
-
const
|
|
716
|
-
const
|
|
717
|
-
if (
|
|
718
|
-
hours < 0 ||
|
|
719
|
-
minutes < 0 ||
|
|
720
|
-
(days === 0 && hours === 0 && minutes === 0)) {
|
|
746
|
+
var _a, _b, _c;
|
|
747
|
+
const { d, h, m } = getDurationNumbers(answer);
|
|
748
|
+
const durationInMinutes = getDurationInMinutes(answer);
|
|
749
|
+
if (d < 0 || h < 0 || m < 0 || d + h + m > 0 || (h > 23 && m > 59)) {
|
|
721
750
|
return "Please enter a valid duration.";
|
|
722
751
|
}
|
|
752
|
+
if (((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes) &&
|
|
753
|
+
durationInMinutes > ((_b = metadata.requestDefaults) === null || _b === void 0 ? void 0 : _b.maxDurationInMinutes)) {
|
|
754
|
+
const maxDHM = getDHMFromMinutes((_c = metadata.requestDefaults) === null || _c === void 0 ? void 0 : _c.maxDurationInMinutes);
|
|
755
|
+
return `The max duration for the selected assets is ${maxDHM}.`;
|
|
756
|
+
}
|
|
723
757
|
return true;
|
|
724
758
|
},
|
|
759
|
+
return: (answer) => {
|
|
760
|
+
return getDurationInMinutes(answer);
|
|
761
|
+
},
|
|
725
762
|
});
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
const durationInMinutes =
|
|
729
|
-
|
|
730
|
-
if (duration.days > 0) {
|
|
731
|
-
durationLabel += `${duration.days}d `;
|
|
732
|
-
}
|
|
733
|
-
if (duration.hours > 0) {
|
|
734
|
-
durationLabel += `${duration.hours}h `;
|
|
735
|
-
}
|
|
736
|
-
if (duration.minutes > 0) {
|
|
737
|
-
durationLabel += `${duration.minutes}m`;
|
|
738
|
-
}
|
|
763
|
+
const durationResult = await durationForm.run();
|
|
764
|
+
const { d, h, m } = getDurationNumbers(durationResult);
|
|
765
|
+
const durationInMinutes = getDurationInMinutes(durationResult);
|
|
766
|
+
const durationLabel = getDHMFromMinutes(durationInMinutes);
|
|
739
767
|
return {
|
|
740
768
|
durationInMinutes: durationInMinutes,
|
|
741
769
|
label: durationLabel,
|
package/lib/utils/displays.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { Command } from "@oclif/core/lib/command";
|
|
|
3
3
|
import type { GetRequestQuery, GetRequestsQuery } from "../graphql/graphql";
|
|
4
4
|
import type { RequestMap, RequestMetadata } from "../lib/requests";
|
|
5
5
|
export declare function headerMessage(cmd: Command): void;
|
|
6
|
-
export declare function treeifyRequestMap(requestMap: RequestMap):
|
|
6
|
+
export declare function treeifyRequestMap(cmd: Command, requestMap: RequestMap): void;
|
|
7
7
|
export declare function displayFinalRequestSummary(cmd: Command, metadata: RequestMetadata): void;
|
|
8
8
|
export declare function getStyledStatus(status: string): string;
|
|
9
9
|
export declare function displayRequestDetails(cmd: Command, requestResp: ApolloQueryResult<GetRequestQuery>): void;
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function displayRequestListTable(cmd: Command, requestResp: ApolloQueryResult<GetRequestsQuery>): void;
|
package/lib/utils/displays.js
CHANGED
|
@@ -5,67 +5,64 @@ exports.treeifyRequestMap = treeifyRequestMap;
|
|
|
5
5
|
exports.displayFinalRequestSummary = displayFinalRequestSummary;
|
|
6
6
|
exports.getStyledStatus = getStyledStatus;
|
|
7
7
|
exports.displayRequestDetails = displayRequestDetails;
|
|
8
|
-
exports.
|
|
8
|
+
exports.displayRequestListTable = displayRequestListTable;
|
|
9
9
|
const chalk_1 = require("chalk");
|
|
10
|
-
const treeify = require("object-treeify");
|
|
11
10
|
const Table = require("cli-table3");
|
|
12
|
-
const
|
|
13
|
-
top: "═",
|
|
14
|
-
"top-mid": "╤",
|
|
15
|
-
"top-left": "╔",
|
|
16
|
-
"top-right": "╗",
|
|
17
|
-
bottom: "═",
|
|
18
|
-
"bottom-mid": "╧",
|
|
19
|
-
"bottom-left": "╚",
|
|
20
|
-
"bottom-right": "╝",
|
|
21
|
-
left: "║",
|
|
22
|
-
"left-mid": "╟",
|
|
23
|
-
mid: "─",
|
|
24
|
-
"mid-mid": "┼",
|
|
25
|
-
right: "║",
|
|
26
|
-
"right-mid": "╢",
|
|
27
|
-
middle: "│",
|
|
28
|
-
};
|
|
11
|
+
const treeify = require("object-treeify").default;
|
|
29
12
|
function headerMessage(cmd) {
|
|
30
13
|
console.clear();
|
|
31
14
|
cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
32
15
|
cmd.log("Opal Access Request ✏️");
|
|
33
16
|
cmd.log("Press Ctrl+C to cancel at any time.\n");
|
|
34
17
|
}
|
|
35
|
-
function treeifyRequestMap(requestMap) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
18
|
+
function treeifyRequestMap(cmd, requestMap) {
|
|
19
|
+
// Configuration options for treeify
|
|
20
|
+
const options = {
|
|
21
|
+
joined: true,
|
|
22
|
+
spacerNoNeighbour: " ",
|
|
23
|
+
spacerNeighbour: "│ ",
|
|
24
|
+
keyNoNeighbour: "└── ",
|
|
25
|
+
keyNeighbour: "├── ",
|
|
26
|
+
separator: "",
|
|
27
|
+
};
|
|
39
28
|
for (const [_appId, appNode] of Object.entries(requestMap)) {
|
|
40
|
-
const
|
|
41
|
-
requestTree[appKey] = {}; // Initialize the app key
|
|
42
|
-
// Iterate over assets
|
|
29
|
+
const assetsTree = {};
|
|
43
30
|
for (const [_assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
44
|
-
const assetKey =
|
|
31
|
+
const assetKey = `${assetNode.assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
|
|
45
32
|
if (assetNode.roles !== undefined) {
|
|
46
|
-
|
|
47
|
-
requestTree[appKey][assetKey] = {}; // Initialize the asset key
|
|
48
|
-
// Iterate over roles
|
|
33
|
+
assetsTree[assetKey] = {};
|
|
49
34
|
for (const [_roleId, roleNode] of Object.entries(assetNode.roles)) {
|
|
50
|
-
|
|
35
|
+
const roleKey = `${roleNode.roleName} ${chalk_1.default.dim("[Role]")}`;
|
|
36
|
+
assetsTree[assetKey][roleKey] = null;
|
|
51
37
|
}
|
|
52
38
|
}
|
|
53
39
|
else {
|
|
54
|
-
|
|
40
|
+
assetsTree[assetKey] = null;
|
|
55
41
|
}
|
|
56
42
|
}
|
|
43
|
+
// Render tree for this app's assets
|
|
44
|
+
const assetsTreeString = treeify(assetsTree, options);
|
|
45
|
+
// Print App title first (without tree lines)
|
|
46
|
+
cmd.log(`${chalk_1.default.bold(appNode.appName)} ${chalk_1.default.dim("[App]")}`);
|
|
47
|
+
// Print its assets/roles indented underneath
|
|
48
|
+
cmd.log(assetsTreeString);
|
|
57
49
|
}
|
|
58
|
-
|
|
50
|
+
cmd.log();
|
|
59
51
|
}
|
|
60
52
|
function displayFinalRequestSummary(cmd, metadata) {
|
|
61
|
-
|
|
62
|
-
cmd.log("
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
cmd.log(
|
|
53
|
+
console.clear();
|
|
54
|
+
cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
55
|
+
cmd.log("Final Summary of Request ✏️");
|
|
56
|
+
cmd.log("Press Ctrl+C to cancel at any time.\n");
|
|
57
|
+
cmd.log();
|
|
58
|
+
treeifyRequestMap(cmd, metadata.requestMap);
|
|
59
|
+
const durationInMinutes = metadata.durationInMinutes;
|
|
60
|
+
cmd.log(`Duration: ${durationInMinutes ? formatDuration(durationInMinutes) : "Permanent"}`);
|
|
61
|
+
const reason = metadata.reason;
|
|
62
|
+
if (reason) {
|
|
63
|
+
cmd.log(`Reason: "${chalk_1.default.italic(reason)}"`);
|
|
64
|
+
}
|
|
65
|
+
cmd.log();
|
|
69
66
|
}
|
|
70
67
|
function getStyledStatus(status) {
|
|
71
68
|
switch (status) {
|
|
@@ -102,9 +99,7 @@ function displayRequestDetails(cmd, requestResp) {
|
|
|
102
99
|
cmd.log(`${chalk_1.default.bold("Requested by:")} ${requester} ${chalk_1.default.gray("->")} ${chalk_1.default.bold("Requested for:")} ${targetUser}`);
|
|
103
100
|
}
|
|
104
101
|
const durationInMinutes = requestResp.data.request.request.durationInMinutes;
|
|
105
|
-
|
|
106
|
-
cmd.log(`${chalk_1.default.bold("Duration:")} ${formatDuration(durationInMinutes)}`);
|
|
107
|
-
}
|
|
102
|
+
cmd.log(`${chalk_1.default.bold("Duration:")} ${durationInMinutes ? formatDuration(durationInMinutes) : "Permanent"}`);
|
|
108
103
|
const reason = requestResp.data.request.request.reason;
|
|
109
104
|
if (reason) {
|
|
110
105
|
cmd.log(`${chalk_1.default.bold("Reason:")} "${chalk_1.default.italic(reason)}"`);
|
|
@@ -129,14 +124,13 @@ function displayRequestDetails(cmd, requestResp) {
|
|
|
129
124
|
}
|
|
130
125
|
}
|
|
131
126
|
}
|
|
132
|
-
function
|
|
127
|
+
function displayRequestListTable(cmd, requestResp) {
|
|
133
128
|
var _a, _b, _c, _d, _e;
|
|
134
129
|
switch (requestResp.data.requests.__typename) {
|
|
135
130
|
case "RequestsResult": {
|
|
136
131
|
const requests = requestResp.data.requests.requests;
|
|
137
132
|
if (requests && requests.length > 0) {
|
|
138
133
|
const table = new Table({
|
|
139
|
-
chars: tableStyle,
|
|
140
134
|
head: [
|
|
141
135
|
"Request ID",
|
|
142
136
|
"Status",
|
|
@@ -153,10 +147,9 @@ function displayRequestList(cmd, requestResp) {
|
|
|
153
147
|
const targetUser = (_a = request.targetUser) === null || _a === void 0 ? void 0 : _a.displayName;
|
|
154
148
|
const reason = request.reason;
|
|
155
149
|
const status = request.status;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
150
|
+
const formattedDuration = request.durationInMinutes
|
|
151
|
+
? formatDuration(request.durationInMinutes)
|
|
152
|
+
: "Permanent";
|
|
160
153
|
const requestedResources = (_c = (_b = request.requestedResources) === null || _b === void 0 ? void 0 : _b.map((resource) => {
|
|
161
154
|
var _a, _b, _c;
|
|
162
155
|
if (((_a = resource.resource) === null || _a === void 0 ? void 0 : _a.__typename) === "Resource") {
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opal-security",
|
|
3
3
|
"description": "Opal allows you to centrally manage access to all of your sensitive systems.",
|
|
4
|
-
"version": "3.1.1-beta.
|
|
4
|
+
"version": "3.1.1-beta.8a533e4",
|
|
5
5
|
"author": "Stephen Cobbe",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opal": "./bin/run"
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"lodash": "^4.17.21",
|
|
25
25
|
"moment": "^2.30.1",
|
|
26
26
|
"node-fetch": "^2.6.7",
|
|
27
|
+
"object-treeify": "^5.0.1",
|
|
27
28
|
"open": "^8.0.4",
|
|
28
29
|
"openid-client": "^5.6.5",
|
|
29
30
|
"prettyjson": "^1.2.1",
|