opal-security 3.1.1-beta.4dbd858 → 3.1.1-beta.4e22fcc

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.
@@ -1,8 +1,10 @@
1
1
  import type { ApolloQueryResult } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core/lib/command";
3
- import type { GetRequestQuery } from "../graphql/graphql";
4
- import type { RequestMap } from "../lib/requests";
3
+ import type { GetRequestQuery, GetRequestsQuery } from "../graphql/graphql";
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;
7
- export declare function displayFinalRequestSummary(cmd: Command, requestMap: RequestMap, reason: string, expiration: string): void;
6
+ export declare function treeifyRequestMap(cmd: Command, requestMap: RequestMap): void;
7
+ export declare function displayFinalRequestSummary(cmd: Command, metadata: RequestMetadata): void;
8
+ export declare function getStyledStatus(status: string): string;
8
9
  export declare function displayRequestDetails(cmd: Command, requestResp: ApolloQueryResult<GetRequestQuery>): void;
10
+ export declare function displayRequestListTable(cmd: Command, requestResp: ApolloQueryResult<GetRequestsQuery>): void;
@@ -3,115 +3,216 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.headerMessage = headerMessage;
4
4
  exports.treeifyRequestMap = treeifyRequestMap;
5
5
  exports.displayFinalRequestSummary = displayFinalRequestSummary;
6
+ exports.getStyledStatus = getStyledStatus;
6
7
  exports.displayRequestDetails = displayRequestDetails;
7
- const prettyjson_1 = require("prettyjson");
8
- const treeify = require("object-treeify");
8
+ exports.displayRequestListTable = displayRequestListTable;
9
+ const chalk_1 = require("chalk");
9
10
  const Table = require("cli-table3");
10
- const tableStyle = {
11
- top: "═",
12
- "top-mid": "╤",
13
- "top-left": "╔",
14
- "top-right": "╗",
15
- bottom: "═",
16
- "bottom-mid": "╧",
17
- "bottom-left": "╚",
18
- "bottom-right": "╝",
19
- left: "║",
20
- "left-mid": "╟",
21
- mid: "─",
22
- "mid-mid": "┼",
23
- right: "║",
24
- "right-mid": "╢",
25
- middle: "│",
26
- };
11
+ const treeify = require("object-treeify").default;
27
12
  function headerMessage(cmd) {
28
13
  console.clear();
29
- cmd.log("============================================================");
14
+ cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
30
15
  cmd.log("Opal Access Request ✏️");
31
16
  cmd.log("Press Ctrl+C to cancel at any time.\n");
32
17
  }
33
- function treeifyRequestMap(requestMap) {
34
- const requestTree = {};
35
- // Create a tree structure from the requestMap
36
- // 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
+ };
37
28
  for (const [_appId, appNode] of Object.entries(requestMap)) {
38
- const appKey = `🔧${appNode.appName}`;
39
- requestTree[appKey] = {}; // Initialize the app key
40
- // Iterate over assets
29
+ const assetsTree = {};
41
30
  for (const [_assetId, assetNode] of Object.entries(appNode.assets)) {
42
- const assetKey = `📦${assetNode.assetName}`;
31
+ // If okta/azure asset with no role, change asset name
32
+ const assetName = assetNode.assetName || "No Role (Direct access)";
33
+ const assetKey = `${assetName} ${chalk_1.default.dim(`[${assetNode.type}]`)}`;
43
34
  if (assetNode.roles !== undefined) {
44
- // If no roles were previously selected
45
- requestTree[appKey][assetKey] = {}; // Initialize the asset key
46
- // Iterate over roles
35
+ assetsTree[assetKey] = {};
47
36
  for (const [_roleId, roleNode] of Object.entries(assetNode.roles)) {
48
- requestTree[appKey][assetKey][roleNode.roleName] = null; // Initialize the role key
37
+ const roleName = roleNode.roleName;
38
+ if (roleName !== "") {
39
+ const roleKey = `${roleName} ${chalk_1.default.dim("[Role]")}`;
40
+ assetsTree[assetKey][roleKey] = null;
41
+ }
49
42
  }
50
43
  }
51
44
  else {
52
- requestTree[appKey][assetKey] = null;
45
+ assetsTree[assetKey] = null;
53
46
  }
54
47
  }
48
+ // Render tree for this app's assets
49
+ const assetsTreeString = treeify(assetsTree, options);
50
+ // Print App title first (without tree lines)
51
+ cmd.log(`${chalk_1.default.bold(appNode.appName)} ${chalk_1.default.dim("[App]")}`);
52
+ // Print its assets/roles indented underneath
53
+ cmd.log(assetsTreeString);
55
54
  }
