opal-security 3.2.1 → 3.2.2

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.
Files changed (56) hide show
  1. package/README.md +28 -25
  2. package/lib/commands/login.js +8 -1
  3. package/lib/commands/request/create.d.ts +2 -0
  4. package/lib/commands/request/create.js +41 -20
  5. package/lib/commands/request/get.js +5 -57
  6. package/lib/commands/request/list.js +3 -60
  7. package/lib/graphql/gql.d.ts +35 -15
  8. package/lib/graphql/gql.js +9 -5
  9. package/lib/graphql/graphql.d.ts +286 -228
  10. package/lib/graphql/graphql.js +1674 -1095
  11. package/lib/labels.d.ts +3 -0
  12. package/lib/labels.js +37 -0
  13. package/lib/lib/request/api/index.d.ts +6 -0
  14. package/lib/lib/request/api/index.js +20 -0
  15. package/lib/lib/request/api/mutations/create-request.d.ts +8 -0
  16. package/lib/lib/request/api/mutations/create-request.js +159 -0
  17. package/lib/lib/request/api/queries/apps.d.ts +4 -0
  18. package/lib/lib/request/api/queries/apps.js +73 -0
  19. package/lib/lib/request/api/queries/assets.d.ts +6 -0
  20. package/lib/lib/request/api/queries/assets.js +136 -0
  21. package/lib/lib/request/api/queries/request-defaults.d.ts +5 -0
  22. package/lib/lib/request/api/queries/request-defaults.js +51 -0
  23. package/lib/lib/request/api/queries/requests.d.ts +4 -0
  24. package/lib/lib/request/api/queries/requests.js +163 -0
  25. package/lib/lib/request/api/queries/roles.d.ts +5 -0
  26. package/lib/lib/request/api/queries/roles.js +239 -0
  27. package/lib/{utils → lib/request}/displays.d.ts +4 -2
  28. package/lib/{utils → lib/request}/displays.js +41 -19
  29. package/lib/lib/request/prompts/apps-prompt.d.ts +4 -0
  30. package/lib/lib/request/prompts/apps-prompt.js +35 -0
  31. package/lib/lib/request/prompts/asset-prompt.d.ts +5 -0
  32. package/lib/lib/request/prompts/asset-prompt.js +81 -0
  33. package/lib/lib/request/prompts/duration-prompt.d.ts +2 -0
  34. package/lib/lib/request/prompts/duration-prompt.js +122 -0
  35. package/lib/lib/request/prompts/index.d.ts +8 -0
  36. package/lib/lib/request/prompts/index.js +20 -0
  37. package/lib/lib/request/prompts/reason-prompt.d.ts +2 -0
  38. package/lib/lib/request/prompts/reason-prompt.js +20 -0
  39. package/lib/lib/request/prompts/role-prompt.d.ts +4 -0
  40. package/lib/lib/request/prompts/role-prompt.js +44 -0
  41. package/lib/lib/request/prompts/validate-prompt.d.ts +4 -0
  42. package/lib/lib/request/prompts/validate-prompt.js +29 -0
  43. package/lib/lib/request/request-utils.d.ts +15 -0
  44. package/lib/lib/request/request-utils.js +467 -0
  45. package/lib/lib/request/types.d.ts +55 -0
  46. package/lib/lib/request/types.js +15 -0
  47. package/lib/lib/util.d.ts +1 -0
  48. package/lib/lib/util.js +16 -0
  49. package/lib/types.d.ts +19 -3
  50. package/lib/types.js +18 -2
  51. package/oclif.manifest.json +54 -38
  52. package/package.json +1 -1
  53. package/lib/lib/requests.d.ts +0 -54
  54. package/lib/lib/requests.js +0 -1160
  55. package/lib/utils/utils.d.ts +0 -1
  56. package/lib/utils/utils.js +0 -18
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryBundle = exports.queryRequests = exports.queryRequest = void 0;
4
+ const graphql_1 = require("../../../../graphql");
5
+ const RESOURCE_FRAGMENT = (0, graphql_1.graphql)(`
6
+ fragment ResourceFields on Resource {
7
+ displayName
8
+ id
9
+ connectionId
10
+ connection {
11
+ name
12
+ connectionType
13
+ }
14
+ }
15
+ `);
16
+ const GROUP_FRAGMENT = (0, graphql_1.graphql)(`
17
+ fragment GroupFields on Group {
18
+ name
19
+ id
20
+ connectionId
21
+ connection {
22
+ name
23
+ connectionType
24
+ }
25
+ }
26
+ `);
27
+ const REQUEST_FIELDS_FRAGMENT = (0, graphql_1.graphql)(`
28
+ fragment RequestFields on Request {
29
+ id
30
+ createdAt
31
+ status
32
+ durationInMinutes
33
+ reason
34
+ requester {
35
+ displayName
36
+ }
37
+ targetUser {
38
+ displayName
39
+ }
40
+ requestedResources {
41
+ resource {
42
+ ...ResourceFields
43
+ }
44
+ accessLevel {
45
+ accessLevelName
46
+ accessLevelRemoteId
47
+ }
48
+ }
49
+ requestedGroups {
50
+ group {
51
+ ...GroupFields
52
+ }
53
+ accessLevel {
54
+ accessLevelName
55
+ accessLevelRemoteId
56
+ }
57
+ }
58
+ }
59
+ `);
60
+ const GET_REQUEST = (0, graphql_1.graphql)(`
61
+ query GetRequest(
62
+ $id: RequestId!
63
+ ) {
64
+ request(input: {id: $id}) {
65
+ __typename
66
+ ... on RequestResult {
67
+ request {
68
+ ...RequestFields
69
+ }
70
+ }
71
+ ... on RequestNotFoundError {
72
+ message
73
+ }
74
+ }
75
+ }
76
+ `);
77
+ const queryRequest = async (client, requestId) => {
78
+ const resp = await client.query({
79
+ query: GET_REQUEST,
80
+ variables: {
81
+ id: requestId,
82
+ },
83
+ fetchPolicy: "network-only", // to avoid caching
84
+ });
85
+ return resp;
86
+ };
87
+ exports.queryRequest = queryRequest;
88
+ // TODO: Add date filters, search query,
89
+ const GET_OUTGOING_REQUESTS = (0, graphql_1.graphql)(`
90
+ query GetRequests($showPendingOnly: Boolean!, $pageSize: Int) {
91
+ requests(input: {
92
+ requestType: OUTGOING
93
+ maxNumEntries: $pageSize
94
+ filters: {
95
+ showPendingOnly: $showPendingOnly
96
+ }
97
+ }) {
98
+ __typename
99
+ ... on RequestsResult {
100
+ requestType
101
+ requests {
102
+ ...RequestFields
103
+ }
104
+
105
+ }
106
+
107
+ }
108
+ }`);
109
+ const queryRequests = async (client, pageSize, showPendingOnly) => {
110
+ const resp = await client.query({
111
+ query: GET_OUTGOING_REQUESTS,
112
+ variables: {
113
+ pageSize: pageSize,
114
+ showPendingOnly: showPendingOnly,
115
+ },
116
+ fetchPolicy: "network-only", // to avoid caching
117
+ });
118
+ return resp;
119
+ };
120
+ exports.queryRequests = queryRequests;
121
+ const GET_BUNDLE = (0, graphql_1.graphql)(`query GetBundle($id: BundleId!) {
122
+ bundle(input: { id: $id }) {
123
+ __typename
124
+ ... on BundleResult {
125
+ bundle {
126
+ name
127
+ id
128
+ items {
129
+ edges {
130
+ accessLevel {
131
+ accessLevelName
132
+ accessLevelRemoteId
133
+ }
134
+ node {
135
+ ... on Resource {
136
+ ...ResourceFields
137
+ isRequestable
138
+ }
139
+ ... on Group {
140
+ ...GroupFields
141
+ isRequestable
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ ... on BundleNotFoundError {
149
+ message
150
+ }
151
+ }
152
+ }`);
153
+ const queryBundle = async (client, bundleId) => {
154
+ const resp = await client.query({
155
+ query: GET_BUNDLE,
156
+ variables: {
157
+ id: bundleId,
158
+ },
159
+ fetchPolicy: "network-only", // to avoid caching
160
+ });
161
+ return resp;
162
+ };
163
+ exports.queryBundle = queryBundle;
@@ -0,0 +1,5 @@
1
+ import type { ApolloClient, NormalizedCacheObject } from "@apollo/client";
2
+ import type { Command } from "@oclif/core";
3
+ import type { PromptChoice } from "../../types";
4
+ export declare function queryAssetRoles(cmd: Command, client: ApolloClient<NormalizedCacheObject>, assetType: string, assetId: string): Promise<PromptChoice[] | undefined>;
5
+ export declare function queryAssociatedItems(cmd: Command, client: ApolloClient<NormalizedCacheObject>, id: string, input: string | undefined): Promise<PromptChoice[] | undefined>;
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryAssetRoles = queryAssetRoles;
4
+ exports.queryAssociatedItems = queryAssociatedItems;
5
+ const graphql_1 = require("../../../../graphql");
6
+ const graphql_2 = require("../../../../graphql/graphql");
7
+ const labels_1 = require("../../../../labels");
8
+ const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
9
+ query ResourceAccessLevels($resourceId: ResourceId!) {
10
+ accessLevels(input: {
11
+ resourceId: $resourceId,
12
+ onlyMine: false,
13
+ }) {
14
+ __typename
15
+ ... on ResourceAccessLevelsResult {
16
+ accessLevels {
17
+ ... on ResourceAccessLevel {
18
+ accessLevelName
19
+ accessLevelRemoteId
20
+ }
21
+ }
22
+ }
23
+ ... on ResourceNotFoundError {
24
+ message
25
+ }
26
+ }
27
+ }
28
+ `);
29
+ const GROUP_ROLES_QUERY = (0, graphql_1.graphql)(`
30
+ query GroupAccessLevels($groupId: GroupId!) {
31
+ groupAccessLevels(
32
+ input: { groupId: $groupId }
33
+ ) {
34
+ ... on GroupAccessLevelsResult {
35
+ groupId
36
+ accessLevels {
37
+ ... on GroupAccessLevel {
38
+ accessLevelName
39
+ accessLevelRemoteId
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ `);
46
+ async function queryAssetRoles(cmd, client, assetType, assetId) {
47
+ var _a, _b, _c, _d, _e, _f, _g, _h;
48
+ try {
49
+ switch (assetType) {
50
+ case graphql_2.EntityType.Resource: {
51
+ const resp = await client.query({
52
+ query: RESOURCE_ROLES_QUERY,
53
+ variables: {
54
+ resourceId: assetId,
55
+ },
56
+ fetchPolicy: "network-only", // to avoid caching
57
+ });
58
+ // no fall through doesn't consider process.exit();
59
+ let x;
60
+ switch (resp.data.accessLevels.__typename) {
61
+ case "ResourceAccessLevelsResult":
62
+ return (_c = (_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.accessLevels) === null || _b === void 0 ? void 0 : _b.accessLevels) === null || _c === void 0 ? void 0 : _c.map((role) => {
63
+ return {
64
+ message: role.accessLevelName || "",
65
+ value: {
66
+ name: role.accessLevelName || "",
67
+ id: role.accessLevelRemoteId || "",
68
+ },
69
+ };
70
+ });
71
+ case "ResourceNotFoundError":
72
+ x = cmd.error((_e = (_d = resp.data) === null || _d === void 0 ? void 0 : _d.accessLevels) === null || _e === void 0 ? void 0 : _e.message);
73
+ break;
74
+ default:
75
+ cmd.error(resp.error || "Unknown error occurred.");
76
+ }
77
+ return;
78
+ }
79
+ case graphql_2.EntityType.Group: {
80
+ const resp = await client.query({
81
+ query: GROUP_ROLES_QUERY,
82
+ variables: {
83
+ groupId: assetId,
84
+ },
85
+ fetchPolicy: "network-only", // to avoid caching
86
+ });
87
+ // no fall through doesn't consider process.exit();
88
+ let x;
89
+ switch (resp.data.groupAccessLevels.__typename) {
90
+ case "GroupAccessLevelsResult":
91
+ return (_h = (_g = (_f = resp.data) === null || _f === void 0 ? void 0 : _f.groupAccessLevels) === null || _g === void 0 ? void 0 : _g.accessLevels) === null || _h === void 0 ? void 0 : _h.map((role) => {
92
+ return {
93
+ message: role.accessLevelName,
94
+ value: {
95
+ name: role.accessLevelName,
96
+ id: role.accessLevelRemoteId,
97
+ },
98
+ };
99
+ });
100
+ default:
101
+ x = cmd.error(resp.error || "Unknown error occurred.");
102
+ }
103
+ return;
104
+ }
105
+ }
106
+ }
107
+ catch (error) {
108
+ if (error instanceof Error || typeof error === "string") {
109
+ cmd.error(error);
110
+ }
111
+ }
112
+ }
113
+ const ASSOCIATED_ITEMS_QUERY = (0, graphql_1.graphql)(`
114
+ query GetAssociatedItems($resourceId: ResourceId!, $searchQuery: String) {
115
+ resource(input: {
116
+ id: $resourceId
117
+ }) {
118
+ __typename
119
+ ... on ResourceResult {
120
+ __typename
121
+ resource {
122
+ associatedItems(
123
+ first: 200
124
+ filters: {
125
+ searchQuery: {
126
+ contains: $searchQuery
127
+ }
128
+ access: REQUESTABLE
129
+ endUserVisible: true
130
+ entityType: {
131
+ in: [GROUP, RESOURCE]
132
+ }
133
+ }
134
+ ) {
135
+ edges {
136
+ __typename
137
+ ... on ResourceAssociatedItemEdge {
138
+ alias
139
+ node {
140
+ __typename
141
+ id
142
+ name
143
+ ... on Resource {
144
+ accessLevels(
145
+ filters: {
146
+ skipRemoteAccessLevels: false # azure app roles are remote
147
+ }
148
+ ) {
149
+ __typename
150
+ accessLevelName
151
+ accessLevelRemoteId
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ ... on ResourceNotFoundError {
161
+ message
162
+ }
163
+ }
164
+ }
165
+ `);
166
+ function appRolesFromEdge(edge) {
167
+ var _a, _b, _c, _d;
168
+ switch (edge.node.__typename) {
169
+ case "Resource": {
170
+ if (edge.node.accessLevels && edge.node.accessLevels.length > 0) {
171
+ return edge.node.accessLevels.map((accessLevel) => ({
172
+ message: accessLevel.accessLevelName || "No Role (Direct access)",
173
+ value: {
174
+ id: edge.node.id + accessLevel.accessLevelRemoteId,
175
+ name: accessLevel.accessLevelName,
176
+ type: labels_1.DisplayLabels[graphql_2.EntityType.Resource],
177
+ toString: () => accessLevel.accessLevelName,
178
+ },
179
+ }));
180
+ }
181
+ return [
182
+ {
183
+ message: (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name,
184
+ value: {
185
+ id: edge.node.id,
186
+ name: (_b = edge.alias) !== null && _b !== void 0 ? _b : edge.node.name,
187
+ type: labels_1.DisplayLabels[graphql_2.EntityType.Resource],
188
+ toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
189
+ },
190
+ },
191
+ ];
192
+ }
193
+ case "Group":
194
+ return [
195
+ {
196
+ message: `${(_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name} ${graphql_2.EntityType.Group}`,
197
+ value: {
198
+ id: edge.node.id,
199
+ name: (_d = edge.alias) !== null && _d !== void 0 ? _d : edge.node.name,
200
+ type: labels_1.DisplayLabels[graphql_2.EntityType.Group],
201
+ toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
202
+ },
203
+ },
204
+ ];
205
+ }
206
+ }
207
+ async function queryAssociatedItems(cmd, client, id, input) {
208
+ var _a, _b;
209
+ try {
210
+ const resp = await client.query({
211
+ query: ASSOCIATED_ITEMS_QUERY,
212
+ variables: {
213
+ resourceId: id || "",
214
+ searchQuery: input || "",
215
+ },
216
+ fetchPolicy: "network-only", // to avoid caching
217
+ });
218
+ switch (resp.data.resource.__typename) {
219
+ case "ResourceResult": {
220
+ const associatedItems = resp.data.resource.resource.associatedItems.edges.filter((edge) => edge.__typename === "ResourceAssociatedItemEdge");
221
+ const initial = [];
222
+ for (const edge of associatedItems) {
223
+ initial.push(...appRolesFromEdge(edge));
224
+ }
225
+ return initial;
226
+ }
227
+ case "ResourceNotFoundError":
228
+ cmd.log((_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.resource) === null || _b === void 0 ? void 0 : _b.message);
229
+ break;
230
+ default:
231
+ cmd.error(resp.error || "Unknown error occurred.");
232
+ }
233
+ }
234
+ catch (error) {
235
+ if (error instanceof Error || typeof error === "string") {
236
+ cmd.error(error);
237
+ }
238
+ }
239
+ }
@@ -1,10 +1,12 @@
1
1
  import type { ApolloQueryResult } from "@apollo/client";
2
2
  import type { Command } from "@oclif/core/lib/command";
3
- import type { GetRequestQuery, GetRequestsQuery } from "../graphql/graphql";
4
- import { type RequestMap, type RequestMetadata } from "../lib/requests";
3
+ import type { GetRequestQuery, GetRequestsQuery } from "../../graphql/graphql";
4
+ import type { RequestMap, RequestMetadata } from "./types";
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;
8
8
  export declare function getStyledStatus(status: string): string;
9
9
  export declare function displayRequestDetails(cmd: Command, requestResp: ApolloQueryResult<GetRequestQuery>): void;
10
10
  export declare function displayRequestListTable(cmd: Command, requestResp: ApolloQueryResult<GetRequestsQuery>): void;
11
+ export declare function formatDuration(durationInMinutes: number): string;
12
+ export declare function displayRequestAgain(cmd: Command, id: string): void;
@@ -6,8 +6,10 @@ exports.displayFinalRequestSummary = displayFinalRequestSummary;
6
6
  exports.getStyledStatus = getStyledStatus;
7
7
  exports.displayRequestDetails = displayRequestDetails;
8
8
  exports.displayRequestListTable = displayRequestListTable;
9
+ exports.formatDuration = formatDuration;
10
+ exports.displayRequestAgain = displayRequestAgain;
9
11
  const chalk_1 = require("chalk");
10
- const requests_1 = require("../lib/requests");
12
+ const labels_1 = require("../../labels");
11
13
  const Table = require("cli-table3");
12
14
  function headerMessage(cmd) {
13
15
  console.clear();
@@ -15,6 +17,16 @@ function headerMessage(cmd) {
15
17
  cmd.log("Opal Access Request ✏️");
16
18
  cmd.log("Press Ctrl+C to cancel at any time.\n");
17
19
  }
20
+ /*
21
+ Example treeified output:
22
+
23
+ Opal [App]
24
+ └── Infosec Group [Group]
25
+ └── Infosec Prod Databases [Group]
26
+ MongoDB Atlas Test [App]
27
+ └── my-mongo-db-atlas [Resource]
28
+ └── admin:test [Role]
29
+ */
18
30
  function treeifyRequestMap(cmd, requestMap) {
19
31
  for (const [_appId, appNode] of Object.entries(requestMap)) {
20
32
  // Print App title first (without tree lines)
@@ -22,7 +34,7 @@ function treeifyRequestMap(cmd, requestMap) {
22
34
  for (const [_assetId, assetNode] of Object.entries(appNode.assets)) {
23
35
  // If okta/azure asset with no role, change asset name
24
36
  const assetName = assetNode.assetName || "No Role (Direct access)";
25
- cmd.log(`└── ${assetName} ${chalk_1.default.dim(`[${requests_1.DISPLAY_LABELS[assetNode.type]}]`)}`);
37
+ cmd.log(`└── ${assetName} ${chalk_1.default.dim(`[${labels_1.DisplayLabels[assetNode.type]}]`)}`);
26
38
  if (assetNode.roles !== undefined) {
27
39
  for (const [_roleId, roleNode] of Object.entries(assetNode.roles)) {
28
40
  const roleName = roleNode.roleName;
@@ -75,34 +87,37 @@ function displayRequestDetails(cmd, requestResp) {
75
87
  var _a, _b, _c, _d, _e, _f;
76
88
  switch (requestResp.data.request.__typename) {
77
89
  case "RequestResult": {
90
+ const request = requestResp.data.request.request;
78
91
  cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
79
- cmd.log(`Request Details ${chalk_1.default.cyan(requestResp.data.request.request.id)}`);
92
+ cmd.log(`Request Details ${chalk_1.default.cyan(request.id)}`);
80
93
  cmd.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
81
- const status = requestResp.data.request.request.status;
94
+ const status = request.status;
82
95
  cmd.log(getStyledStatus(status));
83
96
  // Request users "Requested by: <requester> -> Requested for: <targetUser>"
84
- const requester = (_a = requestResp.data.request.request.requester) === null || _a === void 0 ? void 0 : _a.displayName;
85
- const targetUser = (_b = requestResp.data.request.request.targetUser) === null || _b === void 0 ? void 0 : _b.displayName;
97
+ const requester = (_a = request.requester) === null || _a === void 0 ? void 0 : _a.displayName;
98
+ const targetUser = (_b = request.targetUser) === null || _b === void 0 ? void 0 : _b.displayName;
86
99
  if (requester && targetUser) {
87
100
  cmd.log(`${chalk_1.default.bold("Requested by:")} ${requester} ${chalk_1.default.gray("->")} ${chalk_1.default.bold("Requested for:")} ${targetUser}`);
88
101
  }
89
- const durationInMinutes = requestResp.data.request.request.durationInMinutes;
102
+ const durationInMinutes = request.durationInMinutes;
90
103
  cmd.log(`${chalk_1.default.bold("Duration:")} ${durationInMinutes ? formatDuration(durationInMinutes) : "Permanent"}`);
91
- const reason = requestResp.data.request.request.reason;
104
+ const reason = request.reason;
92
105
  if (reason) {
93
106
  cmd.log(`${chalk_1.default.bold("Reason:")} "${chalk_1.default.italic(reason)}"`);
94
107
  }
95
108
  // Requested resources
96
- const requestedResources = (_d = (_c = requestResp.data.request.request.requestedResources) === null || _c === void 0 ? void 0 : _c.map((resource) => {
97
- var _a, _b, _c;
109
+ const requestedResources = (_d = (_c = request.requestedResources) === null || _c === void 0 ? void 0 : _c.map((resource) => {
110
+ var _a, _b;
98
111
  if (((_a = resource.resource) === null || _a === void 0 ? void 0 : _a.__typename) === "Resource") {
99
- return formatAssetName((_b = resource.resource) === null || _b === void 0 ? void 0 : _b.displayName, ((_c = resource.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
112
+ const requestedResource = resource.resource;
113
+ return formatAssetName(requestedResource.displayName, ((_b = resource.accessLevel) === null || _b === void 0 ? void 0 : _b.accessLevelName) || "");
100
114
  }
101
115
  })) !== null && _d !== void 0 ? _d : [];
102
- const requestedGroups = (_f = (_e = requestResp.data.request.request.requestedGroups) === null || _e === void 0 ? void 0 : _e.map((group) => {
103
- var _a, _b, _c;
116
+ const requestedGroups = (_f = (_e = request.requestedGroups) === null || _e === void 0 ? void 0 : _e.map((group) => {
117
+ var _a, _b;
104
118
  if (((_a = group.group) === null || _a === void 0 ? void 0 : _a.__typename) === "Group") {
105
- return formatAssetName((_b = group.group) === null || _b === void 0 ? void 0 : _b.name, ((_c = group.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
119
+ const requestedGroup = group.group;
120
+ return formatAssetName(requestedGroup.name, ((_b = group.accessLevel) === null || _b === void 0 ? void 0 : _b.accessLevelName) || "");
106
121
  }
107
122
  })) !== null && _f !== void 0 ? _f : [];
108
123
  const requestedItems = [...requestedResources, ...requestedGroups].join(", ");
@@ -131,7 +146,8 @@ function displayRequestListTable(cmd, requestResp) {
131
146
  wordWrap: true,
132
147
  wrapOnWordBoundary: false,
133
148
  });
134
- for (const request of requests) {
149
+ for (const req of requests) {
150
+ const request = req;
135
151
  const targetUser = (_a = request.targetUser) === null || _a === void 0 ? void 0 : _a.displayName;
136
152
  const reason = request.reason;
137
153
  const status = request.status;
@@ -139,15 +155,17 @@ function displayRequestListTable(cmd, requestResp) {
139
155
  ? formatDuration(request.durationInMinutes)
140
156
  : "Permanent";
141
157
  const requestedResources = (_c = (_b = request.requestedResources) === null || _b === void 0 ? void 0 : _b.map((resource) => {
142
- var _a, _b, _c;
158
+ var _a, _b;
143
159
  if (((_a = resource.resource) === null || _a === void 0 ? void 0 : _a.__typename) === "Resource") {
144
- return formatAssetName((_b = resource.resource) === null || _b === void 0 ? void 0 : _b.displayName, ((_c = resource.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
160
+ const requestedResource = resource.resource;
161
+ return formatAssetName(requestedResource.displayName, ((_b = resource.accessLevel) === null || _b === void 0 ? void 0 : _b.accessLevelName) || "");
145
162
  }
146
163
  })) !== null && _c !== void 0 ? _c : [];
147
164
  const requestedGroups = (_e = (_d = request.requestedGroups) === null || _d === void 0 ? void 0 : _d.map((group) => {
148
- var _a, _b, _c;
165
+ var _a, _b;
149
166
  if (((_a = group.group) === null || _a === void 0 ? void 0 : _a.__typename) === "Group") {
150
- return formatAssetName((_b = group.group) === null || _b === void 0 ? void 0 : _b.name, ((_c = group.accessLevel) === null || _c === void 0 ? void 0 : _c.accessLevelName) || "");
167
+ const requestedGroup = group.group;
168
+ return formatAssetName(requestedGroup.name, ((_b = group.accessLevel) === null || _b === void 0 ? void 0 : _b.accessLevelName) || "");
151
169
  }
152
170
  })) !== null && _e !== void 0 ? _e : [];
153
171
  const requestedItems = [
@@ -199,3 +217,7 @@ function formatAssetName(assetName, roleName) {
199
217
  }
200
218
  return str;
201
219
  }
220
+ function displayRequestAgain(cmd, id) {
221
+ cmd.log(chalk_1.default.bold("\nTo request this again, run:"));
222
+ cmd.log(chalk_1.default.italic(` opal request create --template ${id}\n`));
223
+ }
@@ -0,0 +1,4 @@
1
+ import type { ApolloClient, NormalizedCacheObject } from "@apollo/client";
2
+ import type { Command } from "@oclif/core";
3
+ import type { RequestMap } from "../types";
4
+ export declare function selectRequestableItems(cmd: Command, client: ApolloClient<NormalizedCacheObject>, requestMap: RequestMap): Promise<void>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectRequestableItems = selectRequestableItems;
4
+ const _1 = require(".");
5
+ const api_1 = require("../api");
6
+ const { AutoComplete } = require("enquirer");
7
+ async function selectRequestableItems(cmd, client, requestMap) {
8
+ const initial = (await (0, api_1.queryRequestableApps)(cmd, client, "")) || [];
9
+ const appPrompt = new AutoComplete({
10
+ name: "App",
11
+ message: "Select an app",
12
+ hint: _1.selectInstructions,
13
+ limit: 15,
14
+ choices: initial,
15
+ async suggest(input) {
16
+ const filteredChoices = await (0, api_1.queryRequestableApps)(cmd, client, input || "");
17
+ return filteredChoices || initial;
18
+ },
19
+ });
20
+ const App = await appPrompt.run();
21
+ // Set the app in the requestMap and call choose assets step
22
+ if (!(App.id in requestMap)) {
23
+ requestMap[App.id] = {
24
+ appId: App.id,
25
+ appType: App.type,
26
+ appName: App.name,
27
+ assets: {},
28
+ };
29
+ }
30
+ if (App.type === "OKTA_APP" || App.type === "AZURE_ENTERPRISE_APP") {
31
+ await (0, _1.chooseOktaAzureRoles)(cmd, client, App, requestMap);
32
+ return;
33
+ }
34
+ await (0, _1.chooseAssets)(cmd, client, App.id, requestMap);
35
+ }
@@ -0,0 +1,5 @@
1
+ import type { ApolloClient, NormalizedCacheObject } from "@apollo/client";
2
+ import type { Command } from "@oclif/core";
3
+ import { type EntityValue, type RequestMap } from "../types";
4
+ export declare function chooseOktaAzureRoles(cmd: Command, client: ApolloClient<NormalizedCacheObject>, app: EntityValue, requestMap: RequestMap): Promise<void>;
5
+ export declare function chooseAssets(cmd: Command, client: ApolloClient<NormalizedCacheObject>, appId: string, requestMap: RequestMap): Promise<void>;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.chooseOktaAzureRoles = chooseOktaAzureRoles;
4
+ exports.chooseAssets = chooseAssets;
5
+ const _1 = require(".");
6
+ const api_1 = require("../api");
7
+ const types_1 = require("../types");
8
+ const { AutoComplete } = require("enquirer");
9
+ async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
10
+ const associatedItems = (await (0, api_1.queryAssociatedItems)(cmd, client, app.id, "")) || [];
11
+ const rolePrompt = new AutoComplete({
12
+ name: "Roles",
13
+ message: `Select a role for ${app.name}:`,
14
+ hint: _1.multiSelectInstructions,
15
+ limit: 15,
16
+ multiple: true,
17
+ async choices(input) {
18
+ if (!input)
19
+ return associatedItems;
20
+ const filteredChoices = await (0, api_1.queryAssociatedItems)(cmd, client, app.id, input);
21
+ return filteredChoices || associatedItems;
22
+ },
23
+ validate: (answer) => {
24
+ if (answer.length !== 1) {
25
+ return "Only one role is allowed to be requested for on Okta or Azure apps.";
26
+ }
27
+ return true;
28
+ },
29
+ });
30
+ const Roles = await rolePrompt.run();
31
+ const entry = requestMap[app.id];
32
+ for (const role of Roles) {
33
+ if (!(role.id in entry.assets)) {
34
+ entry.assets[role.id] = {
35
+ assetId: role.id,
36
+ assetName: role.name,
37
+ type: (0, types_1.entityTypeFromString)(role.type),
38
+ roles: {},
39
+ };
40
+ }
41
+ }
42
+ }
43
+ async function chooseAssets(cmd, client, appId, requestMap) {
44
+ const initial = (await (0, api_1.queryRequestableAssets)(cmd, client, appId, "")) || [];
45
+ const assetPrompt = new AutoComplete({
46
+ name: "Assets",
47
+ message: "Select one or more assets:",
48
+ hint: _1.multiSelectInstructions,
49
+ limit: 15,
50
+ multiple: true,
51
+ async choices(input) {
52
+ if (!input) {
53
+ return initial;
54
+ }
55
+ const filteredChoices = await (0, api_1.queryRequestableAssets)(cmd, client, appId, input);
56
+ return filteredChoices || initial;
57
+ },
58
+ validate: (answer) => {
59
+ if (answer.length < 1) {
60
+ return "You must select at least one item.";
61
+ }
62
+ return true;
63
+ },
64
+ });
65
+ const Assets = await assetPrompt.run();
66
+ const entry = requestMap[appId];
67
+ for (const asset of Assets) {
68
+ if (entry === undefined) {
69
+ throw new Error(`Error formatting app ${appId} in request`);
70
+ }
71
+ if (!(asset.id in entry.assets)) {
72
+ entry.assets[asset.id] = {
73
+ assetId: asset.id,
74
+ assetName: asset.name,
75
+ type: asset.type,
76
+ roles: {},
77
+ };
78
+ }
79
+ await (0, _1.chooseRoles)(cmd, client, appId, asset.id, requestMap);
80
+ }
81
+ }