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.
- package/README.md +26 -26
- package/lib/commands/request/create.d.ts +6 -0
- package/lib/commands/request/create.js +53 -16
- package/lib/commands/request/get.d.ts +2 -0
- package/lib/commands/request/get.js +21 -3
- package/lib/commands/request/list.d.ts +8 -1
- package/lib/commands/request/list.js +113 -6
- package/lib/graphql/gql.d.ts +31 -6
- package/lib/graphql/gql.js +8 -3
- package/lib/graphql/graphql.d.ts +287 -94
- package/lib/graphql/graphql.js +1625 -171
- package/lib/lib/flags.js +1 -1
- package/lib/lib/requests.d.ts +28 -18
- package/lib/lib/requests.js +813 -129
- package/lib/utils/displays.d.ts +6 -4
- package/lib/utils/displays.js +181 -80
- package/oclif.manifest.json +94 -14
- package/package.json +3 -1
package/lib/lib/requests.js
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.initEmptyRequestMetadata = initEmptyRequestMetadata;
|
|
4
4
|
exports.selectRequestableItems = selectRequestableItems;
|
|
5
|
-
exports.chooseAssets = chooseAssets;
|
|
6
|
-
exports.chooseRoles = chooseRoles;
|
|
7
5
|
exports.doneSelectingAssets = doneSelectingAssets;
|
|
8
6
|
exports.setRequestDefaults = setRequestDefaults;
|
|
9
7
|
exports.promptForReason = promptForReason;
|
|
10
8
|
exports.promptForExpiration = promptForExpiration;
|
|
9
|
+
exports.promptRequestSubmission = promptRequestSubmission;
|
|
11
10
|
exports.submitFinalRequest = submitFinalRequest;
|
|
11
|
+
exports.bypassRequestSelection = bypassRequestSelection;
|
|
12
|
+
exports.bypassDuration = bypassDuration;
|
|
13
|
+
const chalk_1 = require("chalk");
|
|
12
14
|
const inquirer = require("inquirer");
|
|
13
15
|
const graphql_1 = require("../graphql");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const graphql_2 = require("../graphql/graphql");
|
|
17
|
+
const displays_1 = require("../utils/displays");
|
|
18
|
+
const config_1 = require("./config");
|
|
19
|
+
const { AutoComplete, Select, prompt, Form } = require("enquirer");
|
|
20
|
+
function entityTypeFromString(str) {
|
|
21
|
+
if (str === "Resource") {
|
|
22
|
+
return graphql_2.EntityType.Resource;
|
|
23
|
+
}
|
|
24
|
+
if (str === "Group") {
|
|
25
|
+
return graphql_2.EntityType.Group;
|
|
26
|
+
}
|
|
27
|
+
// if type unknown, default to resource
|
|
28
|
+
return graphql_2.EntityType.Resource;
|
|
29
|
+
}
|
|
30
|
+
function initEmptyRequestMetadata() {
|
|
16
31
|
// Initialize with empty defaults
|
|
17
32
|
const requestDefaults = {
|
|
18
33
|
durationOptions: [],
|
|
@@ -28,6 +43,9 @@ function createEmptyRequestMetadata() {
|
|
|
28
43
|
return {
|
|
29
44
|
requestMap,
|
|
30
45
|
requestDefaults,
|
|
46
|
+
durationLabel: "",
|
|
47
|
+
durationInMinutes: 0,
|
|
48
|
+
reason: "",
|
|
31
49
|
};
|
|
32
50
|
}
|
|
33
51
|
// Queries and Mutations
|
|
@@ -73,18 +91,23 @@ async function queryRequestableApps(cmd, client, input) {
|
|
|
73
91
|
});
|
|
74
92
|
return (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.data) === null || _a === void 0 ? void 0 : _a.appsV2) === null || _b === void 0 ? void 0 : _b.edges.map((edge) => {
|
|
75
93
|
let type = undefined;
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
switch (edge.node.__typename) {
|
|
95
|
+
case "Resource":
|
|
96
|
+
type = edge.node.resourceType;
|
|
97
|
+
break;
|
|
98
|
+
case "Connection":
|
|
99
|
+
type = edge.node.connectionType;
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
type = edge.node.__typename;
|
|
78
103
|
}
|
|
79
|
-
if (edge.node.__typename === "Connection") {
|
|
80
|
-
type = edge.node.connectionType;
|
|
81
|
-
}
|
|
82
|
-
const label = `${edge.node.displayName} (${type})`;
|
|
83
104
|
return {
|
|
84
|
-
|
|
105
|
+
message: `${edge.node.displayName} [${type}]`,
|
|
85
106
|
value: {
|
|
86
107
|
id: edge.node.id,
|
|
87
|
-
name:
|
|
108
|
+
name: edge.node.displayName,
|
|
109
|
+
type: type,
|
|
110
|
+
toString: () => edge.node.displayName,
|
|
88
111
|
},
|
|
89
112
|
};
|
|
90
113
|
});
|
|
@@ -147,16 +170,16 @@ async function queryRequestableAssets(cmd, client, appId, input) {
|
|
|
147
170
|
switch (resp.data.app.__typename) {
|
|
148
171
|
case "App":
|
|
149
172
|
return (_d = (_c = (_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.app) === null || _b === void 0 ? void 0 : _b.items) === null || _c === void 0 ? void 0 : _c.items) === null || _d === void 0 ? void 0 : _d.map((item) => {
|
|
150
|
-
var _a, _b, _c, _d, _e, _f;
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
151
174
|
const name = ((_a = item.resource) === null || _a === void 0 ? void 0 : _a.name) || ((_b = item.group) === null || _b === void 0 ? void 0 : _b.name);
|
|
152
175
|
const id = ((_c = item.resource) === null || _c === void 0 ? void 0 : _c.id) || ((_d = item.group) === null || _d === void 0 ? void 0 : _d.id);
|
|
153
176
|
const type = ((_e = item.resource) === null || _e === void 0 ? void 0 : _e.__typename) || ((_f = item.group) === null || _f === void 0 ? void 0 : _f.__typename);
|
|
154
|
-
const label = `${name} (${type})`;
|
|
155
177
|
return {
|
|
156
|
-
|
|
178
|
+
message: `${name} [${type}]`,
|
|
157
179
|
value: {
|
|
158
|
-
name:
|
|
159
|
-
id: id,
|
|
180
|
+
name: name || "",
|
|
181
|
+
id: id || "",
|
|
182
|
+
type: entityTypeFromString(((_g = item.resource) === null || _g === void 0 ? void 0 : _g.__typename) || ((_h = item.group) === null || _h === void 0 ? void 0 : _h.__typename)),
|
|
160
183
|
},
|
|
161
184
|
};
|
|
162
185
|
});
|
|
@@ -182,7 +205,6 @@ const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
|
182
205
|
__typename
|
|
183
206
|
... on ResourceAccessLevelsResult {
|
|
184
207
|
accessLevels {
|
|
185
|
-
__typename
|
|
186
208
|
... on ResourceAccessLevel {
|
|
187
209
|
accessLevelName
|
|
188
210
|
accessLevelRemoteId
|
|
@@ -195,34 +217,82 @@ const RESOURCE_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
|
195
217
|
}
|
|
196
218
|
}
|
|
197
219
|
`);
|
|
198
|
-
|
|
199
|
-
|
|
220
|
+
const GROUP_ROLES_QUERY = (0, graphql_1.graphql)(`
|
|
221
|
+
query GroupAccessLevels($groupId: GroupId!) {
|
|
222
|
+
groupAccessLevels(
|
|
223
|
+
input: { groupId: $groupId }
|
|
224
|
+
) {
|
|
225
|
+
... on GroupAccessLevelsResult {
|
|
226
|
+
groupId
|
|
227
|
+
accessLevels {
|
|
228
|
+
... on GroupAccessLevel {
|
|
229
|
+
accessLevelName
|
|
230
|
+
accessLevelRemoteId
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`);
|
|
237
|
+
async function queryAssetRoles(cmd, client, assetType, assetId) {
|
|
238
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
200
239
|
try {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let x;
|
|
210
|
-
switch (resp.data.accessLevels.__typename) {
|
|
211
|
-
case "ResourceAccessLevelsResult":
|
|
212
|
-
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) => {
|
|
213
|
-
return {
|
|
214
|
-
name: role.accessLevelName,
|
|
215
|
-
value: {
|
|
216
|
-
name: role.accessLevelName,
|
|
217
|
-
id: role.accessLevelRemoteId,
|
|
218
|
-
},
|
|
219
|
-
};
|
|
240
|
+
switch (assetType) {
|
|
241
|
+
case "Resource": {
|
|
242
|
+
const resp = await client.query({
|
|
243
|
+
query: RESOURCE_ROLES_QUERY,
|
|
244
|
+
variables: {
|
|
245
|
+
resourceId: assetId,
|
|
246
|
+
},
|
|
247
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
220
248
|
});
|
|
221
|
-
|
|
222
|
-
x
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
249
|
+
// no fall through doesn't consider process.exit();
|
|
250
|
+
let x;
|
|
251
|
+
switch (resp.data.accessLevels.__typename) {
|
|
252
|
+
case "ResourceAccessLevelsResult":
|
|
253
|
+
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) => {
|
|
254
|
+
return {
|
|
255
|
+
message: role.accessLevelName || "",
|
|
256
|
+
value: {
|
|
257
|
+
name: role.accessLevelName || "",
|
|
258
|
+
id: role.accessLevelRemoteId || "",
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
case "ResourceNotFoundError":
|
|
263
|
+
x = cmd.error((_e = (_d = resp.data) === null || _d === void 0 ? void 0 : _d.accessLevels) === null || _e === void 0 ? void 0 : _e.message);
|
|
264
|
+
break;
|
|
265
|
+
default:
|
|
266
|
+
cmd.error(resp.error || "Unknown error occurred.");
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
case "Group": {
|
|
271
|
+
const resp = await client.query({
|
|
272
|
+
query: GROUP_ROLES_QUERY,
|
|
273
|
+
variables: {
|
|
274
|
+
groupId: assetId,
|
|
275
|
+
},
|
|
276
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
277
|
+
});
|
|
278
|
+
// no fall through doesn't consider process.exit();
|
|
279
|
+
let x;
|
|
280
|
+
switch (resp.data.groupAccessLevels.__typename) {
|
|
281
|
+
case "GroupAccessLevelsResult":
|
|
282
|
+
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) => {
|
|
283
|
+
return {
|
|
284
|
+
message: role.accessLevelName,
|
|
285
|
+
value: {
|
|
286
|
+
name: role.accessLevelName,
|
|
287
|
+
id: role.accessLevelRemoteId,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
default:
|
|
292
|
+
x = cmd.error(resp.error || "Unknown error occurred.");
|
|
293
|
+
}
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
226
296
|
}
|
|
227
297
|
}
|
|
228
298
|
catch (error) {
|
|
@@ -241,16 +311,18 @@ const REQUEST_DEFAULTS_QUERY = (0, graphql_1.graphql)(`
|
|
|
241
311
|
requestedGroups: $requestedGroups,
|
|
242
312
|
}
|
|
243
313
|
) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
314
|
+
... on RequestDefaults {
|
|
315
|
+
durationOptions {
|
|
316
|
+
durationInMinutes
|
|
317
|
+
label
|
|
318
|
+
}
|
|
319
|
+
recommendedDurationInMinutes
|
|
320
|
+
defaultDurationInMinutes
|
|
321
|
+
maxDurationInMinutes
|
|
322
|
+
requireSupportTicket
|
|
323
|
+
reasonOptional
|
|
324
|
+
requesterIsAdmin
|
|
247
325
|
}
|
|
248
|
-
recommendedDurationInMinutes
|
|
249
|
-
defaultDurationInMinutes
|
|
250
|
-
maxDurationInMinutes
|
|
251
|
-
requireSupportTicket
|
|
252
|
-
reasonOptional
|
|
253
|
-
requesterIsAdmin
|
|
254
326
|
}
|
|
255
327
|
}`);
|
|
256
328
|
async function queryRequestDefaults(cmd, client, requestedResources, requestedGroups) {
|
|
@@ -271,37 +343,406 @@ async function queryRequestDefaults(cmd, client, requestedResources, requestedGr
|
|
|
271
343
|
}
|
|
272
344
|
}
|
|
273
345
|
}
|
|
346
|
+
const CREATE_REQUEST_MUTATION = (0, graphql_1.graphql)(`
|
|
347
|
+
mutation CreateRequest(
|
|
348
|
+
$requestedResources: [RequestedResourceInput!]!
|
|
349
|
+
$requestedGroups: [RequestedGroupInput!]!
|
|
350
|
+
$reason: String!
|
|
351
|
+
$durationInMinutes: Int
|
|
352
|
+
) {
|
|
353
|
+
createRequest(
|
|
354
|
+
input: {
|
|
355
|
+
requestedResources: $requestedResources
|
|
356
|
+
requestedGroups: $requestedGroups
|
|
357
|
+
reason: $reason
|
|
358
|
+
durationInMinutes: $durationInMinutes
|
|
359
|
+
}
|
|
360
|
+
) {
|
|
361
|
+
... on CreateRequestResult {
|
|
362
|
+
request {
|
|
363
|
+
id
|
|
364
|
+
status
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
... on RequestDurationTooLargeError {
|
|
368
|
+
message
|
|
369
|
+
}
|
|
370
|
+
... on RequestRequiresUserAuthTokenForConnectionError {
|
|
371
|
+
message
|
|
372
|
+
}
|
|
373
|
+
... on NoReviewersSetForOwnerError {
|
|
374
|
+
message
|
|
375
|
+
ownerId
|
|
376
|
+
}
|
|
377
|
+
... on NoReviewersSetForResourceError {
|
|
378
|
+
message
|
|
379
|
+
resourceId
|
|
380
|
+
}
|
|
381
|
+
... on NoReviewersSetForGroupError {
|
|
382
|
+
message
|
|
383
|
+
groupId
|
|
384
|
+
}
|
|
385
|
+
... on NoManagerSetForRequestingUserError {
|
|
386
|
+
message
|
|
387
|
+
}
|
|
388
|
+
... on MfaInvalidError {
|
|
389
|
+
message
|
|
390
|
+
}
|
|
391
|
+
... on BulkRequestTooLargeError {
|
|
392
|
+
message
|
|
393
|
+
}
|
|
394
|
+
... on ItemCannotBeRequestedError {
|
|
395
|
+
message
|
|
396
|
+
}
|
|
397
|
+
... on UserCannotRequestAccessForTargetGroupError {
|
|
398
|
+
message
|
|
399
|
+
groupId
|
|
400
|
+
userId
|
|
401
|
+
}
|
|
402
|
+
... on GroupNestingNotAllowedError {
|
|
403
|
+
message
|
|
404
|
+
fromGroupId
|
|
405
|
+
toGroupId
|
|
406
|
+
}
|
|
407
|
+
... on TargetUserHasNestedAccessError {
|
|
408
|
+
message
|
|
409
|
+
groupIds
|
|
410
|
+
}
|
|
411
|
+
... on RequestReasonMissingError {
|
|
412
|
+
message
|
|
413
|
+
}
|
|
414
|
+
... on RequestFieldValueMissingError {
|
|
415
|
+
message
|
|
416
|
+
fieldName
|
|
417
|
+
}
|
|
418
|
+
... on LinkedGroupNotRequestableError {
|
|
419
|
+
message
|
|
420
|
+
sourceGroupId
|
|
421
|
+
groupBindingId
|
|
422
|
+
}
|
|
423
|
+
... on RequestReasonBelowMinLengthError {
|
|
424
|
+
message
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
`);
|
|
430
|
+
async function createRequest(cmd, client, requestedResources, requestedGroups, reason, durationInMinutes) {
|
|
431
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
432
|
+
try {
|
|
433
|
+
const resp = await client.mutate({
|
|
434
|
+
mutation: CREATE_REQUEST_MUTATION,
|
|
435
|
+
variables: {
|
|
436
|
+
requestedResources: requestedResources,
|
|
437
|
+
requestedGroups: requestedGroups,
|
|
438
|
+
reason: reason,
|
|
439
|
+
durationInMinutes: durationInMinutes,
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
switch ((_a = resp.data) === null || _a === void 0 ? void 0 : _a.createRequest.__typename) {
|
|
443
|
+
case "CreateRequestResult":
|
|
444
|
+
return (_b = resp.data) === null || _b === void 0 ? void 0 : _b.createRequest.request;
|
|
445
|
+
case "RequestDurationTooLargeError":
|
|
446
|
+
cmd.log((_c = resp.data) === null || _c === void 0 ? void 0 : _c.createRequest.message);
|
|
447
|
+
break;
|
|
448
|
+
case "RequestRequiresUserAuthTokenForConnectionError":
|
|
449
|
+
cmd.log((_d = resp.data) === null || _d === void 0 ? void 0 : _d.createRequest.message);
|
|
450
|
+
break;
|
|
451
|
+
case "NoReviewersSetForOwnerError":
|
|
452
|
+
cmd.log((_e = resp.data) === null || _e === void 0 ? void 0 : _e.createRequest.message);
|
|
453
|
+
break;
|
|
454
|
+
case "NoReviewersSetForResourceError":
|
|
455
|
+
cmd.log((_f = resp.data) === null || _f === void 0 ? void 0 : _f.createRequest.message);
|
|
456
|
+
break;
|
|
457
|
+
case "NoReviewersSetForGroupError":
|
|
458
|
+
cmd.log((_g = resp.data) === null || _g === void 0 ? void 0 : _g.createRequest.message);
|
|
459
|
+
break;
|
|
460
|
+
case "NoManagerSetForRequestingUserError":
|
|
461
|
+
cmd.log((_h = resp.data) === null || _h === void 0 ? void 0 : _h.createRequest.message);
|
|
462
|
+
break;
|
|
463
|
+
case "MfaInvalidError":
|
|
464
|
+
cmd.log((_j = resp.data) === null || _j === void 0 ? void 0 : _j.createRequest.message);
|
|
465
|
+
break;
|
|
466
|
+
case "BulkRequestTooLargeError":
|
|
467
|
+
cmd.log((_k = resp.data) === null || _k === void 0 ? void 0 : _k.createRequest.message);
|
|
468
|
+
break;
|
|
469
|
+
case "ItemCannotBeRequestedError":
|
|
470
|
+
cmd.log((_l = resp.data) === null || _l === void 0 ? void 0 : _l.createRequest.message);
|
|
471
|
+
break;
|
|
472
|
+
case "UserCannotRequestAccessForTargetGroupError":
|
|
473
|
+
cmd.log((_m = resp.data) === null || _m === void 0 ? void 0 : _m.createRequest.message);
|
|
474
|
+
break;
|
|
475
|
+
case "GroupNestingNotAllowedError":
|
|
476
|
+
cmd.log((_o = resp.data) === null || _o === void 0 ? void 0 : _o.createRequest.message);
|
|
477
|
+
break;
|
|
478
|
+
case "TargetUserHasNestedAccessError":
|
|
479
|
+
cmd.log((_p = resp.data) === null || _p === void 0 ? void 0 : _p.createRequest.message);
|
|
480
|
+
break;
|
|
481
|
+
case "RequestReasonMissingError":
|
|
482
|
+
cmd.log((_q = resp.data) === null || _q === void 0 ? void 0 : _q.createRequest.message);
|
|
483
|
+
break;
|
|
484
|
+
case "RequestFieldValueMissingError":
|
|
485
|
+
cmd.log((_r = resp.data) === null || _r === void 0 ? void 0 : _r.createRequest.message);
|
|
486
|
+
break;
|
|
487
|
+
case "LinkedGroupNotRequestableError":
|
|
488
|
+
cmd.log((_s = resp.data) === null || _s === void 0 ? void 0 : _s.createRequest.message);
|
|
489
|
+
break;
|
|
490
|
+
case "RequestReasonBelowMinLengthError":
|
|
491
|
+
cmd.log((_t = resp.data) === null || _t === void 0 ? void 0 : _t.createRequest.message);
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
if (error instanceof Error || typeof error === "string") {
|
|
497
|
+
cmd.error(error);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
const CATALOG_ITEM = (0, graphql_1.graphql)(`
|
|
502
|
+
query GetCatalogItem($uuid: UUID!) {
|
|
503
|
+
catalogItem(id: $uuid) {
|
|
504
|
+
__typename
|
|
505
|
+
... on Connection {
|
|
506
|
+
id
|
|
507
|
+
displayName
|
|
508
|
+
}
|
|
509
|
+
... on Resource {
|
|
510
|
+
id
|
|
511
|
+
displayName
|
|
512
|
+
connection {
|
|
513
|
+
id
|
|
514
|
+
displayName
|
|
515
|
+
}
|
|
516
|
+
accessLevels{
|
|
517
|
+
accessLevelName
|
|
518
|
+
accessLevelRemoteId
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
...on Group {
|
|
522
|
+
id
|
|
523
|
+
name
|
|
524
|
+
connection {
|
|
525
|
+
id
|
|
526
|
+
displayName
|
|
527
|
+
}
|
|
528
|
+
accessLevels{
|
|
529
|
+
accessLevelName
|
|
530
|
+
accessLevelRemoteId
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
... on UserFacingError {
|
|
534
|
+
message
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
`);
|
|
539
|
+
const ASSOCIATED_ITEMS_QUERY = (0, graphql_1.graphql)(`
|
|
540
|
+
query GetAssociatedItems($resourceId: ResourceId!, $searchQuery: String) {
|
|
541
|
+
resource(input: {
|
|
542
|
+
id: $resourceId
|
|
543
|
+
}) {
|
|
544
|
+
__typename
|
|
545
|
+
... on ResourceResult {
|
|
546
|
+
__typename
|
|
547
|
+
resource {
|
|
548
|
+
associatedItems(
|
|
549
|
+
first: 200
|
|
550
|
+
filters: {
|
|
551
|
+
searchQuery: {
|
|
552
|
+
contains: $searchQuery
|
|
553
|
+
}
|
|
554
|
+
access: REQUESTABLE
|
|
555
|
+
endUserVisible: true
|
|
556
|
+
entityType: {
|
|
557
|
+
in: [GROUP, RESOURCE]
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
) {
|
|
561
|
+
edges {
|
|
562
|
+
__typename
|
|
563
|
+
... on ResourceAssociatedItemEdge {
|
|
564
|
+
alias
|
|
565
|
+
node {
|
|
566
|
+
__typename
|
|
567
|
+
id
|
|
568
|
+
name
|
|
569
|
+
... on Resource {
|
|
570
|
+
accessLevels(
|
|
571
|
+
filters: {
|
|
572
|
+
skipRemoteAccessLevels: false # azure app roles are remote
|
|
573
|
+
}
|
|
574
|
+
) {
|
|
575
|
+
__typename
|
|
576
|
+
accessLevelName
|
|
577
|
+
accessLevelRemoteId
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
... on ResourceNotFoundError {
|
|
587
|
+
message
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
`);
|
|
592
|
+
async function queryAssociatedItems(cmd, client, id, input) {
|
|
593
|
+
var _a, _b;
|
|
594
|
+
try {
|
|
595
|
+
const resp = await client.query({
|
|
596
|
+
query: ASSOCIATED_ITEMS_QUERY,
|
|
597
|
+
variables: {
|
|
598
|
+
resourceId: id || "",
|
|
599
|
+
searchQuery: input || "",
|
|
600
|
+
},
|
|
601
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
602
|
+
});
|
|
603
|
+
switch (resp.data.resource.__typename) {
|
|
604
|
+
case "ResourceResult": {
|
|
605
|
+
const associatedItems = resp.data.resource.resource.associatedItems.edges.filter((edge) => edge.__typename === "ResourceAssociatedItemEdge");
|
|
606
|
+
const initial = [];
|
|
607
|
+
for (const edge of associatedItems) {
|
|
608
|
+
initial.push(...appRolesFromEdge(edge));
|
|
609
|
+
}
|
|
610
|
+
return initial;
|
|
611
|
+
}
|
|
612
|
+
case "ResourceNotFoundError":
|
|
613
|
+
cmd.log((_b = (_a = resp.data) === null || _a === void 0 ? void 0 : _a.resource) === null || _b === void 0 ? void 0 : _b.message);
|
|
614
|
+
break;
|
|
615
|
+
default:
|
|
616
|
+
cmd.error(resp.error || "Unknown error occurred.");
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
if (error instanceof Error || typeof error === "string") {
|
|
621
|
+
cmd.error(error);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
274
625
|
// Helper functions
|
|
626
|
+
const selectInstructions = chalk_1.default.dim("āā Navigate Ā· Enter Select Ā· Type to filter");
|
|
627
|
+
const multiSelectInstructions = chalk_1.default.dim("āā Navigate Ā· Space Select Ā· Enter Confirm Ā· Type to filter");
|
|
275
628
|
async function selectRequestableItems(cmd, client, requestMap) {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
629
|
+
const initial = (await queryRequestableApps(cmd, client, "")) || [];
|
|
630
|
+
const appPrompt = new AutoComplete({
|
|
631
|
+
name: "App",
|
|
632
|
+
message: "Select an app",
|
|
633
|
+
hint: selectInstructions,
|
|
634
|
+
limit: 15,
|
|
635
|
+
choices: initial,
|
|
636
|
+
async suggest(input) {
|
|
637
|
+
const filteredChoices = await queryRequestableApps(cmd, client, input || "");
|
|
638
|
+
return filteredChoices || initial;
|
|
286
639
|
},
|
|
287
|
-
|
|
640
|
+
});
|
|
641
|
+
const App = await appPrompt.run();
|
|
288
642
|
// Set the app in the requestMap and call choose assets step
|
|
289
643
|
if (!(App.id in requestMap)) {
|
|
290
644
|
requestMap[App.id] = {
|
|
645
|
+
appId: App.id,
|
|
291
646
|
appName: App.name,
|
|
292
647
|
assets: {},
|
|
293
648
|
};
|
|
294
649
|
}
|
|
650
|
+
if (App.type === "OKTA_APP" || App.type === "AZURE_ENTERPRISE_APP") {
|
|
651
|
+
await chooseOktaAzureRoles(cmd, client, App, requestMap);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
295
654
|
await chooseAssets(cmd, client, App.id, requestMap);
|
|
296
655
|
}
|
|
656
|
+
async function chooseOktaAzureRoles(cmd, client, app, requestMap) {
|
|
657
|
+
const associatedItems = (await queryAssociatedItems(cmd, client, app.id, "")) || [];
|
|
658
|
+
const rolePrompt = new AutoComplete({
|
|
659
|
+
name: "Roles",
|
|
660
|
+
message: `Select a role for ${app.name}:`,
|
|
661
|
+
hint: multiSelectInstructions,
|
|
662
|
+
limit: 15,
|
|
663
|
+
multiple: true,
|
|
664
|
+
async choices(input) {
|
|
665
|
+
if (!input)
|
|
666
|
+
return associatedItems;
|
|
667
|
+
const filteredChoices = await queryAssociatedItems(cmd, client, app.id, input);
|
|
668
|
+
return filteredChoices || associatedItems;
|
|
669
|
+
},
|
|
670
|
+
validate: (answer) => {
|
|
671
|
+
if (answer.length !== 1) {
|
|
672
|
+
return "You must select only one item.";
|
|
673
|
+
}
|
|
674
|
+
return true;
|
|
675
|
+
},
|
|
676
|
+
});
|
|
677
|
+
const Roles = await rolePrompt.run();
|
|
678
|
+
const entry = requestMap[app.id];
|
|
679
|
+
for (const role of Roles) {
|
|
680
|
+
if (!(role.id in entry.assets)) {
|
|
681
|
+
entry.assets[role.id] = {
|
|
682
|
+
assetId: role.id,
|
|
683
|
+
assetName: role.name,
|
|
684
|
+
type: entityTypeFromString(role.type),
|
|
685
|
+
roles: {},
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function appRolesFromEdge(edge) {
|
|
691
|
+
var _a, _b, _c, _d;
|
|
692
|
+
switch (edge.node.__typename) {
|
|
693
|
+
case "Resource": {
|
|
694
|
+
if (edge.node.accessLevels && edge.node.accessLevels.length > 0) {
|
|
695
|
+
return edge.node.accessLevels.map((accessLevel) => ({
|
|
696
|
+
message: accessLevel.accessLevelName || "No Role (Direct access)",
|
|
697
|
+
value: {
|
|
698
|
+
id: edge.node.id + accessLevel.accessLevelRemoteId,
|
|
699
|
+
name: accessLevel.accessLevelName,
|
|
700
|
+
type: graphql_2.EntityType.Resource,
|
|
701
|
+
toString: () => accessLevel.accessLevelName,
|
|
702
|
+
},
|
|
703
|
+
}));
|
|
704
|
+
}
|
|
705
|
+
return [
|
|
706
|
+
{
|
|
707
|
+
message: (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name,
|
|
708
|
+
value: {
|
|
709
|
+
id: edge.node.id,
|
|
710
|
+
name: (_b = edge.alias) !== null && _b !== void 0 ? _b : edge.node.name,
|
|
711
|
+
type: graphql_2.EntityType.Resource,
|
|
712
|
+
toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
];
|
|
716
|
+
}
|
|
717
|
+
case "Group":
|
|
718
|
+
return [
|
|
719
|
+
{
|
|
720
|
+
message: (_c = edge.alias) !== null && _c !== void 0 ? _c : edge.node.name,
|
|
721
|
+
value: {
|
|
722
|
+
id: edge.node.id,
|
|
723
|
+
name: (_d = edge.alias) !== null && _d !== void 0 ? _d : edge.node.name,
|
|
724
|
+
type: graphql_2.EntityType.Group,
|
|
725
|
+
toString: () => { var _a; return (_a = edge.alias) !== null && _a !== void 0 ? _a : edge.node.name; },
|
|
726
|
+
},
|
|
727
|
+
},
|
|
728
|
+
];
|
|
729
|
+
}
|
|
730
|
+
}
|
|
297
731
|
async function chooseAssets(cmd, client, appId, requestMap) {
|
|
298
|
-
|
|
299
|
-
const
|
|
732
|
+
const initial = (await queryRequestableAssets(cmd, client, appId, "")) || [];
|
|
733
|
+
const assetPrompt = new AutoComplete({
|
|
300
734
|
name: "Assets",
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
735
|
+
message: "Select one or more assets:",
|
|
736
|
+
hint: multiSelectInstructions,
|
|
737
|
+
limit: 15,
|
|
738
|
+
multiple: true,
|
|
739
|
+
async choices(input) {
|
|
740
|
+
if (!input) {
|
|
741
|
+
return initial;
|
|
742
|
+
}
|
|
743
|
+
const filteredChoices = await queryRequestableAssets(cmd, client, appId, input);
|
|
744
|
+
return filteredChoices || initial;
|
|
745
|
+
},
|
|
305
746
|
validate: (answer) => {
|
|
306
747
|
if (answer.length < 1) {
|
|
307
748
|
return "You must select at least one item.";
|
|
@@ -309,14 +750,17 @@ async function chooseAssets(cmd, client, appId, requestMap) {
|
|
|
309
750
|
return true;
|
|
310
751
|
},
|
|
311
752
|
});
|
|
753
|
+
const Assets = await assetPrompt.run();
|
|
312
754
|
const entry = requestMap[appId];
|
|
313
755
|
for (const asset of Assets) {
|
|
314
756
|
if (entry === undefined) {
|
|
315
|
-
throw new Error(`
|
|
757
|
+
throw new Error(`Error formatting app ${appId} in request`);
|
|
316
758
|
}
|
|
317
759
|
if (!(asset.id in entry.assets)) {
|
|
318
760
|
entry.assets[asset.id] = {
|
|
761
|
+
assetId: asset.id,
|
|
319
762
|
assetName: asset.name,
|
|
763
|
+
type: asset.type,
|
|
320
764
|
roles: {},
|
|
321
765
|
};
|
|
322
766
|
}
|
|
@@ -325,34 +769,38 @@ async function chooseAssets(cmd, client, appId, requestMap) {
|
|
|
325
769
|
}
|
|
326
770
|
async function chooseRoles(cmd, client, appId, assetId, requestMap) {
|
|
327
771
|
var _a;
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
772
|
+
const entry = requestMap[appId];
|
|
773
|
+
const assetEntry = entry === null || entry === void 0 ? void 0 : entry.assets[assetId];
|
|
774
|
+
if (entry === undefined || assetEntry === undefined) {
|
|
775
|
+
throw new Error(`App ${appId} or Asset ${assetId} not found in requestMap`);
|
|
776
|
+
}
|
|
777
|
+
const assetRoles = (_a = (await queryAssetRoles(cmd, client, assetEntry.type, assetId))) !== null && _a !== void 0 ? _a : [];
|
|
778
|
+
if (assetRoles !== undefined &&
|
|
779
|
+
(assetRoles.length === 0 ||
|
|
780
|
+
(assetRoles.length === 1 && assetRoles[0].value.name === ""))) {
|
|
332
781
|
return;
|
|
333
782
|
}
|
|
334
|
-
const
|
|
335
|
-
name: "
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
783
|
+
const rolePrompt = new AutoComplete({
|
|
784
|
+
name: "Roles",
|
|
785
|
+
message: `Select one or more roles for ${assetEntry.assetName}:`,
|
|
786
|
+
hint: multiSelectInstructions,
|
|
787
|
+
limit: 15,
|
|
788
|
+
multiple: true,
|
|
789
|
+
choices: assetRoles,
|
|
339
790
|
validate: (answer) => {
|
|
340
|
-
if (
|
|
341
|
-
return "You must select at least one
|
|
791
|
+
if (answer.length < 1) {
|
|
792
|
+
return "You must select at least one item.";
|
|
342
793
|
}
|
|
343
794
|
return true;
|
|
344
795
|
},
|
|
345
796
|
});
|
|
346
|
-
const
|
|
347
|
-
const assetEntry = entry === null || entry === void 0 ? void 0 : entry.assets[assetId];
|
|
348
|
-
if (entry === undefined || assetEntry === undefined) {
|
|
349
|
-
throw new Error(`App ${appId} or Asset ${assetId} not found in requestMap`);
|
|
350
|
-
}
|
|
797
|
+
const roles = await rolePrompt.run();
|
|
351
798
|
if (!assetEntry.roles) {
|
|
352
799
|
assetEntry.roles = {};
|
|
353
800
|
}
|
|
354
801
|
for (const role of roles) {
|
|
355
802
|
assetEntry.roles[role.id] = {
|
|
803
|
+
roleId: role.id,
|
|
356
804
|
roleName: role.name,
|
|
357
805
|
};
|
|
358
806
|
}
|
|
@@ -360,14 +808,12 @@ async function chooseRoles(cmd, client, appId, assetId, requestMap) {
|
|
|
360
808
|
async function doneSelectingAssets() {
|
|
361
809
|
const submitMessage = "ā
Yes, proceed with request";
|
|
362
810
|
const addMoreMessage = "ā No, add more items";
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
},
|
|
370
|
-
]);
|
|
811
|
+
const prompt = new Select({
|
|
812
|
+
name: "submitOrAdd",
|
|
813
|
+
message: "Is this all you want to request?",
|
|
814
|
+
choices: [submitMessage, addMoreMessage],
|
|
815
|
+
});
|
|
816
|
+
const submitOrAdd = await prompt.run();
|
|
371
817
|
return submitOrAdd === submitMessage;
|
|
372
818
|
}
|
|
373
819
|
async function setRequestDefaults(cmd, client, metadata) {
|
|
@@ -377,18 +823,34 @@ async function setRequestDefaults(cmd, client, metadata) {
|
|
|
377
823
|
for (const appNode of Object.values(requestMap)) {
|
|
378
824
|
for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
379
825
|
if (assetNode.roles !== undefined) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
826
|
+
const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
|
|
827
|
+
return roleId;
|
|
828
|
+
});
|
|
829
|
+
const roleIds = mappedRoles.length ? mappedRoles : [""];
|
|
830
|
+
for (const roleId of roleIds) {
|
|
831
|
+
switch (assetNode.type) {
|
|
832
|
+
case graphql_2.EntityType.Resource: {
|
|
833
|
+
requestedResources.push({
|
|
834
|
+
resourceId: assetId,
|
|
835
|
+
accessLevelRemoteId: roleId,
|
|
836
|
+
});
|
|
837
|
+
break;
|
|
838
|
+
}
|
|
839
|
+
case graphql_2.EntityType.Group: {
|
|
840
|
+
requestedGroups.push({
|
|
841
|
+
groupId: assetId,
|
|
842
|
+
accessLevelRemoteId: roleId,
|
|
843
|
+
});
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
385
847
|
}
|
|
386
848
|
}
|
|
387
849
|
}
|
|
388
850
|
}
|
|
389
851
|
try {
|
|
390
852
|
const requestDefaults = await queryRequestDefaults(cmd, client, requestedResources, requestedGroups);
|
|
391
|
-
if (
|
|
853
|
+
if (requestDefaults !== undefined) {
|
|
392
854
|
metadata.requestDefaults.durationOptions =
|
|
393
855
|
requestDefaults.durationOptions;
|
|
394
856
|
metadata.requestDefaults.recommendedDurationInMinutes =
|
|
@@ -409,49 +871,133 @@ async function setRequestDefaults(cmd, client, metadata) {
|
|
|
409
871
|
}
|
|
410
872
|
}
|
|
411
873
|
async function promptForReason(metadata) {
|
|
412
|
-
|
|
874
|
+
const { reason } = await prompt([
|
|
413
875
|
{
|
|
414
876
|
name: "reason",
|
|
415
|
-
message: "
|
|
877
|
+
message: "Why do you need access?",
|
|
416
878
|
type: "input",
|
|
417
879
|
validate: (answer) => {
|
|
418
|
-
if (metadata.requestDefaults.reasonOptional && answer.length < 1) {
|
|
880
|
+
if (!metadata.requestDefaults.reasonOptional && answer.length < 1) {
|
|
419
881
|
return "A reason for requesting these assets is required.";
|
|
420
882
|
}
|
|
421
883
|
return true;
|
|
422
884
|
},
|
|
423
885
|
},
|
|
424
886
|
]);
|
|
887
|
+
metadata.reason = reason;
|
|
425
888
|
}
|
|
426
889
|
async function promptForExpiration(metadata) {
|
|
427
890
|
var _a, _b;
|
|
428
891
|
const durations = ((_b = (_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.durationOptions) === null || _b === void 0 ? void 0 : _b.map((option) => {
|
|
892
|
+
var _a;
|
|
893
|
+
let label = option.label;
|
|
894
|
+
if (option.durationInMinutes ===
|
|
895
|
+
((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes)) {
|
|
896
|
+
label = `${label} (MAX)`;
|
|
897
|
+
}
|
|
898
|
+
if (option.durationInMinutes ===
|
|
899
|
+
metadata.requestDefaults.recommendedDurationInMinutes) {
|
|
900
|
+
label = `${label} (RECOMMENDED)`;
|
|
901
|
+
}
|
|
429
902
|
return {
|
|
430
|
-
|
|
431
|
-
metadata.requestDefaults.recommendedDurationInMinutes
|
|
432
|
-
? `${option.label} (Recommended)`
|
|
433
|
-
: option.label,
|
|
903
|
+
message: label,
|
|
434
904
|
value: {
|
|
435
|
-
label:
|
|
905
|
+
label: label,
|
|
436
906
|
durationInMinutes: option.durationInMinutes,
|
|
907
|
+
toString: () => label,
|
|
437
908
|
},
|
|
438
909
|
};
|
|
439
910
|
})) || [];
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
911
|
+
// Sort durations by minutes
|
|
912
|
+
durations.sort((a, b) => a.value.durationInMinutes - b.value.durationInMinutes);
|
|
913
|
+
const expirationSelect = new AutoComplete({
|
|
914
|
+
name: "expiration",
|
|
915
|
+
message: "When should access expire?",
|
|
916
|
+
type: "list",
|
|
917
|
+
choices: durations,
|
|
918
|
+
pageSize: 15,
|
|
919
|
+
});
|
|
920
|
+
let selected = await expirationSelect.run();
|
|
921
|
+
switch (selected.label) {
|
|
922
|
+
case "Custom": {
|
|
923
|
+
selected = await setCustomDuration(metadata);
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case "Permanent": {
|
|
927
|
+
selected.durationInMinutes = undefined;
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
metadata.durationInMinutes = selected.durationInMinutes;
|
|
932
|
+
metadata.durationLabel = selected.label;
|
|
933
|
+
}
|
|
934
|
+
function getDurationNumbers(duration) {
|
|
935
|
+
const d = +duration.days || 0;
|
|
936
|
+
const h = +duration.hours || 0;
|
|
937
|
+
const m = +duration.minutes || 0;
|
|
938
|
+
return { d, h, m };
|
|
939
|
+
}
|
|
940
|
+
function getDurationInMinutes(duration) {
|
|
941
|
+
const { d, h, m } = getDurationNumbers(duration);
|
|
942
|
+
const minutesInDay = 1440; // 24 hours * 60 minutes
|
|
943
|
+
const minutesInHour = 60;
|
|
944
|
+
return d * minutesInDay + h * minutesInHour + m;
|
|
945
|
+
}
|
|
946
|
+
function getDHMFromMinutes(minutes) {
|
|
947
|
+
const label = [];
|
|
948
|
+
const d = Math.floor(minutes / 1440);
|
|
949
|
+
if (d > 0) {
|
|
950
|
+
label.push(`${d}d`);
|
|
951
|
+
}
|
|
952
|
+
const remainingMinutes = minutes % 1440;
|
|
953
|
+
const h = Math.floor(remainingMinutes / 60);
|
|
954
|
+
if (h > 0) {
|
|
955
|
+
label.push(`${h}h`);
|
|
956
|
+
}
|
|
957
|
+
const m = remainingMinutes % 60;
|
|
958
|
+
if (m > 0) {
|
|
959
|
+
label.push(`${m}m`);
|
|
960
|
+
}
|
|
961
|
+
return label.join(" ");
|
|
962
|
+
}
|
|
963
|
+
async function setCustomDuration(metadata) {
|
|
964
|
+
const durationForm = new Form({
|
|
965
|
+
name: "user",
|
|
966
|
+
message: "Please set a custom access duration:",
|
|
967
|
+
choices: [
|
|
968
|
+
{ name: "days", message: "Days", initial: "0" },
|
|
969
|
+
{ name: "hours", message: "Hours", initial: "0" },
|
|
970
|
+
{ name: "minutes", message: "Minutes", initial: "0" },
|
|
971
|
+
],
|
|
972
|
+
validate: (answer) => {
|
|
973
|
+
var _a, _b, _c;
|
|
974
|
+
const { d, h, m } = getDurationNumbers(answer);
|
|
975
|
+
const durationInMinutes = getDurationInMinutes(answer);
|
|
976
|
+
if (d < 0 || h < 0 || m < 0 || d + h + m === 0 || (h > 23 && m > 59)) {
|
|
977
|
+
return "Please enter a valid duration.";
|
|
978
|
+
}
|
|
979
|
+
if (((_a = metadata.requestDefaults) === null || _a === void 0 ? void 0 : _a.maxDurationInMinutes) &&
|
|
980
|
+
durationInMinutes > ((_b = metadata.requestDefaults) === null || _b === void 0 ? void 0 : _b.maxDurationInMinutes)) {
|
|
981
|
+
const maxDHM = getDHMFromMinutes((_c = metadata.requestDefaults) === null || _c === void 0 ? void 0 : _c.maxDurationInMinutes);
|
|
982
|
+
return `The max duration for the selected assets is ${maxDHM}.`;
|
|
983
|
+
}
|
|
984
|
+
return true;
|
|
451
985
|
},
|
|
452
|
-
|
|
986
|
+
return: (answer) => {
|
|
987
|
+
return getDurationInMinutes(answer);
|
|
988
|
+
},
|
|
989
|
+
});
|
|
990
|
+
const durationResult = await durationForm.run();
|
|
991
|
+
const { d, h, m } = getDurationNumbers(durationResult);
|
|
992
|
+
const durationInMinutes = getDurationInMinutes(durationResult);
|
|
993
|
+
const durationLabel = getDHMFromMinutes(durationInMinutes);
|
|
994
|
+
return {
|
|
995
|
+
durationInMinutes: durationInMinutes,
|
|
996
|
+
label: durationLabel,
|
|
997
|
+
};
|
|
453
998
|
}
|
|
454
|
-
async function
|
|
999
|
+
async function promptRequestSubmission(cmd, metadata) {
|
|
1000
|
+
(0, displays_1.displayFinalRequestSummary)(cmd, metadata);
|
|
455
1001
|
const submitMessage = "ā
Yes, submit request";
|
|
456
1002
|
const cancelMessage = "ā No, cancel request";
|
|
457
1003
|
const { submit } = await inquirer.prompt([
|
|
@@ -462,12 +1008,150 @@ async function submitFinalRequest(cmd) {
|
|
|
462
1008
|
choices: [submitMessage, cancelMessage],
|
|
463
1009
|
},
|
|
464
1010
|
]);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
1011
|
+
switch (submit) {
|
|
1012
|
+
case submitMessage: {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
case cancelMessage: {
|
|
1016
|
+
cmd.log("š« Access Request has been cancelled.");
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
default: {
|
|
1020
|
+
cmd.error("Unknown error occurred.");
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
async function submitFinalRequest(cmd, client, metadata) {
|
|
1025
|
+
var _a, _b, _c, _d;
|
|
1026
|
+
// Build requested assets lists for the mutation
|
|
1027
|
+
const requestedResources = [];
|
|
1028
|
+
const requestedGroups = [];
|
|
1029
|
+
for (const appNode of Object.values(metadata.requestMap)) {
|
|
1030
|
+
// This extraction is different than the one in setRequestDefaults.
|
|
1031
|
+
// Both extract the requestedResources and requestedGroups,
|
|
1032
|
+
// use different formats.
|
|
1033
|
+
for (const [assetId, assetNode] of Object.entries(appNode.assets)) {
|
|
1034
|
+
if (assetNode.roles) {
|
|
1035
|
+
const mappedRoles = Object.entries(assetNode.roles).map(([roleId, _roleNode]) => {
|
|
1036
|
+
return roleId;
|
|
1037
|
+
});
|
|
1038
|
+
const roleIds = mappedRoles.length > 0 ? mappedRoles : [""];
|
|
1039
|
+
for (const roleId of roleIds) {
|
|
1040
|
+
switch (assetNode.type) {
|
|
1041
|
+
case graphql_2.EntityType.Resource: {
|
|
1042
|
+
requestedResources.push({
|
|
1043
|
+
resourceId: assetId,
|
|
1044
|
+
accessLevel: {
|
|
1045
|
+
accessLevelName: ((_b = (_a = assetNode.roles) === null || _a === void 0 ? void 0 : _a[roleId]) === null || _b === void 0 ? void 0 : _b.roleName) || "",
|
|
1046
|
+
accessLevelRemoteId: roleId,
|
|
1047
|
+
},
|
|
1048
|
+
});
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
case graphql_2.EntityType.Group: {
|
|
1052
|
+
requestedGroups.push({
|
|
1053
|
+
groupId: assetId,
|
|
1054
|
+
accessLevel: {
|
|
1055
|
+
accessLevelName: ((_d = (_c = assetNode.roles) === null || _c === void 0 ? void 0 : _c[roleId]) === null || _d === void 0 ? void 0 : _d.roleName) || "",
|
|
1056
|
+
accessLevelRemoteId: roleId,
|
|
1057
|
+
},
|
|
1058
|
+
});
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
const resp = await createRequest(cmd, client, requestedResources, requestedGroups, metadata.reason, metadata.durationInMinutes);
|
|
1067
|
+
// Build link to request
|
|
1068
|
+
const configData = (0, config_1.getOrCreateConfigData)(cmd.config.configDir);
|
|
1069
|
+
if (resp === null || resp === void 0 ? void 0 : resp.id) {
|
|
1070
|
+
cmd.log("\nš Your Access Request has been submitted!\n");
|
|
1071
|
+
cmd.log(`${chalk_1.default.bold("ID: ")} ${chalk_1.default.cyan(resp === null || resp === void 0 ? void 0 : resp.id)}`);
|
|
1072
|
+
if (resp === null || resp === void 0 ? void 0 : resp.status) {
|
|
1073
|
+
cmd.log((0, displays_1.getStyledStatus)(resp === null || resp === void 0 ? void 0 : resp.status));
|
|
1074
|
+
}
|
|
1075
|
+
const requestLink = `${configData[config_1.urlKey]}/requests/sent/${resp === null || resp === void 0 ? void 0 : resp.id}`;
|
|
1076
|
+
cmd.log(`${chalk_1.default.bold("Link:")} ${chalk_1.default.underline(requestLink)}\n`);
|
|
1077
|
+
}
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
async function bypassRequestSelection(cmd, client, flagValue, metadata) {
|
|
1081
|
+
var _a, _b;
|
|
1082
|
+
try {
|
|
1083
|
+
// Query Catalog Item endpoint to identify what the id belongs to (resource or group)
|
|
1084
|
+
for (const id of flagValue) {
|
|
1085
|
+
const [assetId, roleName] = id.split(":");
|
|
1086
|
+
const resp = await client.query({
|
|
1087
|
+
query: CATALOG_ITEM,
|
|
1088
|
+
variables: {
|
|
1089
|
+
uuid: assetId || "",
|
|
1090
|
+
},
|
|
1091
|
+
fetchPolicy: "network-only", // to avoid caching
|
|
1092
|
+
});
|
|
1093
|
+
switch (resp.data.catalogItem.__typename) {
|
|
1094
|
+
case "Group":
|
|
1095
|
+
case "Resource": {
|
|
1096
|
+
const item = resp.data.catalogItem;
|
|
1097
|
+
const assetName = item.__typename === "Resource" ? item.displayName : item.name;
|
|
1098
|
+
const requestableRoles = (item.accessLevels || [])
|
|
1099
|
+
// TODO: Support okta azure apps ?.filter((role) => role.accessLevelName !== "") // This assumes length == 1
|
|
1100
|
+
.map((role) => ({
|
|
1101
|
+
id: role.accessLevelRemoteId,
|
|
1102
|
+
name: role.accessLevelName,
|
|
1103
|
+
}));
|
|
1104
|
+
const appId = ((_a = item.connection) === null || _a === void 0 ? void 0 : _a.id) || "";
|
|
1105
|
+
if (!(appId in metadata.requestMap)) {
|
|
1106
|
+
metadata.requestMap[appId] = {
|
|
1107
|
+
appName: ((_b = item.connection) === null || _b === void 0 ? void 0 : _b.displayName) || "",
|
|
1108
|
+
appId: appId,
|
|
1109
|
+
assets: {},
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
const assetEntry = metadata.requestMap[appId].assets[id];
|
|
1113
|
+
if (!assetEntry) {
|
|
1114
|
+
metadata.requestMap[appId].assets[assetId] = {
|
|
1115
|
+
assetId: assetId,
|
|
1116
|
+
assetName: assetName,
|
|
1117
|
+
type: entityTypeFromString(item.__typename),
|
|
1118
|
+
roles: {},
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
if (requestableRoles.length > 0 &&
|
|
1122
|
+
!(requestableRoles.length === 1 && requestableRoles[0].name === "")) {
|
|
1123
|
+
const selectedRole = requestableRoles.find((role) => role.name === roleName);
|
|
1124
|
+
if (selectedRole !== undefined) {
|
|
1125
|
+
if (!metadata.requestMap[appId].assets[assetId].roles) {
|
|
1126
|
+
metadata.requestMap[appId].assets[assetId].roles = {};
|
|
1127
|
+
}
|
|
1128
|
+
metadata.requestMap[appId].assets[assetId].roles[selectedRole.id] = {
|
|
1129
|
+
roleId: selectedRole.id,
|
|
1130
|
+
roleName: selectedRole.name,
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
else {
|
|
1134
|
+
cmd.error(`Access level specified does not match one of ${assetName}'s defined access levels:${requestableRoles.map((role) => role.name)}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
break;
|
|
1138
|
+
}
|
|
1139
|
+
default:
|
|
1140
|
+
cmd.error("Invalid asset id was passed in using the --id flag.");
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
catch (error) {
|
|
1145
|
+
if (error instanceof Error || typeof error === "string") {
|
|
1146
|
+
cmd.error(error);
|
|
1147
|
+
}
|
|
469
1148
|
}
|
|
470
|
-
|
|
471
|
-
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
function bypassDuration(cmd, duration, metadata) {
|
|
1152
|
+
const maxDuration = metadata.requestDefaults.maxDurationInMinutes;
|
|
1153
|
+
if (maxDuration && duration > maxDuration) {
|
|
1154
|
+
cmd.error(`The requested duration exceeds the allowed limit of ${maxDuration}`);
|
|
472
1155
|
}
|
|
1156
|
+
metadata.durationInMinutes = duration;
|
|
473
1157
|
}
|