56
- return String(treeify(requestTree));
55
+ cmd.log();
57
56
  }
58
- function displayFinalRequestSummary(cmd, requestMap, reason, expiration) {
59
- headerMessage(cmd);
60
- cmd.log("Final Summary of Request\n");
61
- const requestedAssets = treeifyRequestMap(requestMap);
62
- const table = new Table({
63
- chars: tableStyle,
64
- });
65
- table.push(["Requested Assets", requestedAssets], ["Reason", reason], ["Expiration", expiration]);
66
- cmd.log(table.toString());
57
+ function displayFinalRequestSummary(cmd, metadata) {
58
+ console.clear();
59
+ cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
60
+ cmd.log("Final Summary of Request ✏️");
61
+ cmd.log("Press Ctrl+C to cancel at any time.\n");
62
+ cmd.log();
63
+ treeifyRequestMap(cmd, metadata.requestMap);
64
+ const durationInMinutes = metadata.durationInMinutes;
65
+ cmd.log(`Duration: ${durationInMinutes ? formatDuration(durationInMinutes) : "Permanent"}`);
66
+ const reason = metadata.reason;
67
+ if (reason) {
68
+ cmd.log(`Reason: "${chalk_1.default.italic(reason)}"`);
69
+ }
70
+ cmd.log();
71
+ }
72
+ function getStyledStatus(status) {
73
+ switch (status) {
74
+ case "PENDING": {
75
+ return `${chalk_1.default.bold("Status:")} ${chalk_1.default.blueBright(status)}`;
76
+ }
77
+ case "APPROVED": {
78
+ return `${chalk_1.default.bold("Status:")} ${chalk_1.default.greenBright(status)}`;
79
+ }
80
+ case "DENIED": {
81
+ return `${chalk_1.default.bold("Status:")} ${chalk_1.default.redBright(status)}`;
82
+ }
83
+ case "CANCELED": {
84
+ return `${chalk_1.default.bold("Status:")} ${chalk_1.default.redBright(status)}`;
85
+ }
86
+ default: {
87
+ return `${chalk_1.default.bold("Status:")} ${chalk_1.default.gray(status)}`;
88
+ }
89
+ }
67
90
  }
68
91
  function displayRequestDetails(cmd, requestResp) {
69
- var _a, _b;
70
- cmd.log("============================================================");
71
- cmd.log("Request Details\n");
92
+ var _a, _b, _c, _d, _e, _f;
72
93
  switch (requestResp.data.request.__typename) {
73
94
  case "RequestResult": {
95
+ cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
96
+ cmd.log(`Request Details ${chalk_1.default.cyan(requestResp.data.request.request.id)}`);
97
+ cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
98
+ const status = requestResp.data.request.request.status;
99
+ cmd.log(getStyledStatus(status));
100
+ // Request users "Requested by: <requester> -> Requested for: <targetUser>"
74
101
  const requester = (_a = requestResp.data.request.request.requester) === null || _a === void 0 ? void 0 : _a.displayName;
75
102
  const targetUser = (_b = requestResp.data.request.request.targetUser) === null || _b === void 0 ? void 0 : _b.displayName;
76
- const durationInMinutes = requestResp.data.request.request.durationInMinutes;
77
- cmd.log(`ID: ${requestResp.data.request.request.id}`);
78
- cmd.log(`STATUS: ${requestResp.data.request.request.status}`);
79
- if (requester) {
80
- cmd.log(`Requester: ${requester}`);
81
- }
82
- if (targetUser) {
83
- cmd.log(`Target: ${targetUser}`);
103
+ if (requester && targetUser) {
104
+ cmd.log(`${chalk_1.default.bold("Requested by:")} ${requester} ${chalk_1.default.gray("->")} ${chalk_1.default.bold("Requested for:")} ${targetUser}`);
84
105
  }
85
- if (durationInMinutes) {
86
- const days = Math.floor(durationInMinutes / 1440);
87
- const remainingMinutes = durationInMinutes % 1440;
88
- const hours = Math.floor(remainingMinutes / 60);
89
- const minutes = remainingMinutes % 60;
90
- let durationStr = "";
91
- if (days > 0)
92
- durationStr += `${days}d`;
93
- if (hours > 0)
94
- durationStr += `${hours}h`;
95
- if (minutes > 0)
96
- durationStr += `${minutes}m`;
97
- if (durationStr === "")
98
- durationStr = `${durationInMinutes}m`;
99
- durationStr += ` (${durationInMinutes}m)`;
100
- cmd.log(`\nDuration: ${durationStr}`);
106
+ const durationInMinutes = requestResp.data.request.request.durationInMinutes;
107
+ cmd.log(`${chalk_1.default.bold("Duration:")} ${durationInMinutes ? formatDuration(durationInMinutes) : "Permanent"}`);
108
+ const reason = requestResp.data.request.request.reason;
109
+ if (reason) {
110
+ cmd.log(`${chalk_1.default.bold("Reason:")} "${chalk_1.default.italic(reason)}"`);
101
111
  }
102
- const requestedResources = requestResp.data.request.request.requestedResources;
103
- const requestedGroups = requestResp.data.request.request.requestedGroups;
104
- if (requestedResources && requestedResources.length > 0) {
105
- cmd.log("\nRequested Resources:");
106
- cmd.log((0, prettyjson_1.render)(requestedResources));
112
+ // Requested resources
113
+ const requestedResources = (_d = (_c = requestResp.data.request.request.requestedResources) === null || _c === void 0 ? void 0 : _c.map((resource) => {
114
+ var _a, _b, _c;
115
+ if (((_a = resource.resource) === null || _a === void 0 ? void 0 : _a.__typename) === "Resource") {
116
+ return formatAssetName((_b = resource.resource) === null || _b === void 0 ? void 0 : _b.displayName, ((_c = resource.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
117
+ }
118
+ })) !== null && _d !== void 0 ? _d : [];
119
+ const requestedGroups = (_f = (_e = requestResp.data.request.request.requestedGroups) === null || _e === void 0 ? void 0 : _e.map((group) => {
120
+ var _a, _b, _c;
121
+ if (((_a = group.group) === null || _a === void 0 ? void 0 : _a.__typename) === "Group") {
122
+ return formatAssetName((_b = group.group) === null || _b === void 0 ? void 0 : _b.name, ((_c = group.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
123
+ }
124
+ })) !== null && _f !== void 0 ? _f : [];
125
+ const requestedItems = [...requestedResources, ...requestedGroups].join(", ");
126
+ if (requestedItems) {
127
+ cmd.log(`${chalk_1.default.bold("Requested Items:")} ${chalk_1.default.cyan(requestedItems)}`);
107
128
  }
108
- if (requestedGroups && requestedGroups.length > 0) {
109
- cmd.log("\nRequested Groups:");
110
- cmd.log((0, prettyjson_1.render)(requestedGroups));
129
+ }
130
+ }
131
+ }
132
+ function displayRequestListTable(cmd, requestResp) {
133
+ var _a, _b, _c, _d, _e;
134
+ switch (requestResp.data.requests.__typename) {
135
+ case "RequestsResult": {
136
+ const requests = requestResp.data.requests.requests;
137
+ if (requests && requests.length > 0) {
138
+ const table = new Table({
139
+ head: [
140
+ "Request ID",
141
+ "Status",
142
+ "For",
143
+ "Duration",
144
+ "Requested Items",
145
+ "Reason",
146
+ ],
147
+ colWidths: [null, null, 20, null, 30, 20],
148
+ wordWrap: true,
149
+ wrapOnWordBoundary: false,
150
+ });
151
+ for (const request of requests) {
152
+ const targetUser = (_a = request.targetUser) === null || _a === void 0 ? void 0 : _a.displayName;
153
+ const reason = request.reason;
154
+ const status = request.status;
155
+ const formattedDuration = request.durationInMinutes
156
+ ? formatDuration(request.durationInMinutes)
157
+ : "Permanent";
158
+ const requestedResources = (_c = (_b = request.requestedResources) === null || _b === void 0 ? void 0 : _b.map((resource) => {
159
+ var _a, _b, _c;
160
+ if (((_a = resource.resource) === null || _a === void 0 ? void 0 : _a.__typename) === "Resource") {
161
+ return formatAssetName((_b = resource.resource) === null || _b === void 0 ? void 0 : _b.displayName, ((_c = resource.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
162
+ }
163
+ })) !== null && _c !== void 0 ? _c : [];
164
+ const requestedGroups = (_e = (_d = request.requestedGroups) === null || _d === void 0 ? void 0 : _d.map((group) => {
165
+ var _a, _b, _c;
166
+ if (((_a = group.group) === null || _a === void 0 ? void 0 : _a.__typename) === "Group") {
167
+ return formatAssetName((_b = group.group) === null || _b === void 0 ? void 0 : _b.name, ((_c = group.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
168
+ }
169
+ })) !== null && _e !== void 0 ? _e : [];
170
+ const requestedItems = [
171
+ ...requestedResources,
172
+ ...requestedGroups,
173
+ ].join(", ");
174
+ table.push([
175
+ request.id,
176
+ status,
177
+ targetUser,
178
+ formattedDuration,
179
+ requestedItems,
180
+ reason,
181
+ ]);
182
+ }
183
+ cmd.log(table.toString());
111
184
  }
112
- if (requestResp.data.request.request.reason) {
113
- cmd.log(`\nReason: "${requestResp.data.request.request.reason}"`);
185
+ else {
186
+ cmd.log("No requests found.");
114
187
  }
188
+ return;
189
+ }
190
+ default: {
191
+ cmd.log("No requests found.");
115
192
  }
116
193
  }
117
194
  }
195
+ function formatDuration(durationInMinutes) {
196
+ const days = Math.floor(durationInMinutes / 1440);
197
+ const remainingMinutes = durationInMinutes % 1440;
198
+ const hours = Math.floor(remainingMinutes / 60);
199
+ const minutes = remainingMinutes % 60;
200
+ let durationStr = "";
201
+ if (days > 0)
202
+ durationStr += `${days}d`;
203
+ if (hours > 0)
204
+ durationStr += `${hours}h`;
205
+ if (minutes > 0)
206
+ durationStr += `${minutes}m`;
207
+ if (durationStr === "")
208
+ durationStr = `${durationInMinutes}m`;
209
+ durationStr += ` (${durationInMinutes}m)`;
210
+ return durationStr;
211
+ }
212
+ function formatAssetName(assetName, roleName) {
213
+ let str = `${assetName}`;
214
+ if (roleName) {
215
+ str += ` (${roleName})`;
216
+ }
217
+ return str;
218
+ }
@@ -365,7 +365,7 @@
365
365
  },
366
366
  "id": {
367
367
  "char": "i",
368
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
368
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
369
369
  "name": "id",
370
370
  "hasDynamicHelp": false,
371
371
  "multiple": false,
@@ -407,7 +407,7 @@
407
407
  },
408
408
  "id": {
409
409
  "char": "i",
410
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
410
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
411
411
  "name": "id",
412
412
  "hasDynamicHelp": false,
413
413
  "multiple": false,
@@ -471,7 +471,7 @@
471
471
  },
472
472
  "id": {
473
473
  "char": "i",
474
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
474
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
475
475
  "name": "id",
476
476
  "hasDynamicHelp": false,
477
477
  "multiple": false,
@@ -537,7 +537,7 @@
537
537
  },
538
538
  "id": {
539
539
  "char": "i",
540
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
540
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
541
541
  "name": "id",
542
542
  "hasDynamicHelp": false,
543
543
  "multiple": false,
@@ -597,8 +597,40 @@
597
597
  "request:create": {
598
598
  "aliases": [],
599
599
  "args": {},
600
- "description": "Opens an Opal access request",
601
- "flags": {},
600
+ "description": "Creates an Opal access request via an interactive form",
601
+ "flags": {
602
+ "help": {
603
+ "char": "h",
604
+ "description": "Show CLI help.",
605
+ "name": "help",
606
+ "allowNo": false,
607
+ "type": "boolean"
608
+ },
609
+ "id": {
610
+ "char": "i",
611
+ "description": "The id of the asset (resource, group) to request access to. Append a role ID using a colon if needed, e.g. `--id 123:456`. \n If not provided, an interactive selection flow will be available to select assets to request.",
612
+ "name": "id",
613
+ "hasDynamicHelp": false,
614
+ "multiple": true,
615
+ "type": "option"
616
+ },
617
+ "reason": {
618
+ "char": "r",
619
+ "description": "The reason for the request, contained in quotes. If not provided, you will be prompted.",
620
+ "name": "reason",
621
+ "hasDynamicHelp": false,
622
+ "multiple": false,
623
+ "type": "option"
624
+ },
625
+ "duration": {
626
+ "char": "d",
627
+ "description": "The duration of access for the request in minutes. If not provided, you will be prompted.",
628
+ "name": "duration",
629
+ "hasDynamicHelp": false,
630
+ "multiple": false,
631
+ "type": "option"
632
+ }
633
+ },
602
634
  "hasDynamicHelp": false,
603
635
  "hidden": true,
604
636
  "hiddenAliases": [],
@@ -620,6 +652,10 @@
620
652
  "aliases": [],
621
653
  "args": {},
622
654
  "description": "Lists access requests",
655
+ "examples": [
656
+ "opal request get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4",
657
+ "opal request get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4 --verbose"
658
+ ],
623
659
  "flags": {
624
660
  "help": {
625
661
  "char": "h",
@@ -630,11 +666,18 @@
630
666
  },
631
667
  "id": {
632
668
  "char": "i",
633
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
669
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
634
670
  "name": "id",
635
671
  "hasDynamicHelp": false,
636
672
  "multiple": false,
637
673
  "type": "option"
674
+ },
675
+ "verbose": {
676
+ "char": "v",
677
+ "description": "Enable verbose output, prints full response in JSON format. Defaults to false.",
678
+ "name": "verbose",
679
+ "allowNo": false,
680
+ "type": "boolean"
638
681
  }
639
682
  },
640
683
  "hasDynamicHelp": false,
@@ -657,8 +700,45 @@
657
700
  "request:list": {
658
701
  "aliases": [],
659
702
  "args": {},
660
- "description": "Lists access requests",
661
- "flags": {},
703
+ "description": "Lists your n recent outgoing access requests",
704
+ "examples": [
705
+ "opal request list --n 5",
706
+ "opal request list --n 5 --pending",
707
+ "opal request list --n 5 --verbose",
708
+ "opal request list --n 5 --pending --verbose"
709
+ ],
710
+ "flags": {
711
+ "help": {
712
+ "char": "h",
713
+ "description": "Show CLI help.",
714
+ "name": "help",
715
+ "allowNo": false,
716
+ "type": "boolean"
717
+ },
718
+ "n": {
719
+ "char": "n",
720
+ "description": "Defines number of requests to be returned. 1 <= n <= 100.",
721
+ "name": "n",
722
+ "default": 10,
723
+ "hasDynamicHelp": false,
724
+ "multiple": false,
725
+ "type": "option"
726
+ },
727
+ "pending": {
728
+ "char": "p",
729
+ "description": "Show only pending requests. Defaults to false.",
730
+ "name": "pending",
731
+ "allowNo": false,
732
+ "type": "boolean"
733
+ },
734
+ "verbose": {
735
+ "char": "v",
736
+ "description": "Enable verbose output, prints full response in JSON format. Defaults to false.",
737
+ "name": "verbose",
738
+ "allowNo": false,
739
+ "type": "boolean"
740
+ }
741
+ },
662
742
  "hasDynamicHelp": false,
663
743
  "hidden": true,
664
744
  "hiddenAliases": [],
@@ -693,7 +773,7 @@
693
773
  },
694
774
  "id": {
695
775
  "char": "i",
696
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
776
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
697
777
  "name": "id",
698
778
  "hasDynamicHelp": false,
699
779
  "multiple": false,
@@ -760,7 +840,7 @@
760
840
  },
761
841
  "id": {
762
842
  "char": "i",
763
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
843
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
764
844
  "name": "id",
765
845
  "hasDynamicHelp": false,
766
846
  "multiple": false,
@@ -835,7 +915,7 @@
835
915
  },
836
916
  "id": {
837
917
  "char": "i",
838
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
918
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
839
919
  "name": "id",
840
920
  "hasDynamicHelp": false,
841
921
  "multiple": false,
@@ -884,7 +964,7 @@
884
964
  },
885
965
  "id": {
886
966
  "char": "i",
887
- "description": "The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
967
+ "description": "The Opal ID of the asset. You can find this from the URL, e.g. https://opal.dev/resources/[ID]",
888
968
  "name": "id",
889
969
  "hasDynamicHelp": false,
890
970
  "multiple": false,
@@ -923,5 +1003,5 @@
923
1003
  ]
924
1004
  }
925
1005
  },
926
- "version": "3.1.1-beta.4dbd858"
1006
+ "version": "3.1.1-beta.4e22fcc"
927
1007
  }
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.4dbd858",
4
+ "version": "3.1.1-beta.4e22fcc",
5
5
  "author": "Stephen Cobbe",
6
6
  "bin": {
7
7
  "opal": "./bin/run"
@@ -16,6 +16,7 @@
16
16
  "argon2": "^0.40.1",
17
17
  "chalk": "^2.4.2",
18
18
  "cli-table3": "^0.6.5",
19
+ "enquirer": "^2.4.1",
19
20
  "graphql": "^15.5.0",
20
21
  "inquirer": "^8.2.6",
21
22
  "inquirer-autocomplete-prompt": "^2.0.1",
@@ -23,6 +24,7 @@
23
24
  "lodash": "^4.17.21",
24
25
  "moment": "^2.30.1",
25
26
  "node-fetch": "^2.6.7",
27
+ "object-treeify": "^5.0.1",
26
28
  "open": "^8.0.4",
27
29
  "openid-client": "^5.6.5",
28
30
  "prettyjson": "^1.2.1",