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 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.7648ca2 linux-x64 node-v20.19.2
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.7648ca2/src/commands/aws/identity.ts)_
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.7648ca2/src/commands/clear-auth-provider.ts)_
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.7648ca2/src/commands/curl-example.ts)_
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.7648ca2/src/commands/groups/get.ts)_
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.7648ca2/src/commands/iam-roles/start.ts)_
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.7648ca2/src/commands/kube-roles/start.ts)_
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.7648ca2/src/commands/login.ts)_
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.7648ca2/src/commands/logout.ts)_
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.7648ca2/src/commands/postgres-instances/start.ts)_
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.7648ca2/src/commands/resources/get.ts)_
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.7648ca2/src/commands/set-auth-provider.ts)_
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.7648ca2/src/commands/set-custom-header.ts)_
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.7648ca2/src/commands/set-token.ts)_
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.7648ca2/src/commands/set-url.ts)_
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.7648ca2/src/commands/ssh/copyFrom.ts)_
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.7648ca2/src/commands/ssh/copyTo.ts)_
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.7648ca2/src/commands/ssh/start.ts)_
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
- this.log((0, displays_1.treeifyRequestMap)(metadata.requestMap), "\n");
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.pageSinze;
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.displayRequestList)(this, resp);
87
+ (0, displays_1.displayRequestListTable)(this, resp);
88
88
  }
89
89
  }
90
90
  }
@@ -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: label,
93
+ message: `${edge.node.displayName} [${type}]`,
95
94
  value: {
96
95
  id: edge.node.id,
97
- name: label,
98
- toString: () => label,
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: label,
165
+ message: `${name} [${type}]`,
168
166
  value: {
169
- name: label || "",
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
- x = cmd.error((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
433
+ cmd.log((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
437
434
  break;
438
435
  case "RequestRequiresUserAuthTokenForConnectionError":
439
- x = cmd.error((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
436
+ cmd.log((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
440
437
  break;
441
438
  case "NoReviewersSetForOwnerError":
442
- x = cmd.error((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
439
+ cmd.log((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
443
440
  break;
444
441
  case "NoReviewersSetForResourceError":
445
- x = cmd.error((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
442
+ cmd.log((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
446
443
  break;
447
444
  case "NoReviewersSetForGroupError":
448
- x = cmd.error((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
445
+ cmd.log((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
449
446
  break;
450
447
  case "NoManagerSetForRequestingUserError":
451
- x = cmd.error((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
448
+ cmd.log((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
452
449
  break;
453
450
  case "MfaInvalidError":
454
- x = cmd.error((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
451
+ cmd.log((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
455
452
  break;
456
453
  case "BulkRequestTooLargeError":
457
- x = cmd.error((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
454
+ cmd.log((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
458
455
  break;
459
456
  case "ItemCannotBeRequestedError":
460
- x = cmd.error((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
457
+ cmd.log((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
461
458
  break;
462
459
  case "UserCannotRequestAccessForTargetGroupError":
463
- x = cmd.error((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
460
+ cmd.log((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
464
461
  break;
465
462
  case "GroupNestingNotAllowedError":
466
- x = cmd.error((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
463
+ cmd.log((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
467
464
  break;
468
465
  case "TargetUserHasNestedAccessError":
469
- x = cmd.error((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
466
+ cmd.log((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
470
467
  break;
471
468
  case "RequestReasonMissingError":
472
- x = cmd.error((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
469
+ cmd.log((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
473
470
  break;
474
471
  case "RequestFieldValueMissingError":
475
- x = cmd.error((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
472
+ cmd.log((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
476
473
  break;
477
474
  case "LinkedGroupNotRequestableError":
478
- x = cmd.error((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
475
+ cmd.log((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
479
476
  break;
480
477
  case "RequestReasonBelowMinLengthError":
481
- x = cmd.error((_t = resp.data) === null || _t === void 0 ? void 0 : _t.createRequest.message);
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
- const label = option.durationInMinutes ===
669
- metadata.requestDefaults.recommendedDurationInMinutes
670
- ? `${option.label} (Recommended)`
671
- : option.label;
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
- async function setCustomDuration() {
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
- const days = Number.parseInt(answer.days);
715
- const hours = Number.parseInt(answer.hours);
716
- const minutes = Number.parseInt(answer.minutes);
717
- if (days < 0 ||
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 duration = await durationForm.run();
727
- // Convert to minutes, define the new custom label
728
- const durationInMinutes = duration.days * 1440 + duration.hours * 60 + duration.minutes;
729
- let durationLabel = "";
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,
@@ -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): string;
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 displayRequestList(cmd: Command, requestResp: ApolloQueryResult<GetRequestsQuery>): void;
10
+ export declare function displayRequestListTable(cmd: Command, requestResp: ApolloQueryResult<GetRequestsQuery>): void;
@@ -5,67 +5,64 @@ exports.treeifyRequestMap = treeifyRequestMap;
5
5
  exports.displayFinalRequestSummary = displayFinalRequestSummary;
6
6
  exports.getStyledStatus = getStyledStatus;
7
7
  exports.displayRequestDetails = displayRequestDetails;
8
- exports.displayRequestList = displayRequestList;
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 tableStyle = {
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
- const requestTree = {};
37
- // Create a tree structure from the requestMap
38
- // Iterate over apps
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 appKey = `🔧${appNode.appName}`;
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 = `📦${assetNode.assetName}`;
31
+ const assetKey = `${assetNode.assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
45
32
  if (assetNode.roles !== undefined) {
46
- // If no roles were previously selected
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
- requestTree[appKey][assetKey][roleNode.roleName] = null; // Initialize the role key
35
+ const roleKey = `${roleNode.roleName} ${chalk_1.default.dim("[Role]")}`;
36
+ assetsTree[assetKey][roleKey] = null;
51
37
  }
52
38
  }
53
39
  else {
54
- requestTree[appKey][assetKey] = null;
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
- return String(treeify(requestTree));
50
+ cmd.log();
59
51
  }
60
52
  function displayFinalRequestSummary(cmd, metadata) {
61
- headerMessage(cmd);
62
- cmd.log("Final Summary of Request\n");
63
- const requestedAssets = treeifyRequestMap(metadata.requestMap);
64
- const table = new Table({
65
- chars: tableStyle,
66
- });
67
- table.push(["Requested Assets", requestedAssets], ["Reason", metadata.reason], ["Expiration", metadata.durationLabel]);
68
- cmd.log(table.toString());
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
- if (durationInMinutes) {
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 displayRequestList(cmd, requestResp) {
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
- let formattedDuration = "";
157
- if (request.durationInMinutes) {
158
- formattedDuration = formatDuration(request.durationInMinutes);
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") {
@@ -971,5 +971,5 @@
971
971
  ]
972
972
  }
973
973
  },
974
- "version": "3.1.1-beta.7648ca2"
974
+ "version": "3.1.1-beta.8a533e4"
975
975
  }
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.7648ca2",
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",